]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #89970 - jackh726:gats_diagnostics, r=nikomatsakis
authorbors <bors@rust-lang.org>
Sat, 6 Nov 2021 04:15:22 +0000 (04:15 +0000)
committerbors <bors@rust-lang.org>
Sat, 6 Nov 2021 04:15:22 +0000 (04:15 +0000)
Implementation of GATs outlives lint

See #87479 for background. Closes #87479

The basic premise of this lint/error is to require the user to write where clauses on a GAT when those bounds can be implied or proven from any function on the trait returning that GAT.

## Intuitive Explanation (Attempt) ##
Let's take this trait definition as an example:
```rust
trait Iterable {
    type Item<'x>;
    fn iter<'a>(&'a self) -> Self::Item<'a>;
}
```
Let's focus on the `iter` function. The first thing to realize is that we know that `Self: 'a` because of `&'a self`. If an impl wants `Self::Item` to contain any data with references, then those references must be derived from `&'a self`. Thus, they must live only as long as `'a`. Furthermore, because of the `Self: 'a` implied bound, they must live only as long as `Self`. Since it's `'a` is used in place of `'x`, it is reasonable to assume that any value of `Self::Item<'x>`, and thus `'x`, will only be able to live as long as `Self`. Therefore, we require this bound on `Item` in the trait.

As another example:
```rust
trait Deserializer<T> {
    type Out<'x>;
    fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>;
}
```
The intuition is similar here, except rather than a `Self: 'a` implied bound, we have a `T: 'a` implied bound. Thus, the data on `Self::Out<'a>` is derived from `&'a T`, and thus it is reasonable to expect that the lifetime `'x` will always be less than `T`.

## Implementation Algorithm ##
* Given a GAT `<P0 as Trait<P1..Pi>>::G<Pi...Pn>` declared as `trait T<A1..Ai> for A0 { type G<Ai...An>; }` used in return type of one associated function `F`
* Given env `E` (including implied bounds) for `F`
* For each lifetime parameter `'a` in `P0...Pn`:
    * For each other type parameter `Pi != 'a` in `P0...Pn`: // FIXME: this include of lifetime parameters too
        * If `E => (P: 'a)`:
            * Require where clause `Ai: 'a`

## Follow-up questions ##
* What should we do when we don't pass params exactly?
For this example:
```rust
trait Des {
    type Out<'x, D>;
    fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, Wrap<T>>;
}
```
Should we be requiring a `D: 'x` clause? We pass `Wrap<T>` as `D` and `'z` as `'x`, and should be able to prove that `Wrap<T>: 'z`.

r? `@nikomatsakis`

1606 files changed:
.github/workflows/ci.yml
.mailmap
Cargo.lock
Cargo.toml
RELEASES.md
compiler/rustc_apfloat/src/ieee.rs
compiler/rustc_ast/README.md
compiler/rustc_ast/src/attr/mod.rs
compiler/rustc_ast/src/lib.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/tokenstream.rs
compiler/rustc_ast/src/util/parser.rs
compiler/rustc_ast_lowering/Cargo.toml
compiler/rustc_ast_lowering/src/asm.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/index.rs [new file with mode: 0644]
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_passes/src/ast_validation.rs
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_attr/src/builtin.rs
compiler/rustc_borrowck/src/borrow_set.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/move_errors.rs
compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_borrowck/src/type_check/canonical.rs
compiler/rustc_borrowck/src/type_check/free_region_relations.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_builtin_macros/src/asm.rs
compiler/rustc_builtin_macros/src/derive.rs
compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
compiler/rustc_builtin_macros/src/deriving/mod.rs
compiler/rustc_builtin_macros/src/standard_library_imports.rs
compiler/rustc_codegen_cranelift/src/driver/aot.rs
compiler/rustc_codegen_gcc/src/asm.rs
compiler/rustc_codegen_gcc/src/base.rs
compiler/rustc_codegen_gcc/src/builder.rs
compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
compiler/rustc_codegen_llvm/Cargo.toml
compiler/rustc_codegen_llvm/src/abi.rs
compiler/rustc_codegen_llvm/src/asm.rs
compiler/rustc_codegen_llvm/src/back/write.rs
compiler/rustc_codegen_llvm/src/base.rs
compiler/rustc_codegen_llvm/src/builder.rs
compiler/rustc_codegen_llvm/src/context.rs
compiler/rustc_codegen_llvm/src/intrinsic.rs
compiler/rustc_codegen_llvm/src/llvm/ffi.rs
compiler/rustc_codegen_llvm/src/llvm_util.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/symbol_export.rs
compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
compiler/rustc_codegen_ssa/src/lib.rs
compiler/rustc_codegen_ssa/src/mir/block.rs
compiler/rustc_codegen_ssa/src/mir/mod.rs
compiler/rustc_codegen_ssa/src/mir/operand.rs
compiler/rustc_codegen_ssa/src/target_features.rs
compiler/rustc_codegen_ssa/src/traits/asm.rs
compiler/rustc_codegen_ssa/src/traits/backend.rs
compiler/rustc_codegen_ssa/src/traits/builder.rs
compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
compiler/rustc_const_eval/src/const_eval/fn_queries.rs
compiler/rustc_const_eval/src/const_eval/machine.rs
compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
compiler/rustc_const_eval/src/interpret/util.rs
compiler/rustc_const_eval/src/lib.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/check_consts/mod.rs
compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
compiler/rustc_const_eval/src/transform/promote_consts.rs
compiler/rustc_data_structures/Cargo.toml
compiler/rustc_data_structures/src/base_n.rs
compiler/rustc_data_structures/src/graph/implementation/mod.rs
compiler/rustc_data_structures/src/graph/iterate/mod.rs
compiler/rustc_data_structures/src/lib.rs
compiler/rustc_data_structures/src/obligation_forest/mod.rs
compiler/rustc_data_structures/src/profiling.rs
compiler/rustc_data_structures/src/sorted_map.rs
compiler/rustc_data_structures/src/sorted_map/index_map.rs
compiler/rustc_data_structures/src/sso/map.rs
compiler/rustc_data_structures/src/sso/set.rs
compiler/rustc_data_structures/src/stable_hasher.rs
compiler/rustc_data_structures/src/stack.rs
compiler/rustc_data_structures/src/steal.rs
compiler/rustc_data_structures/src/tiny_list.rs
compiler/rustc_data_structures/src/vec_linked_list.rs
compiler/rustc_driver/src/pretty.rs
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0482.md
compiler/rustc_error_codes/src/error_codes/E0637.md
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/emitter.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_expand/src/config.rs
compiler/rustc_expand/src/expand.rs
compiler/rustc_expand/src/lib.rs
compiler/rustc_expand/src/mbe/quoted.rs
compiler/rustc_expand/src/mbe/transcribe.rs
compiler/rustc_expand/src/mut_visit/tests.rs
compiler/rustc_expand/src/placeholders.rs
compiler/rustc_feature/src/accepted.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_graphviz/src/lib.rs
compiler/rustc_hir/Cargo.toml
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/stable_hash_impls.rs
compiler/rustc_hir_pretty/src/lib.rs
compiler/rustc_incremental/src/assert_dep_graph.rs
compiler/rustc_incremental/src/lib.rs
compiler/rustc_incremental/src/persist/dirty_clean.rs
compiler/rustc_incremental/src/persist/file_format.rs
compiler/rustc_incremental/src/persist/fs.rs
compiler/rustc_index/src/bit_set.rs
compiler/rustc_index/src/vec.rs
compiler/rustc_infer/src/infer/combine.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
compiler/rustc_infer/src/infer/error_reporting/note.rs
compiler/rustc_infer/src/infer/free_regions.rs
compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/opaque_types.rs
compiler/rustc_infer/src/lib.rs
compiler/rustc_infer/src/traits/mod.rs
compiler/rustc_interface/src/interface.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_lexer/src/unescape.rs
compiler/rustc_lint/src/array_into_iter.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/hidden_unicode_codepoints.rs [new file with mode: 0644]
compiler/rustc_lint/src/lib.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_lint_defs/src/lib.rs
compiler/rustc_llvm/build.rs
compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
compiler/rustc_llvm/src/lib.rs
compiler/rustc_macros/src/hash_stable.rs
compiler/rustc_macros/src/query.rs
compiler/rustc_macros/src/session_diagnostic.rs
compiler/rustc_metadata/Cargo.toml
compiler/rustc_metadata/src/lib.rs
compiler/rustc_metadata/src/locator.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/arena.rs
compiler/rustc_middle/src/dep_graph/dep_node.rs
compiler/rustc_middle/src/dep_graph/mod.rs
compiler/rustc_middle/src/hir/map/blocks.rs [deleted file]
compiler/rustc_middle/src/hir/map/collector.rs [deleted file]
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/hir/mod.rs
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/mir/interpret/allocation.rs
compiler/rustc_middle/src/mir/mono.rs
compiler/rustc_middle/src/mir/pretty.rs
compiler/rustc_middle/src/mir/query.rs
compiler/rustc_middle/src/mir/spanview.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/traits/select.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/diagnostics.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/instance.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/query.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_mir_build/src/build/expr/as_place.rs
compiler/rustc_mir_build/src/build/scope.rs
compiler/rustc_mir_build/src/lib.rs
compiler/rustc_mir_build/src/lints.rs
compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
compiler/rustc_mir_dataflow/src/framework/cursor.rs
compiler/rustc_mir_dataflow/src/framework/tests.rs
compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
compiler/rustc_mir_dataflow/src/impls/mod.rs
compiler/rustc_mir_dataflow/src/lib.rs
compiler/rustc_mir_dataflow/src/rustc_peek.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/coverage/mod.rs
compiler/rustc_mir_transform/src/dump_mir.rs
compiler/rustc_mir_transform/src/inline.rs
compiler/rustc_mir_transform/src/lib.rs
compiler/rustc_mir_transform/src/lower_slice_len.rs
compiler/rustc_mir_transform/src/normalize_array_len.rs
compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
compiler/rustc_mir_transform/src/reveal_all.rs [new file with mode: 0644]
compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
compiler/rustc_monomorphize/src/collector.rs
compiler/rustc_monomorphize/src/lib.rs
compiler/rustc_monomorphize/src/partitioning/default.rs
compiler/rustc_monomorphize/src/polymorphize.rs
compiler/rustc_monomorphize/src/util.rs
compiler/rustc_parse/Cargo.toml
compiler/rustc_parse/src/lexer/mod.rs
compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse/src/parser/stmt.rs
compiler/rustc_parse/src/parser/ty.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_impl/Cargo.toml
compiler/rustc_query_impl/src/lib.rs
compiler/rustc_query_impl/src/on_disk_cache.rs
compiler/rustc_query_impl/src/plumbing.rs
compiler/rustc_query_system/src/dep_graph/dep_node.rs
compiler/rustc_query_system/src/dep_graph/graph.rs
compiler/rustc_query_system/src/dep_graph/mod.rs
compiler/rustc_query_system/src/dep_graph/serialized.rs
compiler/rustc_query_system/src/ich/hcx.rs
compiler/rustc_query_system/src/ich/impls_hir.rs
compiler/rustc_query_system/src/lib.rs
compiler/rustc_query_system/src/query/config.rs
compiler/rustc_query_system/src/query/job.rs
compiler/rustc_query_system/src/query/mod.rs
compiler/rustc_query_system/src/query/plumbing.rs
compiler/rustc_resolve/Cargo.toml
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/imports.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_resolve/src/late/lifetimes.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_save_analysis/src/dump_visitor.rs
compiler/rustc_serialize/src/serialize.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/options.rs
compiler/rustc_session/src/parse.rs
compiler/rustc_session/src/session.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/lev_distance.rs
compiler/rustc_span/src/lev_distance/tests.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_symbol_mangling/src/lib.rs
compiler/rustc_symbol_mangling/src/v0.rs
compiler/rustc_target/src/abi/call/mod.rs
compiler/rustc_target/src/abi/mod.rs
compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs
compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs
compiler/rustc_target/src/spec/aarch64_fuchsia.rs
compiler/rustc_target/src/spec/aarch64_linux_android.rs
compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs
compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
compiler/rustc_target/src/spec/hermit_kernel_base.rs
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
compiler/rustc_target/src/spec/x86_64_fuchsia.rs
compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
compiler/rustc_target/src/spec/x86_64_unknown_none.rs [new file with mode: 0644]
compiler/rustc_trait_selection/src/lib.rs
compiler/rustc_trait_selection/src/opaque_types.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/mod.rs
compiler/rustc_trait_selection/src/traits/object_safety.rs
compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/project.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_ty_utils/src/needs_drop.rs
compiler/rustc_ty_utils/src/ty.rs
compiler/rustc_typeck/src/astconv/generics.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/bounds.rs
compiler/rustc_typeck/src/check/_match.rs
compiler/rustc_typeck/src/check/callee.rs
compiler/rustc_typeck/src/check/check.rs
compiler/rustc_typeck/src/check/coercion.rs
compiler/rustc_typeck/src/check/demand.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/suggestions.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/check/op.rs
compiler/rustc_typeck/src/check/pat.rs
compiler/rustc_typeck/src/check/place_op.rs
compiler/rustc_typeck/src/check/regionck.rs
compiler/rustc_typeck/src/check/upvar.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/type_of.rs
compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
compiler/rustc_typeck/src/lib.rs
compiler/rustc_typeck/src/variance/constraints.rs
config.toml.example
library/alloc/benches/btree/map.rs
library/alloc/src/alloc.rs
library/alloc/src/collections/binary_heap.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/map/entry.rs
library/alloc/src/collections/btree/map/tests.rs
library/alloc/src/collections/btree/set.rs
library/alloc/src/collections/btree/set/tests.rs
library/alloc/src/collections/linked_list.rs
library/alloc/src/collections/mod.rs
library/alloc/src/collections/vec_deque/mod.rs
library/alloc/src/fmt.rs
library/alloc/src/lib.rs
library/alloc/src/rc.rs
library/alloc/src/slice.rs
library/alloc/src/str.rs
library/alloc/src/string.rs
library/alloc/src/sync.rs
library/alloc/src/vec/drain.rs
library/alloc/src/vec/mod.rs
library/alloc/tests/str.rs
library/backtrace
library/core/src/alloc/layout.rs
library/core/src/any.rs
library/core/src/array/mod.rs
library/core/src/ascii.rs
library/core/src/cell.rs
library/core/src/char/convert.rs
library/core/src/char/decode.rs
library/core/src/clone.rs
library/core/src/cmp.rs
library/core/src/convert/mod.rs
library/core/src/convert/num.rs
library/core/src/default.rs
library/core/src/fmt/float.rs
library/core/src/fmt/mod.rs
library/core/src/future/mod.rs
library/core/src/internal_macros.rs
library/core/src/intrinsics.rs
library/core/src/iter/adapters/zip.rs
library/core/src/iter/sources/empty.rs
library/core/src/iter/traits/iterator.rs
library/core/src/lazy.rs
library/core/src/lib.rs
library/core/src/marker.rs
library/core/src/mem/mod.rs
library/core/src/num/error.rs
library/core/src/num/f32.rs
library/core/src/num/f64.rs
library/core/src/num/fmt.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/num/wrapping.rs
library/core/src/ops/arith.rs
library/core/src/ops/bit.rs
library/core/src/ops/control_flow.rs
library/core/src/ops/range.rs
library/core/src/option.rs
library/core/src/panic/location.rs
library/core/src/panic/panic_info.rs
library/core/src/panicking.rs
library/core/src/pin.rs
library/core/src/ptr/mod.rs
library/core/src/ptr/non_null.rs
library/core/src/ptr/unique.rs
library/core/src/result.rs
library/core/src/slice/ascii.rs
library/core/src/slice/iter.rs
library/core/src/slice/memchr.rs
library/core/src/slice/mod.rs
library/core/src/slice/raw.rs
library/core/src/str/error.rs
library/core/src/str/iter.rs
library/core/src/str/lossy.rs
library/core/src/str/mod.rs
library/core/src/str/pattern.rs
library/core/src/str/traits.rs
library/core/src/str/validations.rs
library/core/src/sync/atomic.rs
library/core/src/task/poll.rs
library/core/src/task/wake.rs
library/core/src/time.rs
library/core/tests/array.rs
library/core/tests/ascii.rs
library/core/tests/atomic.rs
library/core/tests/cell.rs
library/core/tests/char.rs
library/core/tests/fmt/float.rs
library/core/tests/lazy.rs
library/core/tests/lib.rs
library/core/tests/nonzero.rs
library/core/tests/option.rs
library/core/tests/result.rs
library/core/tests/slice.rs
library/std/Cargo.toml
library/std/src/backtrace.rs
library/std/src/collections/hash/map.rs
library/std/src/collections/hash/set.rs
library/std/src/env.rs
library/std/src/f32.rs
library/std/src/f32/tests.rs
library/std/src/f64.rs
library/std/src/f64/tests.rs
library/std/src/ffi/c_str.rs
library/std/src/ffi/mod.rs
library/std/src/ffi/os_str.rs
library/std/src/fs.rs
library/std/src/fs/tests.rs
library/std/src/io/error.rs
library/std/src/io/mod.rs
library/std/src/io/stdio.rs
library/std/src/io/util.rs
library/std/src/lib.rs
library/std/src/net/addr.rs
library/std/src/net/ip.rs
library/std/src/net/ip/tests.rs
library/std/src/net/parser.rs
library/std/src/net/tcp.rs
library/std/src/os/raw/mod.rs
library/std/src/os/unix/net/ancillary.rs
library/std/src/os/unix/net/listener.rs
library/std/src/os/unix/process.rs
library/std/src/panic.rs
library/std/src/panicking.rs
library/std/src/path.rs
library/std/src/path/tests.rs
library/std/src/process.rs
library/std/src/rt.rs
library/std/src/sync/barrier.rs
library/std/src/sync/condvar.rs
library/std/src/sync/mpsc/cache_aligned.rs
library/std/src/sync/mpsc/mod.rs
library/std/src/sys/hermit/condvar.rs
library/std/src/sys/hermit/net.rs
library/std/src/sys/itron/thread.rs
library/std/src/sys/unix/stack_overflow.rs
library/std/src/sys/unix/time.rs
library/std/src/sys/windows/c.rs
library/std/src/sys/windows/fs.rs
library/std/src/sys/windows/os.rs
library/std/src/sys/windows/path.rs
library/std/src/sys/windows/path/tests.rs
library/std/src/sys/windows/thread_local_dtor.rs
library/std/src/sys/windows/thread_local_key.rs
library/std/src/sys_common/process.rs
library/std/src/sys_common/wtf8.rs
library/std/src/thread/mod.rs
library/std/src/thread/tests.rs
library/std/src/time.rs
library/std/src/time/tests.rs
library/test/src/formatters/junit.rs
library/unwind/src/lib.rs
src/bootstrap/bin/rustc.rs
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/doc.rs
src/bootstrap/lib.rs
src/bootstrap/metadata.rs
src/bootstrap/native.rs
src/ci/docker/host-x86_64/disabled/asmjs/Dockerfile
src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile
src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh
src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh
src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh
src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh [new file with mode: 0755]
src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt [deleted file]
src/ci/docker/host-x86_64/test-various/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-llvm-10/Dockerfile [deleted file]
src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile [new file with mode: 0644]
src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
src/ci/docker/run.sh
src/ci/docker/scripts/freebsd-toolchain.sh
src/ci/github-actions/ci.yml
src/ci/pgo.sh
src/ci/run.sh
src/ci/scripts/select-xcode.sh [deleted file]
src/doc/book
src/doc/embedded-book
src/doc/nomicon
src/doc/reference
src/doc/rust-by-example
src/doc/rustc-dev-guide
src/doc/rustc/src/SUMMARY.md
src/doc/rustc/src/exploit-mitigations.md
src/doc/rustc/src/platform-support.md
src/doc/rustc/src/platform-support/x86_64-unknown-none.md [new file with mode: 0644]
src/doc/rustdoc/src/the-doc-attribute.md
src/doc/rustdoc/src/unstable-features.md
src/doc/unstable-book/src/compiler-flags/location-detail.md [new file with mode: 0644]
src/doc/unstable-book/src/compiler-flags/no-unique-section-names.md [new file with mode: 0644]
src/doc/unstable-book/src/compiler-flags/sanitizer.md
src/doc/unstable-book/src/library-features/asm.md
src/librustdoc/Cargo.toml
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/config.rs
src/librustdoc/core.rs
src/librustdoc/docfs.rs
src/librustdoc/doctest.rs
src/librustdoc/fold.rs
src/librustdoc/formats/cache.rs
src/librustdoc/formats/item_type.rs
src/librustdoc/html/format.rs
src/librustdoc/html/highlight.rs
src/librustdoc/html/highlight/fixtures/decorations.html [new file with mode: 0644]
src/librustdoc/html/highlight/fixtures/sample.html
src/librustdoc/html/highlight/tests.rs
src/librustdoc/html/layout.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/cache.rs
src/librustdoc/html/render/context.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/render/span_map.rs
src/librustdoc/html/render/write_shared.rs
src/librustdoc/html/sources.rs
src/librustdoc/html/static/css/noscript.css
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/fonts/NanumBarunGothic-LICENSE.txt [new file with mode: 0644]
src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff [new file with mode: 0644]
src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff2 [new file with mode: 0644]
src/librustdoc/html/static/fonts/noto-sans-kr-LICENSE.txt [deleted file]
src/librustdoc/html/static/fonts/noto-sans-kr-regular.woff [deleted file]
src/librustdoc/html/static/fonts/noto-sans-kr-regular.woff2 [deleted file]
src/librustdoc/html/static/js/main.js
src/librustdoc/html/static/js/scrape-examples.js [new file with mode: 0644]
src/librustdoc/html/static/js/search.js
src/librustdoc/html/static_files.rs
src/librustdoc/html/templates/page.html
src/librustdoc/json/conversions.rs
src/librustdoc/lib.rs
src/librustdoc/passes/bare_urls.rs
src/librustdoc/passes/calculate_doc_coverage.rs
src/librustdoc/passes/check_code_block_syntax.rs
src/librustdoc/passes/check_doc_test_visibility.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_intra_doc_links/early.rs
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/passes/html_tags.rs
src/librustdoc/passes/stripper.rs
src/librustdoc/scrape_examples.rs [new file with mode: 0644]
src/librustdoc/visit.rs [new file with mode: 0644]
src/librustdoc/visit_ast.rs
src/stage0.json
src/test/assembly/asm/aarch64-modifiers.rs
src/test/assembly/asm/aarch64-outline-atomics.rs
src/test/assembly/asm/aarch64-types.rs
src/test/assembly/asm/arm-modifiers.rs
src/test/assembly/asm/arm-types.rs
src/test/assembly/asm/global_asm.rs
src/test/assembly/asm/hexagon-types.rs
src/test/assembly/asm/mips-types.rs
src/test/assembly/asm/nvptx-types.rs
src/test/assembly/asm/powerpc-types.rs
src/test/assembly/asm/riscv-types.rs
src/test/assembly/asm/s390x-types.rs
src/test/assembly/asm/wasm-types.rs
src/test/assembly/asm/x86-modifiers.rs
src/test/assembly/asm/x86-types.rs
src/test/assembly/static-relocation-model.rs
src/test/codegen-units/item-collection/implicit-panic-call.rs [new file with mode: 0644]
src/test/codegen/alloc-optimisation.rs
src/test/codegen/asm-powerpc-clobbers.rs
src/test/codegen/binary-search-index-no-bound-check.rs
src/test/codegen/debug-vtable.rs
src/test/codegen/enum-bounds-check-derived-idx.rs
src/test/codegen/enum-bounds-check-issue-13926.rs
src/test/codegen/enum-bounds-check-issue-82871.rs
src/test/codegen/function-arguments.rs
src/test/codegen/issue-27130.rs
src/test/codegen/issue-73031.rs
src/test/codegen/issue-73396-bounds-check-after-position.rs
src/test/codegen/issue-73827-bounds-check-index-in-subexpr.rs
src/test/codegen/issue-75525-bounds-checks.rs
src/test/codegen/issue-75546.rs
src/test/codegen/issue-77812.rs
src/test/codegen/non-terminate/infinite-loop-1.rs
src/test/codegen/non-terminate/infinite-loop-2.rs
src/test/codegen/non-terminate/infinite-recursion.rs
src/test/codegen/non-terminate/nonempty-infinite-loop.rs
src/test/codegen/repr-transparent-aggregates-1.rs
src/test/codegen/repr-transparent-aggregates-2.rs
src/test/codegen/repr-transparent-aggregates-3.rs
src/test/codegen/sanitizer_cfi_add_canonical_jump_tables_flag.rs [new file with mode: 0644]
src/test/codegen/sanitizer_cfi_emit_type_checks.rs [new file with mode: 0644]
src/test/codegen/sanitizer_cfi_emit_type_metadata.rs [new file with mode: 0644]
src/test/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs
src/test/codegen/vec-in-place.rs
src/test/codegen/wasm_casts_trapping.rs
src/test/incremental/auxiliary/rustc-rust-log-aux.rs [new file with mode: 0644]
src/test/incremental/hashes/for_loops.rs
src/test/incremental/rustc-rust-log.rs [new file with mode: 0644]
src/test/mir-opt/inline/inline_generator.main.Inline.diff
src/test/mir-opt/inline/issue-78442.rs [new file with mode: 0644]
src/test/mir-opt/inline/issue_78442.bar.Inline.diff [new file with mode: 0644]
src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff [new file with mode: 0644]
src/test/run-make-fulldeps/coverage-llvmir/Makefile
src/test/run-make-fulldeps/coverage-reports/Makefile
src/test/run-make-fulldeps/foreign-exceptions/foo.rs
src/test/run-make-fulldeps/obtain-borrowck/driver.rs
src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/Makefile [new file with mode: 0644]
src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/examples/ex.rs [new file with mode: 0644]
src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/lib.rs [new file with mode: 0644]
src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/proc.rs [new file with mode: 0644]
src/test/run-make-fulldeps/split-debuginfo/Makefile
src/test/run-make-fulldeps/split-dwarf/Makefile
src/test/run-make-fulldeps/tools.mk
src/test/run-make/issue-36710/foo.rs
src/test/run-make/rustdoc-scrape-examples-invalid-expr/Makefile [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-invalid-expr/examples/ex.rs [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-invalid-expr/src/lib.rs [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-multiple/Makefile [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex.rs [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex2.rs [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-multiple/scrape.mk [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-multiple/src/lib.rs [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-ordering/Makefile [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex1.rs [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex2.rs [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-remap/Makefile [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-remap/examples/ex.rs [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-remap/src/a.rs [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-remap/src/lib.rs [new file with mode: 0644]
src/test/rustdoc-gui/anchor-navigable.goml [new file with mode: 0644]
src/test/rustdoc-gui/basic.goml
src/test/rustdoc-gui/check-code-blocks-margin.goml [new file with mode: 0644]
src/test/rustdoc-gui/docblock-code-block-line-number.goml [new file with mode: 0644]
src/test/rustdoc-gui/font-weight.goml
src/test/rustdoc-gui/headings.goml [new file with mode: 0644]
src/test/rustdoc-gui/javascript-disabled.goml [new file with mode: 0644]
src/test/rustdoc-gui/module-items-font.goml
src/test/rustdoc-gui/overflow-tooltip-information.goml [new file with mode: 0644]
src/test/rustdoc-gui/sidebar-macro-reexport.goml [new file with mode: 0644]
src/test/rustdoc-gui/sidebar.goml
src/test/rustdoc-gui/src/lib2/lib.rs
src/test/rustdoc-gui/src/test_docs/lib.rs
src/test/rustdoc-gui/type-declation-overflow.goml
src/test/rustdoc-js/generics.js
src/test/rustdoc-js/generics.rs
src/test/rustdoc-json/reexport/macro.rs [new file with mode: 0644]
src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs
src/test/rustdoc-ui/doc-without-codeblock.rs
src/test/rustdoc-ui/doc-without-codeblock.stderr
src/test/rustdoc-ui/invalid-doc-attr.stderr
src/test/rustdoc-ui/recursive-deref-ice.rs [new file with mode: 0644]
src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs [new file with mode: 0644]
src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr [new file with mode: 0644]
src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs [new file with mode: 0644]
src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr [new file with mode: 0644]
src/test/rustdoc/attributes.rs
src/test/rustdoc/deref-recursive-pathbuf.rs [new file with mode: 0644]
src/test/rustdoc/deref-recursive.rs [new file with mode: 0644]
src/test/rustdoc/deref-typedef.rs
src/test/rustdoc/doc-auto-cfg.rs [new file with mode: 0644]
src/test/rustdoc/doc-cfg-hide.rs
src/test/rustdoc/doc-cfg-implicit.rs
src/test/rustdoc/feature-gate-doc_auto_cfg.rs [new file with mode: 0644]
src/test/rustdoc/issue-89852.rs [new file with mode: 0644]
src/test/rustdoc/recursive-deref-sidebar.rs
src/test/rustdoc/recursive-deref.rs
src/test/rustdoc/reexports-priv.rs
src/test/rustdoc/reexports.rs
src/test/rustdoc/toggle-item-contents.rs
src/test/rustdoc/trait_alias.rs
src/test/ui/abi/unsupported.aarch64.stderr
src/test/ui/abi/unsupported.arm.stderr
src/test/ui/abi/unsupported.rs
src/test/ui/abi/unsupported.x64.stderr
src/test/ui/asm/aarch64/const.rs
src/test/ui/asm/aarch64/srcloc.rs
src/test/ui/asm/aarch64/srcloc.stderr
src/test/ui/asm/aarch64/sym.rs
src/test/ui/asm/x86_64/const.rs
src/test/ui/asm/x86_64/issue-89875.rs [new file with mode: 0644]
src/test/ui/asm/x86_64/srcloc.rs
src/test/ui/asm/x86_64/srcloc.stderr
src/test/ui/asm/x86_64/sym.rs
src/test/ui/associated-types/associated-types-path-2.rs
src/test/ui/associated-types/associated-types-path-2.stderr
src/test/ui/async-await/async-fn-nonsend.stderr
src/test/ui/async-await/issue-64130-1-sync.stderr
src/test/ui/async-await/issue-64130-2-send.stderr
src/test/ui/async-await/issue-64130-3-other.stderr
src/test/ui/async-await/issue-64130-non-send-future-diags.rs
src/test/ui/async-await/issue-64130-non-send-future-diags.stderr
src/test/ui/async-await/issue-71137.rs
src/test/ui/async-await/issue-71137.stderr
src/test/ui/async-await/issues/issue-67893.rs
src/test/ui/async-await/issues/issue-67893.stderr
src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr
src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs
src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
src/test/ui/async-await/pin-needed-to-poll-2.stderr
src/test/ui/attributes/invalid-doc-attr.stderr
src/test/ui/binding/ambiguity-item.stderr
src/test/ui/closures/2229_closure_analysis/issue-90465.fixed [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/issue-90465.rs [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/issue-90465.stderr [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed
src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs
src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr
src/test/ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed
src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs
src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr
src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed
src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs
src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr
src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
src/test/ui/closures/print/closure-print-generic-verbose-2.stderr
src/test/ui/closures/print/closure-print-verbose.stderr
src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs
src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs
src/test/ui/coherence/auxiliary/error_lib.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-overlap-negate-alias-strict.stderr [new file with mode: 0644]
src/test/ui/coherence/coherence-overlap-negate-not-use-feature-gate.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-overlap-negate-not-use-feature-gate.stderr [new file with mode: 0644]
src/test/ui/coherence/coherence-overlap-negate-strict.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-overlap-negate-use-feature-gate.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-overlap-negative-trait.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-overlap-trait-alias.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-overlap-trait-alias.stderr [new file with mode: 0644]
src/test/ui/conditional-compilation/cfg-arg-invalid-7.rs [new file with mode: 0644]
src/test/ui/conditional-compilation/cfg-arg-invalid-7.stderr [new file with mode: 0644]
src/test/ui/const-generics/defaults/default-annotation.rs
src/test/ui/const-generics/defaults/doesnt_infer.rs [new file with mode: 0644]
src/test/ui/const-generics/defaults/doesnt_infer.stderr [new file with mode: 0644]
src/test/ui/const-generics/defaults/rp_impl_trait.rs [new file with mode: 0644]
src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs [new file with mode: 0644]
src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr [new file with mode: 0644]
src/test/ui/const-generics/defaults/trait_objects.rs [new file with mode: 0644]
src/test/ui/const-generics/defaults/trait_objects_fail.rs [new file with mode: 0644]
src/test/ui/const-generics/defaults/trait_objects_fail.stderr [new file with mode: 0644]
src/test/ui/const-generics/defaults/wfness.rs [new file with mode: 0644]
src/test/ui/const-generics/defaults/wfness.stderr [new file with mode: 0644]
src/test/ui/const-generics/defaults/wrong-order.rs
src/test/ui/const-generics/defaults/wrong-order.stderr
src/test/ui/const-generics/expose-default-substs-param-env.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/issue-85848.stderr
src/test/ui/const-generics/issues/issue-67375.full.stderr
src/test/ui/const-generics/issues/issue-67375.rs
src/test/ui/const-generics/issues/issue-67945-1.full.stderr
src/test/ui/const-generics/issues/issue-67945-1.rs
src/test/ui/const-generics/issues/issue-88997.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-88997.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-89304.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-89334.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-90364.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-90364.stderr [new file with mode: 0644]
src/test/ui/consts/closure-structural-match-issue-90013.rs [new file with mode: 0644]
src/test/ui/consts/const-eval/issue-84957-const-str-as-bytes.rs [new file with mode: 0644]
src/test/ui/consts/precise-drop-with-promoted.rs [new file with mode: 0644]
src/test/ui/consts/promote-not.rs
src/test/ui/consts/promote-not.stderr
src/test/ui/consts/promoted-const-drop.rs [new file with mode: 0644]
src/test/ui/consts/promoted-const-drop.stderr [new file with mode: 0644]
src/test/ui/consts/promoted-storage.rs [new file with mode: 0644]
src/test/ui/consts/qualif-indirect-mutation-fail.rs [new file with mode: 0644]
src/test/ui/consts/qualif-indirect-mutation-fail.stderr [new file with mode: 0644]
src/test/ui/consts/qualif-indirect-mutation-pass.rs [new file with mode: 0644]
src/test/ui/consts/qualif-union.rs [new file with mode: 0644]
src/test/ui/consts/qualif-union.stderr [new file with mode: 0644]
src/test/ui/deprecation/invalid-literal.stderr
src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr
src/test/ui/derives/derives-span-Hash-enum.stderr
src/test/ui/derives/derives-span-Hash-struct.stderr
src/test/ui/derives/derives-span-Hash-tuple-struct.stderr
src/test/ui/did_you_mean/issue-42764.stderr
src/test/ui/empty/empty-struct-unit-expr.stderr
src/test/ui/entry-point/imported_main_conflict.rs
src/test/ui/entry-point/imported_main_conflict.stderr
src/test/ui/enum-discriminant/issue-90038.rs [new file with mode: 0644]
src/test/ui/error-codes/E0283.stderr
src/test/ui/error-codes/E0618.stderr
src/test/ui/error-codes/E0637.rs
src/test/ui/error-codes/E0637.stderr
src/test/ui/error-codes/E0659.stderr
src/test/ui/extern/extern-methods.rs
src/test/ui/extern/extern-thiscall.rs
src/test/ui/extern/extern-vectorcall.rs
src/test/ui/feature-gates/feature-gate-relaxed_struct_unsize.rs [deleted file]
src/test/ui/feature-gates/feature-gate-relaxed_struct_unsize.stderr [deleted file]
src/test/ui/feature-gates/feature-gate-type_changing_struct_update.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-type_changing_struct_update.stderr [new file with mode: 0644]
src/test/ui/feature-gates/issue-43106-gating-of-macro_use.stderr
src/test/ui/function-pointer/function-pointer-comparison-issue-54685.rs
src/test/ui/generic-associated-types/issue-74816.stderr
src/test/ui/generic-associated-types/issue-85921.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-86483.stderr
src/test/ui/generic-associated-types/issue-87258_a.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-87258_a.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-87258_b.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-87258_b.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-88459.rs [new file with mode: 0644]
src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr
src/test/ui/hello2021.rs
src/test/ui/hidden-doc-associated-item.rs [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-44005.rs [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-56556.rs [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.stderr
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.rs
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.stderr [deleted file]
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-74261.rs [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-76956.rs [new file with mode: 0644]
src/test/ui/hrtb/issue-62203-hrtb-ice.rs
src/test/ui/hrtb/issue-62203-hrtb-ice.stderr
src/test/ui/hrtb/issue-90177.rs [new file with mode: 0644]
src/test/ui/hygiene/auxiliary/fields.rs [new file with mode: 0644]
src/test/ui/hygiene/auxiliary/methods.rs [new file with mode: 0644]
src/test/ui/hygiene/auxiliary/pub_hygiene.rs [new file with mode: 0644]
src/test/ui/hygiene/auxiliary/use_by_macro.rs [new file with mode: 0644]
src/test/ui/hygiene/auxiliary/variants.rs [new file with mode: 0644]
src/test/ui/hygiene/cross-crate-define-and-use.rs [new file with mode: 0644]
src/test/ui/hygiene/cross-crate-fields.rs [new file with mode: 0644]
src/test/ui/hygiene/cross-crate-glob-hygiene.rs [new file with mode: 0644]
src/test/ui/hygiene/cross-crate-glob-hygiene.stderr [new file with mode: 0644]
src/test/ui/hygiene/cross-crate-methods.rs [new file with mode: 0644]
src/test/ui/hygiene/cross-crate-name-collision.rs [new file with mode: 0644]
src/test/ui/hygiene/cross-crate-name-hiding-2.rs [new file with mode: 0644]
src/test/ui/hygiene/cross-crate-name-hiding-2.stderr [new file with mode: 0644]
src/test/ui/hygiene/cross-crate-name-hiding.rs [new file with mode: 0644]
src/test/ui/hygiene/cross-crate-name-hiding.stderr [new file with mode: 0644]
src/test/ui/hygiene/cross-crate-redefine.rs [new file with mode: 0644]
src/test/ui/hygiene/cross-crate-redefine.stderr [new file with mode: 0644]
src/test/ui/hygiene/cross-crate-variants.rs [new file with mode: 0644]
src/test/ui/hygiene/cross_crate_hygiene.rs [deleted file]
src/test/ui/hygiene/rustc-macro-transparency.stderr
src/test/ui/impl-trait/auto-trait-leak2.stderr
src/test/ui/impl-trait/equality.rs
src/test/ui/impl-trait/equality.stderr
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr [deleted file]
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr [deleted file]
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
src/test/ui/impl-trait/no-method-suggested-traits.stderr
src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr [deleted file]
src/test/ui/impl-trait/static-return-lifetime-infered.rs
src/test/ui/impl-trait/static-return-lifetime-infered.stderr
src/test/ui/imports/duplicate.stderr
src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr
src/test/ui/imports/glob-shadowing.stderr
src/test/ui/imports/issue-53269.stderr
src/test/ui/imports/issue-55884-1.stderr
src/test/ui/imports/issue-56125.stderr
src/test/ui/imports/issue-57539.stderr
src/test/ui/imports/local-modularized-tricky-fail-1.stderr
src/test/ui/imports/macro-paths.stderr
src/test/ui/imports/macros.stderr
src/test/ui/imports/rfc-1560-warning-cycle.stderr
src/test/ui/imports/shadow_builtin_macros.stderr
src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr
src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr
src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
src/test/ui/inference/issue-71732.stderr
src/test/ui/inference/issue-72616.stderr
src/test/ui/intrinsics/const-eval-select-bad.rs
src/test/ui/intrinsics/const-eval-select-bad.stderr
src/test/ui/issues/issue-16966.stderr
src/test/ui/issues/issue-21160.stderr
src/test/ui/issues/issue-22933-2.stderr
src/test/ui/issues/issue-23122-2.stderr
src/test/ui/issues/issue-29147.stderr
src/test/ui/issues/issue-31299.rs
src/test/ui/issues/issue-40827.stderr
src/test/ui/issues/issue-44005.rs [deleted file]
src/test/ui/issues/issue-44005.stderr [deleted file]
src/test/ui/issues/issue-54954.stderr
src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs
src/test/ui/issues/issue-69455.rs
src/test/ui/issues/issue-69455.stderr
src/test/ui/issues/issue-69683.rs
src/test/ui/issues/issue-69683.stderr
src/test/ui/issues/issue-72690.rs
src/test/ui/issues/issue-72690.stderr
src/test/ui/issues/issue-73427.stderr
src/test/ui/iterators/into-iter-on-arrays-2021.rs
src/test/ui/iterators/rsplit-clone.rs [new file with mode: 0644]
src/test/ui/let-else/issue-89960.rs [new file with mode: 0644]
src/test/ui/let-else/issue-89960.stderr [new file with mode: 0644]
src/test/ui/let-else/let-else-bool-binop-init.stderr
src/test/ui/let-else/let-else-brace-before-else.stderr
src/test/ui/let-else/let-else-if.rs [new file with mode: 0644]
src/test/ui/let-else/let-else-if.stderr [new file with mode: 0644]
src/test/ui/lifetimes/issue-90170-elision-mismatch.fixed [new file with mode: 0644]
src/test/ui/lifetimes/issue-90170-elision-mismatch.nll.stderr [new file with mode: 0644]
src/test/ui/lifetimes/issue-90170-elision-mismatch.rs [new file with mode: 0644]
src/test/ui/lifetimes/issue-90170-elision-mismatch.stderr [new file with mode: 0644]
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.stderr
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.stderr
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.stderr
src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr
src/test/ui/lint/force-warn/allowed-cli-deny-by-default-lint.rs
src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.rs
src/test/ui/lint/force-warn/warn-by-default-lint-two-modules.rs
src/test/ui/lint/force-warn/warnings-lint-group.rs
src/test/ui/lint/force-warn/warnings-lint-group.stderr
src/test/ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs [new file with mode: 0644]
src/test/ui/lint/must_not_suspend/gated.rs [new file with mode: 0644]
src/test/ui/lint/must_not_suspend/gated.stderr [new file with mode: 0644]
src/test/ui/lint/must_not_suspend/issue-89562.rs [new file with mode: 0644]
src/test/ui/lint/must_not_suspend/mutex.rs
src/test/ui/lint/must_not_suspend/mutex.stderr
src/test/ui/lint/must_not_suspend/warn.rs
src/test/ui/lint/must_not_suspend/warn.stderr
src/test/ui/lint/unused_parens_json_suggestion.fixed
src/test/ui/lint/unused_parens_json_suggestion.rs
src/test/ui/lint/unused_parens_json_suggestion.stderr
src/test/ui/lint/unused_parens_remove_json_suggestion.fixed
src/test/ui/lint/unused_parens_remove_json_suggestion.rs
src/test/ui/lint/unused_parens_remove_json_suggestion.stderr
src/test/ui/macros/ambiguity-legacy-vs-modern.stderr
src/test/ui/macros/macro-path-prelude-shadowing.stderr
src/test/ui/macros/macro-shadowing.stderr
src/test/ui/macros/missing-bang-in-decl.fixed [new file with mode: 0644]
src/test/ui/macros/missing-bang-in-decl.rs [new file with mode: 0644]
src/test/ui/macros/missing-bang-in-decl.stderr [new file with mode: 0644]
src/test/ui/macros/out-of-order-shadowing.stderr
src/test/ui/macros/restricted-shadowing-legacy.stderr
src/test/ui/macros/restricted-shadowing-modern.stderr
src/test/ui/marker_trait_attr/region-overlap.stderr
src/test/ui/matches2021.rs
src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs
src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
src/test/ui/mir-dataflow/indirect-mutation-offset.rs [deleted file]
src/test/ui/mir-dataflow/indirect-mutation-offset.stderr [deleted file]
src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr
src/test/ui/mut/mutable-enum-indirect.stderr
src/test/ui/nll/issue-73159-rpit-static.rs
src/test/ui/nll/issue-73159-rpit-static.stderr
src/test/ui/nll/issue-78561.rs [new file with mode: 0644]
src/test/ui/nll/ty-outlives/impl-trait-captures.rs
src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
src/test/ui/no_send-enum.stderr
src/test/ui/no_share-enum.stderr
src/test/ui/on-unimplemented/bad-annotation.stderr
src/test/ui/panics/location-detail-panic-no-column.rs [new file with mode: 0644]
src/test/ui/panics/location-detail-panic-no-column.run.stderr [new file with mode: 0644]
src/test/ui/panics/location-detail-panic-no-file.rs [new file with mode: 0644]
src/test/ui/panics/location-detail-panic-no-file.run.stderr [new file with mode: 0644]
src/test/ui/panics/location-detail-panic-no-line.rs [new file with mode: 0644]
src/test/ui/panics/location-detail-panic-no-line.run.stderr [new file with mode: 0644]
src/test/ui/panics/location-detail-unwrap-no-file.rs [new file with mode: 0644]
src/test/ui/panics/location-detail-unwrap-no-file.run.stderr [new file with mode: 0644]
src/test/ui/parser/auxiliary/issue-89971-outer-attr-following-inner-attr-ice.rs [new file with mode: 0644]
src/test/ui/parser/issue-89971-outer-attr-following-inner-attr-ice.rs [new file with mode: 0644]
src/test/ui/parser/issue-89971-outer-attr-following-inner-attr-ice.stderr [new file with mode: 0644]
src/test/ui/parser/recover-for-loop-parens-around-head.rs
src/test/ui/parser/recover-for-loop-parens-around-head.stderr
src/test/ui/parser/unicode-control-codepoints.rs [new file with mode: 0644]
src/test/ui/parser/unicode-control-codepoints.stderr [new file with mode: 0644]
src/test/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs
src/test/ui/pattern/non-structural-match-types.rs [new file with mode: 0644]
src/test/ui/pattern/non-structural-match-types.stderr [new file with mode: 0644]
src/test/ui/polymorphization/predicates.rs
src/test/ui/polymorphization/predicates.stderr
src/test/ui/privacy/privacy2.stderr
src/test/ui/privacy/privacy3.stderr
src/test/ui/privacy/pub-priv-dep/pub-priv1.rs
src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr
src/test/ui/proc-macro/ambiguous-builtin-attrs.rs
src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr
src/test/ui/proc-macro/derive-helper-shadowing.stderr
src/test/ui/proc-macro/generate-mod.rs
src/test/ui/proc-macro/generate-mod.stderr
src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs
src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stderr
src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout
src/test/ui/proc-macro/helper-attr-blocked-by-import-ambig.stderr
src/test/ui/proc-macro/issue-41211.stderr
src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs
src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr
src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout
src/test/ui/proc-macro/meta-macro-hygiene.stdout
src/test/ui/proc-macro/nonterminal-token-hygiene.stdout
src/test/ui/proc-macro/proc-macro-attributes.stderr
src/test/ui/query-system/issue-83479.rs [new file with mode: 0644]
src/test/ui/query-system/issue-83479.stderr [new file with mode: 0644]
src/test/ui/resolve/issue-90113.rs [new file with mode: 0644]
src/test/ui/resolve/issue-90113.stderr [new file with mode: 0644]
src/test/ui/resolve/privacy-enum-ctor.stderr
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr
src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr
src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr
src/test/ui/rt-explody-panic-payloads.rs
src/test/ui/rust-2018/uniform-paths/ambiguity-macros-nested.stderr
src/test/ui/rust-2018/uniform-paths/ambiguity-macros.stderr
src/test/ui/rust-2018/uniform-paths/ambiguity-nested.stderr
src/test/ui/rust-2018/uniform-paths/ambiguity.stderr
src/test/ui/rust-2018/uniform-paths/auxiliary/issue-55779-extern-trait.rs [new file with mode: 0644]
src/test/ui/rust-2018/uniform-paths/auxiliary/issue-87932-a.rs [new file with mode: 0644]
src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.stderr
src/test/ui/rust-2018/uniform-paths/block-scoped-shadow.stderr
src/test/ui/rust-2018/uniform-paths/issue-55779.rs [new file with mode: 0644]
src/test/ui/rust-2018/uniform-paths/issue-56596.stderr
src/test/ui/rust-2018/uniform-paths/issue-87932.rs [new file with mode: 0644]
src/test/ui/rust-2018/uniform-paths/issue-87932.stderr [new file with mode: 0644]
src/test/ui/rust-2018/uniform-paths/macro-rules.stderr
src/test/ui/rust-2018/uniform-paths/redundant.rs
src/test/ui/rust-2021/future-prelude-collision-shadow.stderr
src/test/ui/rust-2021/prelude2021.rs
src/test/ui/rust-2021/reserved-prefixes-migration.fixed
src/test/ui/rust-2021/reserved-prefixes-migration.rs
src/test/ui/rustc-rust-log.rs
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.nll.stderr [deleted file]
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.rs
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr [deleted file]
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
src/test/ui/suggestions/core-std-import-order-issue-83564.stderr
src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr
src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs
src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
src/test/ui/suggestions/into-str.stderr
src/test/ui/suggestions/issue-84973-blacklist.stderr
src/test/ui/suggestions/issue-90213-expected-boxfuture-self-ice.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-90213-expected-boxfuture-self-ice.stderr [new file with mode: 0644]
src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr
src/test/ui/suggestions/slice-issue-87994.stderr
src/test/ui/suggestions/suggest-on-bare-closure-call.stderr
src/test/ui/suggestions/suggest-tryinto-edition-change.rs [new file with mode: 0644]
src/test/ui/suggestions/suggest-tryinto-edition-change.stderr [new file with mode: 0644]
src/test/ui/suggestions/undeclared-module-alloc.rs [new file with mode: 0644]
src/test/ui/suggestions/undeclared-module-alloc.stderr [new file with mode: 0644]
src/test/ui/trait-bounds/issue-75961.rs [new file with mode: 0644]
src/test/ui/traits/cache-reached-depth-ice.rs
src/test/ui/traits/cache-reached-depth-ice.stderr
src/test/ui/traits/issue-71136.stderr
src/test/ui/traits/issue-77982.rs
src/test/ui/traits/issue-77982.stderr
src/test/ui/traits/issue-83538-tainted-cache-after-cycle.rs
src/test/ui/traits/issue-83538-tainted-cache-after-cycle.stderr
src/test/ui/traits/issue-90195-2.rs [new file with mode: 0644]
src/test/ui/traits/issue-90195.rs [new file with mode: 0644]
src/test/ui/traits/multidispatch-convert-ambig-dest.rs
src/test/ui/traits/multidispatch-convert-ambig-dest.stderr
src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr
src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.rs
src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.stderr [deleted file]
src/test/ui/traits/param-without-lifetime-constraint.stderr
src/test/ui/traits/self-without-lifetime-constraint.stderr
src/test/ui/traits/test-2.rs
src/test/ui/traits/test-2.stderr
src/test/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr
src/test/ui/type-alias-impl-trait/auto-trait-leakage2.stderr
src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs
src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr
src/test/ui/type-alias-impl-trait/issue-89686.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-89686.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-89806.rs [new file with mode: 0644]
src/test/ui/typeck/issue-89806.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-89935.rs [new file with mode: 0644]
src/test/ui/typeck/issue-90101.rs [new file with mode: 0644]
src/test/ui/typeck/issue-90101.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-90164.rs [new file with mode: 0644]
src/test/ui/typeck/issue-90164.stderr [new file with mode: 0644]
src/test/ui/typeck/typeck-unsafe-always-share.stderr
src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.stderr
src/test/ui/uniform-paths/basic-nested.rs
src/test/ui/uniform-paths/basic.rs
src/test/ui/uniform-paths/macros-nested.rs
src/test/ui/uniform-paths/macros.rs
src/test/ui/unique-object-noncopyable.stderr
src/test/ui/unsized-locals/unsized-exprs.stderr
src/test/ui/unsized/unchanged-param.rs
src/test/ui/unsized/unsized-bare-typaram.stderr
src/test/ui/unsized/unsized-struct.stderr
src/test/ui/unused-crate-deps/extern-loc-missing-loc.rs
src/test/ui/variance/variance-associated-consts.rs [new file with mode: 0644]
src/test/ui/variance/variance-associated-consts.stderr [new file with mode: 0644]
src/tools/bump-stage0/src/main.rs
src/tools/cargo
src/tools/clippy/.cargo/config [deleted file]
src/tools/clippy/.cargo/config.toml [new file with mode: 0644]
src/tools/clippy/.github/deploy.sh
src/tools/clippy/CHANGELOG.md
src/tools/clippy/CONTRIBUTING.md
src/tools/clippy/Cargo.toml
src/tools/clippy/clippy_dev/Cargo.toml
src/tools/clippy/clippy_dev/src/main.rs
src/tools/clippy/clippy_dev/src/new_lint.rs
src/tools/clippy/clippy_dev/src/update_lints.rs
src/tools/clippy/clippy_lints/Cargo.toml
src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/casts/mod.rs
src/tools/clippy/clippy_lints/src/copies.rs
src/tools/clippy/clippy_lints/src/default.rs
src/tools/clippy/clippy_lints/src/deprecated_lints.rs
src/tools/clippy/clippy_lints/src/dereference.rs
src/tools/clippy/clippy_lints/src/disallowed_type.rs
src/tools/clippy/clippy_lints/src/doc.rs
src/tools/clippy/clippy_lints/src/entry.rs
src/tools/clippy/clippy_lints/src/enum_variants.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/eta_reduction.rs
src/tools/clippy/clippy_lints/src/format.rs
src/tools/clippy/clippy_lints/src/format_args.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/functions/mod.rs
src/tools/clippy/clippy_lints/src/identity_op.rs
src/tools/clippy/clippy_lints/src/if_not_else.rs
src/tools/clippy/clippy_lints/src/if_then_panic.rs [deleted file]
src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
src/tools/clippy/clippy_lints/src/inherent_to_string.rs
src/tools/clippy/clippy_lints/src/int_plus_one.rs
src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.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_complexity.rs
src/tools/clippy/clippy_lints/src/lib.register_correctness.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/utils.rs
src/tools/clippy/clippy_lints/src/manual_assert.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
src/tools/clippy/clippy_lints/src/match_result_ok.rs
src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches.rs
src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
src/tools/clippy/clippy_lints/src/misc_early/double_neg.rs
src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/misc_early/mod.rs
src/tools/clippy/clippy_lints/src/misc_early/unseparated_literal_suffix.rs [deleted file]
src/tools/clippy/clippy_lints/src/missing_inline.rs
src/tools/clippy/clippy_lints/src/module_style.rs
src/tools/clippy/clippy_lints/src/mut_mut.rs
src/tools/clippy/clippy_lints/src/needless_borrow.rs
src/tools/clippy/clippy_lints/src/no_effect.rs
src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
src/tools/clippy/clippy_lints/src/option_if_let_else.rs
src/tools/clippy/clippy_lints/src/ptr.rs
src/tools/clippy/clippy_lints/src/question_mark.rs
src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
src/tools/clippy/clippy_lints/src/shadow.rs
src/tools/clippy/clippy_lints/src/strings.rs
src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
src/tools/clippy/clippy_lints/src/trailing_empty_array.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/transmute/mod.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/unicode.rs
src/tools/clippy/clippy_lints/src/uninit_vec.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/unit_hash.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
src/tools/clippy/clippy_lints/src/utils/conf.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/vec.rs
src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
src/tools/clippy/clippy_utils/Cargo.toml
src/tools/clippy/clippy_utils/src/camel_case.rs [deleted file]
src/tools/clippy/clippy_utils/src/consts.rs
src/tools/clippy/clippy_utils/src/diagnostics.rs
src/tools/clippy/clippy_utils/src/higher.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/paths.rs
src/tools/clippy/clippy_utils/src/str_utils.rs [new file with mode: 0644]
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/clippy/doc/adding_lints.md
src/tools/clippy/doc/basics.md
src/tools/clippy/rust-toolchain
src/tools/clippy/tests/compile-test.rs
src/tools/clippy/tests/missing-test-files.rs
src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed
src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs
src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.stderr
src/tools/clippy/tests/ui-toml/functions_maxlines/test.rs
src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr
src/tools/clippy/tests/ui-toml/toml_disallowed_type/clippy.toml
src/tools/clippy/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.rs
src/tools/clippy/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.stderr
src/tools/clippy/tests/ui/assertions_on_constants.rs
src/tools/clippy/tests/ui/assertions_on_constants.stderr
src/tools/clippy/tests/ui/async_yields_async.fixed
src/tools/clippy/tests/ui/async_yields_async.rs
src/tools/clippy/tests/ui/async_yields_async.stderr
src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
src/tools/clippy/tests/ui/await_holding_lock.rs
src/tools/clippy/tests/ui/await_holding_lock.stderr
src/tools/clippy/tests/ui/await_holding_refcell_ref.rs
src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr
src/tools/clippy/tests/ui/cast.rs
src/tools/clippy/tests/ui/cast.stderr
src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed
src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs
src/tools/clippy/tests/ui/crashes/auxiliary/ice-7868-aux.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/crashes/ice-3969.rs
src/tools/clippy/tests/ui/crashes/ice-3969.stderr
src/tools/clippy/tests/ui/crashes/ice-5207.rs
src/tools/clippy/tests/ui/crashes/ice-6252.rs
src/tools/clippy/tests/ui/crashes/ice-6252.stderr
src/tools/clippy/tests/ui/crashes/ice-7231.rs
src/tools/clippy/tests/ui/crashes/ice-7868.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/crashes/ice-7868.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/crashes/ice-7869.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/crashes/ice-7869.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs
src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs
src/tools/clippy/tests/ui/deprecated.rs
src/tools/clippy/tests/ui/deprecated.stderr
src/tools/clippy/tests/ui/diverging_sub_expression.rs
src/tools/clippy/tests/ui/diverging_sub_expression.stderr
src/tools/clippy/tests/ui/doc/doc-fixable.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/doc/doc-fixable.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/doc/doc-fixable.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/doc/doc.rs [deleted file]
src/tools/clippy/tests/ui/doc/doc.stderr [deleted file]
src/tools/clippy/tests/ui/doc/issue_1832.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/doc/issue_902.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
src/tools/clippy/tests/ui/doc_errors.rs
src/tools/clippy/tests/ui/doc_errors.stderr
src/tools/clippy/tests/ui/doc_unsafe.rs
src/tools/clippy/tests/ui/enum_variants.stderr
src/tools/clippy/tests/ui/equatable_if_let.fixed
src/tools/clippy/tests/ui/equatable_if_let.rs
src/tools/clippy/tests/ui/equatable_if_let.stderr
src/tools/clippy/tests/ui/eval_order_dependence.rs
src/tools/clippy/tests/ui/eval_order_dependence.stderr
src/tools/clippy/tests/ui/expect_fun_call.fixed
src/tools/clippy/tests/ui/expect_fun_call.rs
src/tools/clippy/tests/ui/expect_fun_call.stderr
src/tools/clippy/tests/ui/fallible_impl_from.rs
src/tools/clippy/tests/ui/fallible_impl_from.stderr
src/tools/clippy/tests/ui/field_reassign_with_default.rs
src/tools/clippy/tests/ui/field_reassign_with_default.stderr
src/tools/clippy/tests/ui/fn_to_numeric_cast_any.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr [new file with mode: 0644]
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/format_args.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/format_args.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/format_args.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/format_args_unfixable.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/format_args_unfixable.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/future_not_send.rs
src/tools/clippy/tests/ui/future_not_send.stderr
src/tools/clippy/tests/ui/if_not_else.rs
src/tools/clippy/tests/ui/if_not_else.stderr
src/tools/clippy/tests/ui/if_then_panic.fixed [deleted file]
src/tools/clippy/tests/ui/if_then_panic.rs [deleted file]
src/tools/clippy/tests/ui/if_then_panic.stderr [deleted file]
src/tools/clippy/tests/ui/implicit_hasher.rs
src/tools/clippy/tests/ui/implicit_hasher.stderr
src/tools/clippy/tests/ui/implicit_return.fixed
src/tools/clippy/tests/ui/implicit_return.rs
src/tools/clippy/tests/ui/implicit_return.stderr
src/tools/clippy/tests/ui/implicit_saturating_sub.fixed
src/tools/clippy/tests/ui/implicit_saturating_sub.rs
src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed
src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs
src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr
src/tools/clippy/tests/ui/issue-7447.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/issue_4266.rs
src/tools/clippy/tests/ui/issue_4266.stderr
src/tools/clippy/tests/ui/iter_count.fixed
src/tools/clippy/tests/ui/iter_count.rs
src/tools/clippy/tests/ui/iter_count.stderr
src/tools/clippy/tests/ui/len_without_is_empty.rs
src/tools/clippy/tests/ui/len_without_is_empty.stderr
src/tools/clippy/tests/ui/literals.rs
src/tools/clippy/tests/ui/literals.stderr
src/tools/clippy/tests/ui/macro_use_imports.fixed
src/tools/clippy/tests/ui/macro_use_imports.rs
src/tools/clippy/tests/ui/macro_use_imports.stderr
src/tools/clippy/tests/ui/manual_assert.edition2018.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_assert.edition2018.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_assert.edition2021.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_assert.edition2021.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_assert.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_assert.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_async_fn.fixed
src/tools/clippy/tests/ui/manual_async_fn.rs
src/tools/clippy/tests/ui/manual_async_fn.stderr
src/tools/clippy/tests/ui/manual_map_option.fixed
src/tools/clippy/tests/ui/manual_map_option.rs
src/tools/clippy/tests/ui/manual_map_option.stderr
src/tools/clippy/tests/ui/manual_unwrap_or.fixed
src/tools/clippy/tests/ui/manual_unwrap_or.rs
src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
src/tools/clippy/tests/ui/match_overlapping_arm.rs
src/tools/clippy/tests/ui/match_overlapping_arm.stderr
src/tools/clippy/tests/ui/match_ref_pats.rs
src/tools/clippy/tests/ui/match_ref_pats.stderr
src/tools/clippy/tests/ui/match_str_case_mismatch.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/match_str_case_mismatch.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/match_wild_err_arm.edition2018.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/match_wild_err_arm.rs
src/tools/clippy/tests/ui/match_wild_err_arm.stderr [deleted file]
src/tools/clippy/tests/ui/methods.rs
src/tools/clippy/tests/ui/methods.stderr
src/tools/clippy/tests/ui/missing-doc.rs
src/tools/clippy/tests/ui/missing-doc.stderr
src/tools/clippy/tests/ui/missing_panics_doc.rs
src/tools/clippy/tests/ui/missing_panics_doc.stderr
src/tools/clippy/tests/ui/mut_mut.rs
src/tools/clippy/tests/ui/mut_mut.stderr
src/tools/clippy/tests/ui/needless_borrow_pat.rs
src/tools/clippy/tests/ui/needless_borrow_pat.stderr
src/tools/clippy/tests/ui/needless_lifetimes.rs
src/tools/clippy/tests/ui/needless_lifetimes.stderr
src/tools/clippy/tests/ui/needless_return.fixed
src/tools/clippy/tests/ui/needless_return.rs
src/tools/clippy/tests/ui/needless_return.stderr
src/tools/clippy/tests/ui/no_effect.rs
src/tools/clippy/tests/ui/no_effect.stderr
src/tools/clippy/tests/ui/non_expressive_names.rs
src/tools/clippy/tests/ui/nonminimal_bool.stderr
src/tools/clippy/tests/ui/option_if_let_else.fixed
src/tools/clippy/tests/ui/option_if_let_else.rs
src/tools/clippy/tests/ui/option_if_let_else.stderr
src/tools/clippy/tests/ui/panic_in_result_fn.rs
src/tools/clippy/tests/ui/panic_in_result_fn.stderr
src/tools/clippy/tests/ui/ptr_arg.rs
src/tools/clippy/tests/ui/ptr_arg.stderr
src/tools/clippy/tests/ui/question_mark.fixed
src/tools/clippy/tests/ui/question_mark.rs
src/tools/clippy/tests/ui/question_mark.stderr
src/tools/clippy/tests/ui/redundant_clone.fixed
src/tools/clippy/tests/ui/redundant_clone.stderr
src/tools/clippy/tests/ui/ref_binding_to_reference.rs
src/tools/clippy/tests/ui/ref_binding_to_reference.stderr
src/tools/clippy/tests/ui/rename.fixed
src/tools/clippy/tests/ui/rename.rs
src/tools/clippy/tests/ui/rename.stderr
src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
src/tools/clippy/tests/ui/shadow.rs
src/tools/clippy/tests/ui/shadow.stderr
src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs
src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs
src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr
src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs
src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
src/tools/clippy/tests/ui/single_component_path_imports.fixed
src/tools/clippy/tests/ui/single_component_path_imports.rs
src/tools/clippy/tests/ui/single_component_path_imports.stderr
src/tools/clippy/tests/ui/single_component_path_imports_macro.fixed
src/tools/clippy/tests/ui/single_component_path_imports_macro.rs
src/tools/clippy/tests/ui/single_component_path_imports_macro.stderr
src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs
src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr
src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs
src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs
src/tools/clippy/tests/ui/string_slice.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/string_slice.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/to_string_in_display.rs
src/tools/clippy/tests/ui/trailing_empty_array.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/trailing_empty_array.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/transmute.rs
src/tools/clippy/tests/ui/transmute.stderr
src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/uninit_vec.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/uninit_vec.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/unit_hash.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/unit_hash.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/unnecessary_sort_by.fixed
src/tools/clippy/tests/ui/unnecessary_sort_by.rs
src/tools/clippy/tests/ui/unnecessary_sort_by.stderr
src/tools/clippy/tests/ui/unused_async.rs
src/tools/clippy/tests/ui/unused_async.stderr
src/tools/clippy/tests/ui/use_self.fixed
src/tools/clippy/tests/ui/use_self.rs
src/tools/clippy/tests/ui/use_self.stderr
src/tools/clippy/tests/ui/used_underscore_binding.rs
src/tools/clippy/tests/ui/used_underscore_binding.stderr
src/tools/clippy/tests/ui/useless_conversion.fixed
src/tools/clippy/tests/ui/useless_conversion.rs
src/tools/clippy/tests/ui/wildcard_imports.fixed
src/tools/clippy/tests/ui/wildcard_imports.rs
src/tools/clippy/tests/ui/wildcard_imports.stderr
src/tools/clippy/tests/ui/wrong_self_convention.rs
src/tools/clippy/tests/ui/wrong_self_convention.stderr
src/tools/clippy/tests/ui/wrong_self_convention2.rs
src/tools/clippy/tests/ui/wrong_self_convention2.stderr
src/tools/clippy/tests/ui/wrong_self_conventions_mut.rs
src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr
src/tools/clippy/tests/ui_test/eq_op.rs [new file with mode: 0644]
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/header/tests.rs
src/tools/compiletest/src/json.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/linkchecker/main.rs
src/tools/miri
src/tools/rust-analyzer
src/tools/rustdoc-js/tester.js
src/tools/rustfmt/.github/workflows/upload-assets.yml
src/tools/rustfmt/.github/workflows/windows.yml
src/tools/rustfmt/.gitignore
src/tools/rustfmt/CHANGELOG.md
src/tools/rustfmt/Cargo.lock
src/tools/rustfmt/Cargo.toml
src/tools/rustfmt/Configurations.md
src/tools/rustfmt/appveyor.yml
src/tools/rustfmt/docs/index.html
src/tools/rustfmt/rust-toolchain
src/tools/rustfmt/src/attr.rs
src/tools/rustfmt/src/bin/main.rs
src/tools/rustfmt/src/cargo-fmt/main.rs
src/tools/rustfmt/src/cargo-fmt/test/message_format.rs [new file with mode: 0644]
src/tools/rustfmt/src/cargo-fmt/test/mod.rs [new file with mode: 0644]
src/tools/rustfmt/src/cargo-fmt/test/targets.rs [new file with mode: 0644]
src/tools/rustfmt/src/comment.rs
src/tools/rustfmt/src/config/mod.rs
src/tools/rustfmt/src/config/options.rs
src/tools/rustfmt/src/expr.rs
src/tools/rustfmt/src/formatting.rs
src/tools/rustfmt/src/formatting/generated.rs [new file with mode: 0644]
src/tools/rustfmt/src/imports.rs
src/tools/rustfmt/src/items.rs
src/tools/rustfmt/src/lists.rs
src/tools/rustfmt/src/matches.rs
src/tools/rustfmt/src/missed_spans.rs
src/tools/rustfmt/src/overflow.rs
src/tools/rustfmt/src/patterns.rs
src/tools/rustfmt/src/reorder.rs
src/tools/rustfmt/src/spanned.rs
src/tools/rustfmt/src/syntux/session.rs
src/tools/rustfmt/src/test/mod.rs
src/tools/rustfmt/src/types.rs
src/tools/rustfmt/src/visitor.rs
src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/Cargo.toml [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/dependency-dir-name/Cargo.toml [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/dependency-dir-name/src/lib.rs [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/dependency-dir-name/subdep-dir-name/Cargo.toml [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/dependency-dir-name/subdep-dir-name/src/lib.rs [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/src/main.rs [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/e/Cargo.toml [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/e/src/main.rs [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/Cargo.toml [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/Cargo.toml [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/d/Cargo.toml [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/d/f/Cargo.toml [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/d/f/src/lib.rs [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/d/src/lib.rs [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/src/main.rs [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/b/Cargo.toml [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/b/src/main.rs [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/c/Cargo.toml [new file with mode: 0644]
src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/c/src/lib.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/binop-separator-back/bitwise.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/binop-separator-back/comp.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/binop-separator-back/logic.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/binop-separator-back/math.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/binop-separator-back/patterns.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/binop-separator-back/range.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/configs/format_generated_files/false.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/configs/format_generated_files/true.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/hex_literal_lower.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/hex_literal_upper.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/impls.rs
src/tools/rustfmt/tests/source/imports_granularity_one.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-3158.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4530.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4615/minimum_example.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4816/lib.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4926/deeply_nested_struct.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4926/deeply_nested_struct_with_long_field_names.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4926/deeply_nested_struct_with_many_fields.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4926/enum_struct_field.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4926/minimum_example.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4926/struct_with_long_field_names.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4926/struct_with_many_fields.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4984/minimum_example.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4984/multi_line_derive.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-4984/multiple_comments_within.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue-5011.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue_4032.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue_4257.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue_4322.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue_4579.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue_4911.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue_4943.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue_4954.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/issue_4963.rs [new file with mode: 0644]
src/tools/rustfmt/tests/source/match-block-trailing-comma.rs
src/tools/rustfmt/tests/source/trait.rs
src/tools/rustfmt/tests/target/binop-separator-back/bitwise.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/binop-separator-back/comp.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/binop-separator-back/logic.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/binop-separator-back/math.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/binop-separator-back/patterns.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/binop-separator-back/range.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/configs/format_generated_files/false.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/configs/format_generated_files/true.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/hex_literal_lower.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/hex_literal_preserve.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/hex_literal_upper.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/impls.rs
src/tools/rustfmt/tests/target/imports_granularity_one.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-3158.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4530.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4615/minimum_example.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4816/lib.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4908-2.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4908.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4926/deeply_nested_struct.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4926/deeply_nested_struct_with_long_field_names.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4926/deeply_nested_struct_with_many_fields.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4926/enum_struct_field.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4926/minimum_example.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4926/struct_with_long_field_names.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4926/struct_with_many_fields.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4984/minimum_example.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4984/multi_line_derive.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4984/multiple_comments_within.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-4984/should_not_change.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-5005/minimum_example.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-5009/1_minimum_example.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-5009/2_many_in_connectors_in_pattern.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-5009/3_nested_for_loop_with_connector_in_pattern.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-5009/4_nested_for_loop_with_if_elseif_else.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-5009/5_nested_for_loop_with_connector_in_if_elseif_else.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-5009/6_deeply_nested_for_loop_with_connector_in_pattern.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue-5011.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_4031.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_4032.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_4110.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_4257.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_4322.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_4579.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_4911.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_4936.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_4943.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_4954.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/issue_4963.rs [new file with mode: 0644]
src/tools/rustfmt/tests/target/match-block-trailing-comma.rs
src/tools/rustfmt/tests/target/trait.rs
src/tools/rustfmt/triagebot.toml [new file with mode: 0644]
src/tools/tidy/src/edition.rs
src/tools/tidy/src/features.rs
src/tools/tidy/src/ui_tests.rs
src/version
triagebot.toml

index 78ff874e7550114f3919a77a108a9fd93514b788..407db519d51dc0631442037d06819c0df6937fac 100644 (file)
@@ -43,7 +43,7 @@ jobs:
           - name: mingw-check
             os: ubuntu-latest-xl
             env: {}
-          - name: x86_64-gnu-llvm-10
+          - name: x86_64-gnu-llvm-12
             os: ubuntu-latest-xl
             env: {}
           - name: x86_64-gnu-tools
@@ -92,9 +92,6 @@ jobs:
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
-      - name: select Xcode
-        run: src/ci/scripts/select-xcode.sh
-        if: success() && !env.SKIP_JOB
       - name: install clang
         run: src/ci/scripts/install-clang.sh
         if: success() && !env.SKIP_JOB
@@ -277,7 +274,7 @@ jobs:
           - name: x86_64-gnu-distcheck
             os: ubuntu-latest-xl
             env: {}
-          - name: x86_64-gnu-llvm-10
+          - name: x86_64-gnu-llvm-12
             env:
               RUST_BACKTRACE: 1
             os: ubuntu-latest-xl
@@ -290,12 +287,13 @@ jobs:
             os: ubuntu-latest-xl
           - name: dist-x86_64-apple
             env:
-              SCRIPT: "./x.py dist"
+              SCRIPT: "./x.py dist --exclude src/doc --exclude extended && ./x.py dist --target=x86_64-apple-darwin src/doc && ./x.py dist extended"
               RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.7
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
+              NO_OVERFLOW_CHECKS: 1
               DIST_REQUIRE_ALL_TOOLS: 1
             os: macos-latest
           - name: dist-x86_64-apple-alt
@@ -306,6 +304,7 @@ jobs:
               MACOSX_DEPLOYMENT_TARGET: 10.7
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
+              NO_OVERFLOW_CHECKS: 1
             os: macos-latest
           - name: x86_64-apple
             env:
@@ -316,18 +315,19 @@ jobs:
               MACOSX_STD_DEPLOYMENT_TARGET: 10.7
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
+              NO_OVERFLOW_CHECKS: 1
             os: macos-latest
           - 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"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              SELECT_XCODE: /Applications/Xcode_12.2.app
               USE_XCODE_CLANG: 1
               MACOSX_DEPLOYMENT_TARGET: 11.0
               MACOSX_STD_DEPLOYMENT_TARGET: 11.0
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
+              NO_OVERFLOW_CHECKS: 1
               DIST_REQUIRE_ALL_TOOLS: 1
               JEMALLOC_SYS_WITH_LG_PAGE: 14
             os: macos-latest
@@ -467,9 +467,6 @@ jobs:
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
-      - name: select Xcode
-        run: src/ci/scripts/select-xcode.sh
-        if: success() && !env.SKIP_JOB
       - name: install clang
         run: src/ci/scripts/install-clang.sh
         if: success() && !env.SKIP_JOB
@@ -580,9 +577,6 @@ jobs:
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
-      - name: select Xcode
-        run: src/ci/scripts/select-xcode.sh
-        if: success() && !env.SKIP_JOB
       - name: install clang
         run: src/ci/scripts/install-clang.sh
         if: success() && !env.SKIP_JOB
index 3b3e7334b759879790c962f2f977f4f3d5633db1..a160f2f4fbfecc2d97e69bc408987dacbb9a2157 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -111,6 +111,7 @@ Graydon Hoare <graydon@pobox.com> Graydon Hoare <graydon@mozilla.com>
 Guillaume Gomez <guillaume1.gomez@gmail.com>
 Guillaume Gomez <guillaume1.gomez@gmail.com> ggomez <ggomez@ggo.ifr.lan>
 Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <ggomez@ggo.ifr.lan>
+Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <guillaume.gomez@huawei.com>
 Hanna Kruppe <hanna.kruppe@gmail.com> <robin.kruppe@gmail.com>
 Heather <heather@cynede.net> <Cynede@Gentoo.org>
 Heather <heather@cynede.net> <Heather@cynede.net>
index 102450188aacd0366a3aaec98de67f77c0716f91..6f95dae42a4ab1a9edd126739aacfde5914fdcb8 100644 (file)
@@ -265,14 +265,23 @@ version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da"
 
+[[package]]
+name = "camino"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "cargo"
-version = "0.58.0"
+version = "0.59.0"
 dependencies = [
  "anyhow",
  "atty",
  "bytesize",
- "cargo-platform",
+ "cargo-platform 0.1.2",
  "cargo-test-macro",
  "cargo-test-support",
  "cargo-util",
@@ -374,6 +383,15 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "cargo-platform"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "cargo-test-macro"
 version = "0.1.0"
@@ -421,23 +439,24 @@ dependencies = [
 
 [[package]]
 name = "cargo_metadata"
-version = "0.8.2"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426"
+checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345"
 dependencies = [
- "semver 0.9.0",
+ "semver 0.11.0",
  "serde",
- "serde_derive",
  "serde_json",
 ]
 
 [[package]]
 name = "cargo_metadata"
-version = "0.12.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345"
+checksum = "c297bd3135f558552f99a0daa180876984ea2c4ffa7470314540dff8c654109a"
 dependencies = [
- "semver 0.11.0",
+ "camino",
+ "cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver 1.0.3",
  "serde",
  "serde_json",
 ]
@@ -555,9 +574,9 @@ dependencies = [
 
 [[package]]
 name = "clippy"
-version = "0.1.57"
+version = "0.1.58"
 dependencies = [
- "cargo_metadata 0.12.0",
+ "cargo_metadata 0.14.0",
  "clippy_lints",
  "clippy_utils",
  "compiletest_rs",
@@ -569,7 +588,7 @@ dependencies = [
  "regex",
  "rustc-workspace-hack",
  "rustc_tools_util 0.2.0",
- "semver 0.11.0",
+ "semver 1.0.3",
  "serde",
  "syn",
  "tempfile",
@@ -582,6 +601,7 @@ version = "0.0.1"
 dependencies = [
  "bytecount",
  "clap",
+ "indoc",
  "itertools 0.10.1",
  "opener",
  "regex",
@@ -591,9 +611,9 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.57"
+version = "0.1.58"
 dependencies = [
- "cargo_metadata 0.12.0",
+ "cargo_metadata 0.14.0",
  "clippy_utils",
  "if_chain",
  "itertools 0.10.1",
@@ -601,7 +621,7 @@ dependencies = [
  "quine-mc_cluskey",
  "regex-syntax",
  "rustc-semver",
- "semver 0.11.0",
+ "semver 1.0.3",
  "serde",
  "serde_json",
  "toml",
@@ -612,7 +632,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.57"
+version = "0.1.58"
 dependencies = [
  "if_chain",
  "rustc-semver",
@@ -690,9 +710,9 @@ dependencies = [
 
 [[package]]
 name = "compiletest_rs"
-version = "0.7.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64698e5e2435db061a85e6320af12c30c5fd88eb84b35d2c1e03ce4f143255ca"
+checksum = "29843cb8d351febf86557681d049d1e1652b81a086a190fa1173c07fd17fbf83"
 dependencies = [
  "diff",
  "filetime",
@@ -1069,9 +1089,9 @@ dependencies = [
 
 [[package]]
 name = "env_logger"
-version = "0.6.2"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
+checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
 dependencies = [
  "atty",
  "humantime 1.3.0",
@@ -1082,12 +1102,12 @@ dependencies = [
 
 [[package]]
 name = "env_logger"
-version = "0.7.1"
+version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
+checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
 dependencies = [
  "atty",
- "humantime 1.3.0",
+ "humantime 2.0.1",
  "log",
  "regex",
  "termcolor",
@@ -1665,6 +1685,15 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "indoc"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5a75aeaaef0ce18b58056d306c27b07436fbb34b8816c53094b76dd81803136"
+dependencies = [
+ "unindent",
+]
+
 [[package]]
 name = "installer"
 version = "0.0.0"
@@ -1688,15 +1717,6 @@ version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485"
 
-[[package]]
-name = "itertools"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
-dependencies = [
- "either",
-]
-
 [[package]]
 name = "itertools"
 version = "0.9.0"
@@ -1880,9 +1900,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
 [[package]]
 name = "libc"
-version = "0.2.103"
+version = "0.2.106"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
+checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -2143,6 +2163,20 @@ dependencies = [
  "smallvec",
 ]
 
+[[package]]
+name = "measureme"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd460fad6e55ca82fa0cd9dab0d315294188fd9ec6efbf4105e5635d4872ef9c"
+dependencies = [
+ "log",
+ "memmap2",
+ "parking_lot",
+ "perf-event-open-sys",
+ "rustc-hash",
+ "smallvec",
+]
+
 [[package]]
 name = "memchr"
 version = "2.4.1"
@@ -2247,7 +2281,7 @@ dependencies = [
  "hex 0.4.2",
  "libc",
  "log",
- "measureme",
+ "measureme 9.1.2",
  "rand 0.8.4",
  "rustc-workspace-hack",
  "rustc_version 0.4.0",
@@ -2315,9 +2349,9 @@ dependencies = [
 
 [[package]]
 name = "odht"
-version = "0.3.0"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2504d29fda40b3f2f9ef525392435ab660e407c188196cb664b116ebcca0142"
+checksum = "5a518809ac14b25b569624d0268eba1e88498f71615893dca57982bed7621abb"
 dependencies = [
  "cfg-if 1.0.0",
 ]
@@ -2728,9 +2762,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.24"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70"
 dependencies = [
  "unicode-xid",
 ]
@@ -3235,7 +3269,7 @@ dependencies = [
  "indexmap",
  "jobserver",
  "libc",
- "measureme",
+ "measureme 9.1.2",
  "memmap2",
  "parking_lot",
  "rustc-ap-rustc_graphviz",
@@ -3568,6 +3602,7 @@ dependencies = [
  "rustc_errors",
  "rustc_hir",
  "rustc_index",
+ "rustc_query_system",
  "rustc_session",
  "rustc_span",
  "rustc_target",
@@ -3673,7 +3708,7 @@ dependencies = [
  "bitflags",
  "cstr",
  "libc",
- "measureme",
+ "measureme 10.0.0",
  "rustc-demangle",
  "rustc_arena",
  "rustc_ast",
@@ -3766,7 +3801,7 @@ dependencies = [
  "indexmap",
  "jobserver",
  "libc",
- "measureme",
+ "measureme 10.0.0",
  "memmap2",
  "parking_lot",
  "rustc-hash",
@@ -4102,6 +4137,7 @@ dependencies = [
  "polonius-engine",
  "rand 0.8.4",
  "rand_xoshiro 0.6.0",
+ "rustc-rayon",
  "rustc-rayon-core",
  "rustc_apfloat",
  "rustc_arena",
@@ -4223,6 +4259,7 @@ dependencies = [
  "rustc_span",
  "tracing",
  "unicode-normalization",
+ "unicode-width",
 ]
 
 [[package]]
@@ -4290,7 +4327,7 @@ dependencies = [
 name = "rustc_query_impl"
 version = "0.0.0"
 dependencies = [
- "measureme",
+ "measureme 10.0.0",
  "rustc-rayon-core",
  "rustc_ast",
  "rustc_data_structures",
@@ -4303,7 +4340,6 @@ dependencies = [
  "rustc_serialize",
  "rustc_session",
  "rustc_span",
- "tracing",
 ]
 
 [[package]]
@@ -4346,6 +4382,7 @@ dependencies = [
  "rustc_index",
  "rustc_metadata",
  "rustc_middle",
+ "rustc_query_system",
  "rustc_session",
  "rustc_span",
  "smallvec",
@@ -4579,8 +4616,8 @@ dependencies = [
  "itertools 0.9.0",
  "minifier",
  "pulldown-cmark 0.8.0",
+ "rayon",
  "regex",
- "rustc-rayon",
  "rustdoc-json-types",
  "serde",
  "serde_json",
@@ -4647,19 +4684,19 @@ dependencies = [
 
 [[package]]
 name = "rustfmt-nightly"
-version = "1.4.37"
+version = "1.4.38"
 dependencies = [
  "annotate-snippets",
  "anyhow",
  "bytecount",
- "cargo_metadata 0.8.2",
+ "cargo_metadata 0.14.0",
  "derive-new",
  "diff",
  "dirs",
- "env_logger 0.6.2",
+ "env_logger 0.8.4",
  "getopts",
  "ignore",
- "itertools 0.8.2",
+ "itertools 0.9.0",
  "lazy_static",
  "log",
  "regex",
@@ -4742,23 +4779,13 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-dependencies = [
- "semver-parser 0.7.0",
- "serde",
-]
-
 [[package]]
 name = "semver"
 version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
 dependencies = [
- "semver-parser 0.10.2",
+ "semver-parser",
  "serde",
 ]
 
@@ -4771,12 +4798,6 @@ dependencies = [
  "serde",
 ]
 
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-
 [[package]]
 name = "semver-parser"
 version = "0.10.2"
@@ -5090,9 +5111,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.65"
+version = "1.0.80"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
+checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5577,6 +5598,12 @@ dependencies = [
  "diff",
 ]
 
+[[package]]
+name = "unindent"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
+
 [[package]]
 name = "unstable-book-gen"
 version = "0.1.0"
index 8d6afd2b4483773173d0f0c142af563225b09edb..cae48d795178388cbb4ee8487207a4d096fb7d55 100644 (file)
@@ -77,6 +77,13 @@ overflow-checks = false
 # per-crate configuration isn't specifiable in the environment.
 codegen-units = 10000
 
+[profile.release.package.rustc-rayon-core]
+# The rustc fork of Rayon has deadlock detection code which intermittently
+# causes overflows in the CI (see https://github.com/rust-lang/rust/issues/90227)
+# so we turn overflow checks off for now.
+# FIXME: This workaround should be removed once #90227 is fixed.
+overflow-checks = false
+
 # These dependencies of the standard library implement symbolication for
 # backtraces on most platforms. Their debuginfo causes both linking to be slower
 # (more data to chew through) and binaries to be larger without really all that
index 52d823d8acac48c035ac564f5cbbe0498375426d..a38ab7cabf468c39aace386fb49321579be2dc22 100644 (file)
@@ -1,3 +1,11 @@
+Version 1.56.1 (2021-11-01)
+===========================
+
+- New lints to detect the presence of bidirectional-override Unicode
+  codepoints in the compiled source code ([CVE-2021-42574])
+
+[CVE-2021-42574]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-42574
+
 Version 1.56.0 (2021-10-21)
 ========================
 
@@ -77,7 +85,7 @@ Cargo
 - [Cargo supports specifying a minimum supported Rust version in Cargo.toml.][`rust-version`]
   This has no effect at present on dependency version selection.
   We encourage crates to specify their minimum supported Rust version, and we encourage CI systems
-  that support Rust code to include a crate's specified minimum version in the text matrix for that
+  that support Rust code to include a crate's specified minimum version in the test matrix for that
   crate by default.
 
 Compatibility notes
index 739c6fd0a435f3eea5a58e2339885ea0d32cd719..96277950cfe1a0fbf9489172436ddc6c49f18480 100644 (file)
@@ -389,7 +389,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let _: Loss = sig::shift_right(&mut sig, &mut exp, trailing_zeros as usize);
 
         // Change the exponent from 2^e to 10^e.
-        #[allow(clippy::comparison_chain)]
         if exp == 0 {
             // Nothing to do.
         } else if exp > 0 {
@@ -2527,7 +2526,6 @@ pub(super) fn add_or_sub(
         if *a_sign ^ b_sign {
             let (reverse, loss);
 
-            #[allow(clippy::comparison_chain)]
             if bits == 0 {
                 reverse = cmp(a_sig, b_sig) == Ordering::Less;
                 loss = Loss::ExactlyZero;
index dd407dba1f4cca03b3e19bce687b40e49a3ead68..b2b90fed033b3f1192fc3e75f065a957d14b72e6 100644 (file)
@@ -1,6 +1,5 @@
 The `rustc_ast` crate contains those things concerned purely with syntax
-– that is, the AST ("abstract syntax tree"), parser, pretty-printer,
-lexer, macro expander, and utilities for traversing ASTs.
+– that is, the AST ("abstract syntax tree"), along with some definitions for tokens and token streams, data structures/traits for mutating ASTs, and shared definitions for other AST-related parts of the compiler (like the lexer and macro-expansion).
 
 For more information about how these things work in rustc, see the
 rustc dev guide:
index 5f17008bdc2b0747e118971443f2ca616f59d64c..927d7c6aaf6a4508549aa35a85790f6fa55ae5b3 100644 (file)
@@ -62,7 +62,7 @@ pub fn ident(&self) -> Option<Ident> {
         self.meta_item().and_then(|meta_item| meta_item.ident())
     }
     pub fn name_or_empty(&self) -> Symbol {
-        self.ident().unwrap_or_else(Ident::invalid).name
+        self.ident().unwrap_or_else(Ident::empty).name
     }
 
     /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
@@ -131,7 +131,7 @@ pub fn ident(&self) -> Option<Ident> {
         }
     }
     pub fn name_or_empty(&self) -> Symbol {
-        self.ident().unwrap_or_else(Ident::invalid).name
+        self.ident().unwrap_or_else(Ident::empty).name
     }
 
     pub fn value_str(&self) -> Option<Symbol> {
@@ -166,7 +166,7 @@ pub fn ident(&self) -> Option<Ident> {
         if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
     }
     pub fn name_or_empty(&self) -> Symbol {
-        self.ident().unwrap_or_else(Ident::invalid).name
+        self.ident().unwrap_or_else(Ident::empty).name
     }
 
     // Example:
index e3c610585d978e32c8ef8071aa0ffda993431310..2a165e700a6a310f02bdf61f441aa8da50e7b529 100644 (file)
@@ -1,4 +1,4 @@
-//! The Rust parser and macro expander.
+//! The Rust Abstract Syntax Tree (AST).
 //!
 //! # Note
 //!
index ba86036577ac5c1f5efb12102a19b13d783159f5..74def2bab1bfa2a58319e728f6765a2c9dc0f081 100644 (file)
@@ -37,9 +37,7 @@ pub trait MutVisitor: Sized {
     /// Mutable token visiting only exists for the `macro_rules` token marker and should not be
     /// used otherwise. Token visitor would be entirely separate from the regular visitor if
     /// the marker didn't have to visit AST fragments in nonterminal tokens.
-    fn token_visiting_enabled(&self) -> bool {
-        false
-    }
+    const VISIT_TOKENS: bool = false;
 
     // Methods in this trait have one of three forms:
     //
@@ -363,7 +361,7 @@ pub fn visit_mac_args<T: MutVisitor>(args: &mut MacArgs, vis: &mut T) {
         }
         MacArgs::Eq(eq_span, token) => {
             vis.visit_span(eq_span);
-            if vis.token_visiting_enabled() {
+            if T::VISIT_TOKENS {
                 visit_token(token, vis);
             } else {
                 // The value in `#[key = VALUE]` must be visited as an expression for backward
@@ -682,7 +680,7 @@ pub fn visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) {
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
 pub fn visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) {
-    if vis.token_visiting_enabled() && !tts.is_empty() {
+    if T::VISIT_TOKENS && !tts.is_empty() {
         let tts = Lrc::make_mut(tts);
         visit_vec(tts, |(tree, _is_joint)| visit_tt(tree, vis));
     }
@@ -692,14 +690,14 @@ pub fn visit_attr_annotated_tts<T: MutVisitor>(
     AttrAnnotatedTokenStream(tts): &mut AttrAnnotatedTokenStream,
     vis: &mut T,
 ) {
-    if vis.token_visiting_enabled() && !tts.is_empty() {
+    if T::VISIT_TOKENS && !tts.is_empty() {
         let tts = Lrc::make_mut(tts);
         visit_vec(tts, |(tree, _is_joint)| visit_attr_annotated_tt(tree, vis));
     }
 }
 
 pub fn visit_lazy_tts_opt_mut<T: MutVisitor>(lazy_tts: Option<&mut LazyTokenStream>, vis: &mut T) {
-    if vis.token_visiting_enabled() {
+    if T::VISIT_TOKENS {
         if let Some(lazy_tts) = lazy_tts {
             let mut tts = lazy_tts.create_token_stream();
             visit_attr_annotated_tts(&mut tts, vis);
@@ -1060,7 +1058,7 @@ pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
         let item_vis =
             Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None };
         let item = P(Item {
-            ident: Ident::invalid(),
+            ident: Ident::empty(),
             attrs,
             id: DUMMY_NODE_ID,
             vis: item_vis,
index 5d994dbad4d1fcf128851668679a54ced7f92e41..51cabb50cd3de7280a1ddfd8cff2caaeabb1e3c6 100644 (file)
@@ -221,12 +221,6 @@ pub fn to_tokenstream(&self) -> TokenStream {
                     for attr in &data.attrs {
                         match attr.style {
                             crate::AttrStyle::Outer => {
-                                assert!(
-                                    inner_attrs.len() == 0,
-                                    "Found outer attribute {:?} after inner attrs {:?}",
-                                    attr,
-                                    inner_attrs
-                                );
                                 outer_attrs.push(attr);
                             }
                             crate::AttrStyle::Inner => {
index 078dd4bd6e60232ed7a118db39e4601d04faa702..500c97e65ef9cc868611037369912944f783430a 100644 (file)
@@ -357,13 +357,13 @@ pub fn order(self) -> i8 {
     }
 }
 
-/// In `let p = e`, operators with precedence `<=` this one requires parenthesis in `e`.
+/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
 pub fn prec_let_scrutinee_needs_par() -> usize {
     AssocOp::LAnd.precedence()
 }
 
 /// Suppose we have `let _ = e` and the `order` of `e`.
-/// Is the `order` such that `e` in `let _ = e` needs parenthesis when it is on the RHS?
+/// Is the `order` such that `e` in `let _ = e` needs parentheses when it is on the RHS?
 ///
 /// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
 /// Can we print this as `let _ = a OP b`?
index f4859ee4ae91f48133fe8684de01436d86dcb416..7989af24d9986107290d3fa9b6ad0d75adb73a7d 100644 (file)
@@ -14,6 +14,7 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_target = { path = "../rustc_target" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_index = { path = "../rustc_index" }
+rustc_query_system = { path = "../rustc_query_system" }
 rustc_span = { path = "../rustc_span" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_session = { path = "../rustc_session" }
index 957b14f34872962eef8455fcbf1bc5ffa712993d..d0da88f1cc095163e82ebef41dd2df9a95eea2e3 100644 (file)
@@ -11,8 +11,8 @@
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
     crate fn lower_inline_asm(&mut self, sp: Span, asm: &InlineAsm) -> &'hir hir::InlineAsm<'hir> {
-        // Rustdoc needs to support asm! from foriegn architectures: don't try
-        // lowering the register contraints in this case.
+        // Rustdoc needs to support asm! from foreign architectures: don't try
+        // lowering the register constraints in this case.
         let asm_arch = if self.sess.opts.actually_rustdoc { None } else { self.sess.asm_arch };
         if asm_arch.is_none() && !self.sess.opts.actually_rustdoc {
             struct_span_err!(self.sess, sp, E0472, "inline assembly is unsupported on this target")
@@ -214,9 +214,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 // means that we disallow passing a value in/out of the asm and
                 // require that the operand name an explicit register, not a
                 // register class.
-                if reg_class.is_clobber_only(asm_arch.unwrap())
-                    && !(op.is_clobber() && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_)))
-                {
+                if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() {
                     let msg = format!(
                         "register class `{}` can only be used as a clobber, \
                              not as an input or output",
index 6027027428eeecbbab7d293feaf6656727fa9071..405e9035c4c1922f392a6b6502ff7d36d6cec885 100644 (file)
@@ -252,9 +252,10 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                     }
                     // Merge attributes into the inner expression.
                     if !e.attrs.is_empty() {
-                        let old_attrs = self.attrs.get(&ex.hir_id).map(|la| *la).unwrap_or(&[]);
+                        let old_attrs =
+                            self.attrs.get(&ex.hir_id.local_id).map(|la| *la).unwrap_or(&[]);
                         self.attrs.insert(
-                            ex.hir_id,
+                            ex.hir_id.local_id,
                             &*self.arena.alloc_from_iter(
                                 e.attrs
                                     .iter()
@@ -1331,15 +1332,11 @@ fn lower_expr_for(
         body: &Block,
         opt_label: Option<Label>,
     ) -> hir::Expr<'hir> {
-        let orig_head_span = head.span;
         // expand <head>
-        let mut head = self.lower_expr_mut(head);
-        let desugared_span = self.mark_span_with_reason(
-            DesugaringKind::ForLoop(ForLoopLoc::Head),
-            orig_head_span,
-            None,
-        );
-        head.span = self.lower_span(desugared_span);
+        let head = self.lower_expr_mut(head);
+        let desugared_span =
+            self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), head.span, None);
+        let e_span = self.lower_span(e.span);
 
         let iter = Ident::with_dummy_span(sym::iter);
 
@@ -1353,23 +1350,24 @@ fn lower_expr_for(
         // `::std::option::Option::Some(val) => __next = val`
         let pat_arm = {
             let val_ident = Ident::with_dummy_span(sym::val);
-            let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
-            let val_expr = self.expr_ident(pat.span, val_ident, val_pat_hid);
-            let next_expr = self.expr_ident(pat.span, next_ident, next_pat_hid);
+            let pat_span = self.lower_span(pat.span);
+            let (val_pat, val_pat_hid) = self.pat_ident(pat_span, val_ident);
+            let val_expr = self.expr_ident(pat_span, val_ident, val_pat_hid);
+            let next_expr = self.expr_ident(pat_span, next_ident, next_pat_hid);
             let assign = self.arena.alloc(self.expr(
-                pat.span,
-                hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat.span)),
+                pat_span,
+                hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat_span)),
                 ThinVec::new(),
             ));
-            let some_pat = self.pat_some(pat.span, val_pat);
+            let some_pat = self.pat_some(pat_span, val_pat);
             self.arm(some_pat, assign)
         };
 
         // `::std::option::Option::None => break`
         let break_arm = {
             let break_expr =
-                self.with_loop_scope(e.id, |this| this.expr_break_alloc(e.span, ThinVec::new()));
-            let pat = self.pat_none(e.span);
+                self.with_loop_scope(e.id, |this| this.expr_break_alloc(e_span, ThinVec::new()));
+            let pat = self.pat_none(e_span);
             self.arm(pat, break_expr)
         };
 
@@ -1415,10 +1413,10 @@ fn lower_expr_for(
 
         let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
         let body_expr = self.expr_block(body_block, ThinVec::new());
-        let body_stmt = self.stmt_expr(body.span, body_expr);
+        let body_stmt = self.stmt_expr(body_block.span, body_expr);
 
         let loop_block = self.block_all(
-            e.span,
+            e_span,
             arena_vec![self; next_let, match_stmt, pat_let, body_stmt],
             None,
         );
@@ -1428,7 +1426,7 @@ fn lower_expr_for(
             loop_block,
             self.lower_label(opt_label),
             hir::LoopSource::ForLoop,
-            self.lower_span(e.span.with_hi(orig_head_span.hi())),
+            self.lower_span(e_span.with_hi(head.span.hi())),
         );
         let loop_expr = self.arena.alloc(hir::Expr {
             hir_id: self.lower_node_id(e.id),
@@ -1441,7 +1439,7 @@ fn lower_expr_for(
 
         let into_iter_span = self.mark_span_with_reason(
             DesugaringKind::ForLoop(ForLoopLoc::IntoIter),
-            orig_head_span,
+            head.span,
             None,
         );
 
@@ -1457,7 +1455,7 @@ fn lower_expr_for(
         // #82462: to correctly diagnose borrow errors, the block that contains
         // the iter expr needs to have a span that covers the loop body.
         let desugared_full_span =
-            self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e.span, None);
+            self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e_span, None);
 
         let match_expr = self.arena.alloc(self.expr_match(
             desugared_full_span,
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
new file mode 100644 (file)
index 0000000..8a9dad2
--- /dev/null
@@ -0,0 +1,350 @@
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sorted_map::SortedMap;
+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::*;
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_session::Session;
+use rustc_span::source_map::SourceMap;
+use rustc_span::{Span, DUMMY_SP};
+
+use tracing::debug;
+
+/// A visitor that walks over the HIR and collects `Node`s into a HIR map.
+pub(super) struct NodeCollector<'a, 'hir> {
+    /// Source map
+    source_map: &'a SourceMap,
+    bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>,
+
+    /// Outputs
+    nodes: IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>,
+    parenting: FxHashMap<LocalDefId, ItemLocalId>,
+
+    /// The parent of this node
+    parent_node: hir::ItemLocalId,
+
+    owner: LocalDefId,
+
+    definitions: &'a definitions::Definitions,
+}
+
+pub(super) fn index_hir<'hir>(
+    sess: &Session,
+    definitions: &definitions::Definitions,
+    item: hir::OwnerNode<'hir>,
+    bodies: &SortedMap<ItemLocalId, &'hir Body<'hir>>,
+) -> (IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>, FxHashMap<LocalDefId, ItemLocalId>) {
+    let mut nodes = IndexVec::new();
+    // This node's parent should never be accessed: the owner's parent is computed by the
+    // hir_owner_parent query.  Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is
+    // used.
+    nodes.push(Some(ParentedNode { parent: ItemLocalId::INVALID, node: item.into() }));
+    let mut collector = NodeCollector {
+        source_map: sess.source_map(),
+        definitions,
+        owner: item.def_id(),
+        parent_node: ItemLocalId::new(0),
+        nodes,
+        bodies,
+        parenting: FxHashMap::default(),
+    };
+
+    match item {
+        OwnerNode::Crate(citem) => collector.visit_mod(&citem, citem.inner, hir::CRATE_HIR_ID),
+        OwnerNode::Item(item) => collector.visit_item(item),
+        OwnerNode::TraitItem(item) => collector.visit_trait_item(item),
+        OwnerNode::ImplItem(item) => collector.visit_impl_item(item),
+        OwnerNode::ForeignItem(item) => collector.visit_foreign_item(item),
+    };
+
+    (collector.nodes, collector.parenting)
+}
+
+impl<'a, 'hir> NodeCollector<'a, 'hir> {
+    fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
+        debug_assert_eq!(self.owner, hir_id.owner);
+        debug_assert_ne!(hir_id.local_id.as_u32(), 0);
+
+        // Make sure that the DepNode of some node coincides with the HirId
+        // owner of that node.
+        if cfg!(debug_assertions) {
+            if hir_id.owner != self.owner {
+                panic!(
+                    "inconsistent DepNode at `{:?}` for `{:?}`: \
+                     current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
+                    self.source_map.span_to_diagnostic_string(span),
+                    node,
+                    self.definitions.def_path(self.owner).to_string_no_crate_verbose(),
+                    self.owner,
+                    self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(),
+                    hir_id.owner,
+                )
+            }
+        }
+
+        self.nodes.insert(hir_id.local_id, ParentedNode { parent: self.parent_node, node: node });
+    }
+
+    fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) {
+        debug_assert_eq!(parent_node_id.owner, self.owner);
+        let parent_node = self.parent_node;
+        self.parent_node = parent_node_id.local_id;
+        f(self);
+        self.parent_node = parent_node;
+    }
+
+    fn insert_nested(&mut self, item: LocalDefId) {
+        self.parenting.insert(item, self.parent_node);
+    }
+}
+
+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);
+    }
+
+    fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
+        self.insert_nested(item_id.def_id);
+    }
+
+    fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
+        self.insert_nested(item_id.def_id);
+    }
+
+    fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
+        self.insert_nested(foreign_id.def_id);
+    }
+
+    fn visit_nested_body(&mut self, id: BodyId) {
+        debug_assert_eq!(id.hir_id.owner, self.owner);
+        let body = self.bodies[&id.hir_id.local_id];
+        self.visit_body(body);
+    }
+
+    fn visit_param(&mut self, param: &'hir Param<'hir>) {
+        let node = Node::Param(param);
+        self.insert(param.pat.span, param.hir_id, node);
+        self.with_parent(param.hir_id, |this| {
+            intravisit::walk_param(this, param);
+        });
+    }
+
+    fn visit_item(&mut self, i: &'hir Item<'hir>) {
+        debug!("visit_item: {:?}", i);
+        debug_assert_eq!(i.def_id, self.owner);
+        self.with_parent(i.hir_id(), |this| {
+            if let ItemKind::Struct(ref struct_def, _) = i.kind {
+                // If this is a tuple or unit-like struct, register the constructor.
+                if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
+                    this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
+                }
+            }
+            intravisit::walk_item(this, i);
+        });
+    }
+
+    fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
+        debug_assert_eq!(fi.def_id, self.owner);
+        self.with_parent(fi.hir_id(), |this| {
+            intravisit::walk_foreign_item(this, fi);
+        });
+    }
+
+    fn visit_generic_param(&mut self, param: &'hir GenericParam<'hir>) {
+        self.insert(param.span, param.hir_id, Node::GenericParam(param));
+        intravisit::walk_generic_param(self, param);
+    }
+
+    fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) {
+        self.with_parent(param, |this| {
+            intravisit::walk_const_param_default(this, ct);
+        })
+    }
+
+    fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
+        debug_assert_eq!(ti.def_id, self.owner);
+        self.with_parent(ti.hir_id(), |this| {
+            intravisit::walk_trait_item(this, ti);
+        });
+    }
+
+    fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
+        debug_assert_eq!(ii.def_id, self.owner);
+        self.with_parent(ii.hir_id(), |this| {
+            intravisit::walk_impl_item(this, ii);
+        });
+    }
+
+    fn visit_pat(&mut self, pat: &'hir Pat<'hir>) {
+        let node =
+            if let PatKind::Binding(..) = pat.kind { Node::Binding(pat) } else { Node::Pat(pat) };
+        self.insert(pat.span, pat.hir_id, node);
+
+        self.with_parent(pat.hir_id, |this| {
+            intravisit::walk_pat(this, pat);
+        });
+    }
+
+    fn visit_arm(&mut self, arm: &'hir Arm<'hir>) {
+        let node = Node::Arm(arm);
+
+        self.insert(arm.span, arm.hir_id, node);
+
+        self.with_parent(arm.hir_id, |this| {
+            intravisit::walk_arm(this, arm);
+        });
+    }
+
+    fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
+        self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant));
+
+        self.with_parent(constant.hir_id, |this| {
+            intravisit::walk_anon_const(this, constant);
+        });
+    }
+
+    fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
+        self.insert(expr.span, expr.hir_id, Node::Expr(expr));
+
+        self.with_parent(expr.hir_id, |this| {
+            intravisit::walk_expr(this, expr);
+        });
+    }
+
+    fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) {
+        self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt));
+
+        self.with_parent(stmt.hir_id, |this| {
+            intravisit::walk_stmt(this, stmt);
+        });
+    }
+
+    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment<'hir>) {
+        if let Some(hir_id) = path_segment.hir_id {
+            self.insert(path_span, hir_id, Node::PathSegment(path_segment));
+        }
+        intravisit::walk_path_segment(self, path_span, path_segment);
+    }
+
+    fn visit_ty(&mut self, ty: &'hir Ty<'hir>) {
+        self.insert(ty.span, ty.hir_id, Node::Ty(ty));
+
+        self.with_parent(ty.hir_id, |this| {
+            intravisit::walk_ty(this, ty);
+        });
+    }
+
+    fn visit_infer(&mut self, inf: &'hir InferArg) {
+        self.insert(inf.span, inf.hir_id, Node::Infer(inf));
+
+        self.with_parent(inf.hir_id, |this| {
+            intravisit::walk_inf(this, inf);
+        });
+    }
+
+    fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) {
+        self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr));
+
+        self.with_parent(tr.hir_ref_id, |this| {
+            intravisit::walk_trait_ref(this, tr);
+        });
+    }
+
+    fn visit_fn(
+        &mut self,
+        fk: intravisit::FnKind<'hir>,
+        fd: &'hir FnDecl<'hir>,
+        b: BodyId,
+        s: Span,
+        id: HirId,
+    ) {
+        assert_eq!(self.owner, id.owner);
+        assert_eq!(self.parent_node, id.local_id);
+        intravisit::walk_fn(self, fk, fd, b, s, id);
+    }
+
+    fn visit_block(&mut self, block: &'hir Block<'hir>) {
+        self.insert(block.span, block.hir_id, Node::Block(block));
+        self.with_parent(block.hir_id, |this| {
+            intravisit::walk_block(this, block);
+        });
+    }
+
+    fn visit_local(&mut self, l: &'hir Local<'hir>) {
+        self.insert(l.span, l.hir_id, Node::Local(l));
+        self.with_parent(l.hir_id, |this| {
+            intravisit::walk_local(this, l);
+        })
+    }
+
+    fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) {
+        self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime));
+    }
+
+    fn visit_vis(&mut self, visibility: &'hir Visibility<'hir>) {
+        match visibility.node {
+            VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {}
+            VisibilityKind::Restricted { hir_id, .. } => {
+                self.insert(visibility.span, hir_id, Node::Visibility(visibility));
+                self.with_parent(hir_id, |this| {
+                    intravisit::walk_vis(this, visibility);
+                });
+            }
+        }
+    }
+
+    fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) {
+        self.insert(v.span, v.id, Node::Variant(v));
+        self.with_parent(v.id, |this| {
+            // Register the constructor of this variant.
+            if let Some(ctor_hir_id) = v.data.ctor_hir_id() {
+                this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data));
+            }
+            intravisit::walk_variant(this, v, g, item_id);
+        });
+    }
+
+    fn visit_field_def(&mut self, field: &'hir FieldDef<'hir>) {
+        self.insert(field.span, field.hir_id, Node::Field(field));
+        self.with_parent(field.hir_id, |this| {
+            intravisit::walk_field_def(this, field);
+        });
+    }
+
+    fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
+        // Do not visit the duplicate information in TraitItemRef. We want to
+        // map the actual nodes, not the duplicate ones in the *Ref.
+        let TraitItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
+
+        self.visit_nested_trait_item(id);
+    }
+
+    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;
+
+        self.visit_nested_impl_item(id);
+    }
+
+    fn visit_foreign_item_ref(&mut self, fi: &'hir ForeignItemRef) {
+        // Do not visit the duplicate information in ForeignItemRef. We want to
+        // map the actual nodes, not the duplicate ones in the *Ref.
+        let ForeignItemRef { id, ident: _, span: _ } = *fi;
+
+        self.visit_nested_foreign_item(id);
+    }
+}
index a5a4de81f12f68aaeef6a361df30705fb53365f4..63b20cd320b37b60ef04f67f0acd4b81f1c79625 100644 (file)
@@ -10,6 +10,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::LocalDefId;
+use rustc_index::vec::Idx;
 use rustc_span::source_map::{respan, DesugaringKind};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
@@ -99,11 +100,12 @@ fn with_parent_item_lifetime_defs<T>(
     ) -> T {
         let old_len = self.in_scope_lifetimes.len();
 
-        let parent_generics = match self.owners[parent_hir_id].unwrap().expect_item().kind {
-            hir::ItemKind::Impl(hir::Impl { ref generics, .. })
-            | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
-            _ => &[],
-        };
+        let parent_generics =
+            match self.owners[parent_hir_id].as_ref().unwrap().node().expect_item().kind {
+                hir::ItemKind::Impl(hir::Impl { ref generics, .. })
+                | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
+                _ => &[],
+            };
         let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind {
             hir::GenericParamKind::Lifetime { .. } => Some(param.name.normalize_to_macros_2_0()),
             _ => None,
@@ -493,7 +495,7 @@ fn lower_use_tree(
                         let kind = hir::ItemKind::Use(path, hir::UseKind::Single);
                         let vis = this.rebuild_vis(&vis);
                         if let Some(attrs) = attrs {
-                            this.attrs.insert(hir::HirId::make_owner(new_id), attrs);
+                            this.attrs.insert(hir::ItemLocalId::new(0), attrs);
                         }
 
                         let item = hir::Item {
@@ -568,7 +570,7 @@ fn lower_use_tree(
                         let kind =
                             this.lower_use_tree(use_tree, &prefix, id, &mut vis, &mut ident, attrs);
                         if let Some(attrs) = attrs {
-                            this.attrs.insert(hir::HirId::make_owner(new_hir_id), attrs);
+                            this.attrs.insert(hir::ItemLocalId::new(0), attrs);
                         }
 
                         let item = hir::Item {
@@ -971,7 +973,8 @@ fn record_body(
     ) -> hir::BodyId {
         let body = hir::Body { generator_kind: self.generator_kind, params, value };
         let id = body.id();
-        self.bodies.insert(id, body);
+        debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
+        self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
         id
     }
 
@@ -1124,7 +1127,7 @@ fn lower_maybe_async_body(
                 //
                 // If this is the simple case, this parameter will end up being the same as the
                 // original parameter, but with a different pattern id.
-                let stmt_attrs = this.attrs.get(&parameter.hir_id).copied();
+                let stmt_attrs = this.attrs.get(&parameter.hir_id.local_id).copied();
                 let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident);
                 let new_parameter = hir::Param {
                     hir_id: parameter.hir_id,
index 245199e37511380a0e1220e6e2f9f54cc46af10f..79464a751721751ddfcce69776513184901395dd 100644 (file)
 #![feature(crate_visibility_modifier)]
 #![feature(box_patterns)]
 #![feature(iter_zip)]
+#![feature(never_type)]
 #![recursion_limit = "256"]
 
-use rustc_ast::node_id::NodeMap;
 use rustc_ast::token::{self, Token};
 use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
 use rustc_ast::visit;
 use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fingerprint::Fingerprint;
+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::sync::Lrc;
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::intravisit;
 use rustc_hir::{ConstArg, GenericArg, InferKind, ParamName};
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_query_system::ich::StableHashingContext;
 use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
 use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::ExpnId;
-use rustc_span::source_map::{respan, CachingSourceMapView, DesugaringKind};
+use rustc_span::source_map::{respan, DesugaringKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
 use smallvec::SmallVec;
-use std::collections::BTreeMap;
 use tracing::{debug, trace};
 
 macro_rules! arena_vec {
@@ -76,6 +79,7 @@ macro_rules! arena_vec {
 mod asm;
 mod block;
 mod expr;
+mod index;
 mod item;
 mod pat;
 mod path;
@@ -97,13 +101,14 @@ struct LoweringContext<'a, 'hir: 'a> {
     arena: &'hir Arena<'hir>,
 
     /// The items being lowered are collected here.
-    owners: IndexVec<LocalDefId, Option<hir::OwnerNode<'hir>>>,
-    bodies: BTreeMap<hir::BodyId, hir::Body<'hir>>,
+    owners: IndexVec<LocalDefId, Option<hir::OwnerInfo<'hir>>>,
+    /// Bodies inside the owner being lowered.
+    bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
+    /// Attributes inside the owner being lowered.
+    attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
 
     generator_kind: Option<hir::GeneratorKind>,
 
-    attrs: BTreeMap<hir::HirId, &'hir [Attribute]>,
-
     /// When inside an `async` context, this is the `HirId` of the
     /// `task_context` local bound to the resume argument of the generator.
     task_context: Option<hir::HirId>,
@@ -152,6 +157,9 @@ struct LoweringContext<'a, 'hir: 'a> {
     item_local_id_counter: hir::ItemLocalId,
     node_id_to_hir_id: IndexVec<NodeId, Option<hir::HirId>>,
 
+    /// NodeIds that are lowered inside the current HIR owner.
+    local_node_ids: Vec<NodeId>,
+
     allow_try_trait: Option<Lrc<[Symbol]>>,
     allow_gen_future: Option<Lrc<[Symbol]>>,
 }
@@ -178,11 +186,13 @@ pub trait ResolverAstLowering {
     /// This should only return `None` during testing.
     fn definitions(&mut self) -> &mut Definitions;
 
+    fn create_stable_hashing_context(&self) -> StableHashingContext<'_>;
+
     fn lint_buffer(&mut self) -> &mut LintBuffer;
 
     fn next_node_id(&mut self) -> NodeId;
 
-    fn take_trait_map(&mut self) -> NodeMap<Vec<hir::TraitCandidate>>;
+    fn take_trait_map(&mut self, node: NodeId) -> Option<Vec<hir::TraitCandidate>>;
 
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>;
 
@@ -200,37 +210,6 @@ fn create_def(
     ) -> LocalDefId;
 }
 
-struct LoweringHasher<'a> {
-    source_map: CachingSourceMapView<'a>,
-    resolver: &'a dyn ResolverAstLowering,
-}
-
-impl<'a> rustc_span::HashStableContext for LoweringHasher<'a> {
-    #[inline]
-    fn hash_spans(&self) -> bool {
-        true
-    }
-
-    #[inline]
-    fn def_span(&self, id: LocalDefId) -> Span {
-        self.resolver.def_span(id)
-    }
-
-    #[inline]
-    fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
-        self.resolver.def_path_hash(def_id)
-    }
-
-    #[inline]
-    fn span_data_to_lines_and_cols(
-        &mut self,
-        span: &rustc_span::SpanData,
-    ) -> Option<(Lrc<rustc_span::SourceFile>, usize, rustc_span::BytePos, usize, rustc_span::BytePos)>
-    {
-        self.source_map.span_data_to_lines_and_cols(span)
-    }
-}
-
 /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
 /// and if so, what meaning it has.
 #[derive(Debug)]
@@ -314,14 +293,15 @@ pub fn lower_crate<'a, 'hir>(
 ) -> &'hir hir::Crate<'hir> {
     let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
 
+    let owners = IndexVec::from_fn_n(|_| None, resolver.definitions().def_index_count());
     LoweringContext {
         sess,
         resolver,
         nt_to_tokenstream,
         arena,
-        owners: IndexVec::default(),
-        bodies: BTreeMap::new(),
-        attrs: BTreeMap::default(),
+        owners,
+        bodies: Vec::new(),
+        attrs: SortedMap::new(),
         catch_scope: None,
         loop_scope: None,
         is_in_loop_condition: false,
@@ -331,6 +311,7 @@ pub fn lower_crate<'a, 'hir>(
         current_hir_id_owner: CRATE_DEF_ID,
         item_local_id_counter: hir::ItemLocalId::new(0),
         node_id_to_hir_id: IndexVec::new(),
+        local_node_ids: Vec::new(),
         generator_kind: None,
         task_context: None,
         current_item: None,
@@ -420,13 +401,7 @@ fn lower_crate(mut self, c: &Crate) -> &'hir hir::Crate<'hir> {
             hir::OwnerNode::Crate(lctx.arena.alloc(module))
         });
 
-        let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
-        for (k, v) in self.resolver.take_trait_map().into_iter() {
-            if let Some(Some(hir_id)) = self.node_id_to_hir_id.get(k) {
-                let map = trait_map.entry(hir_id.owner).or_default();
-                map.insert(hir_id.local_id, v.into_boxed_slice());
-            }
-        }
+        let hir_hash = self.compute_hir_hash();
 
         let mut def_id_to_hir_id = IndexVec::default();
 
@@ -441,24 +416,29 @@ fn lower_crate(mut self, c: &Crate) -> &'hir hir::Crate<'hir> {
 
         self.resolver.definitions().init_def_id_to_hir_id_mapping(def_id_to_hir_id);
 
-        #[cfg(debug_assertions)]
-        for (&id, attrs) in self.attrs.iter() {
-            // Verify that we do not store empty slices in the map.
-            if attrs.is_empty() {
-                panic!("Stored empty attributes for {:?}", id);
-            }
-        }
-
-        let krate =
-            hir::Crate { owners: self.owners, bodies: self.bodies, trait_map, attrs: self.attrs };
+        let krate = hir::Crate { owners: self.owners, hir_hash };
         self.arena.alloc(krate)
     }
 
-    fn create_stable_hashing_context(&self) -> LoweringHasher<'_> {
-        LoweringHasher {
-            source_map: CachingSourceMapView::new(self.sess.source_map()),
-            resolver: self.resolver,
-        }
+    /// Compute the hash for the HIR of the full crate.
+    /// This hash will then be part of the crate_hash which is stored in the metadata.
+    fn compute_hir_hash(&mut self) -> Fingerprint {
+        let definitions = self.resolver.definitions();
+        let mut hir_body_nodes: Vec<_> = self
+            .owners
+            .iter_enumerated()
+            .filter_map(|(def_id, info)| {
+                let info = info.as_ref()?;
+                let def_path_hash = definitions.def_path_hash(def_id);
+                Some((def_path_hash, info))
+            })
+            .collect();
+        hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
+
+        let mut stable_hasher = StableHasher::new();
+        let mut hcx = self.resolver.create_stable_hashing_context();
+        hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher);
+        stable_hasher.finish()
     }
 
     fn with_hir_id_owner(
@@ -468,25 +448,93 @@ fn with_hir_id_owner(
     ) -> LocalDefId {
         let def_id = self.resolver.local_def_id(owner);
 
-        // Always allocate the first `HirId` for the owner itself.
-        let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id));
-        debug_assert_eq!(_old, None);
-
+        let current_attrs = std::mem::take(&mut self.attrs);
+        let current_bodies = std::mem::take(&mut self.bodies);
+        let current_node_ids = std::mem::take(&mut self.local_node_ids);
         let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id);
         let current_local_counter =
             std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
 
+        // Always allocate the first `HirId` for the owner itself.
+        let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id));
+        debug_assert_eq!(_old, None);
+        self.local_node_ids.push(owner);
+
         let item = f(self);
+        debug_assert_eq!(def_id, item.def_id());
+        let info = self.make_owner_info(item);
 
+        self.attrs = current_attrs;
+        self.bodies = current_bodies;
+        self.local_node_ids = current_node_ids;
         self.current_hir_id_owner = current_owner;
         self.item_local_id_counter = current_local_counter;
 
-        let _old = self.owners.insert(def_id, item);
+        let _old = self.owners.insert(def_id, info);
         debug_assert!(_old.is_none());
 
         def_id
     }
 
+    fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir> {
+        let attrs = std::mem::take(&mut self.attrs);
+        let mut bodies = std::mem::take(&mut self.bodies);
+        let local_node_ids = std::mem::take(&mut self.local_node_ids);
+        let trait_map = local_node_ids
+            .into_iter()
+            .filter_map(|node_id| {
+                let hir_id = self.node_id_to_hir_id[node_id]?;
+                let traits = self.resolver.take_trait_map(node_id)?;
+                Some((hir_id.local_id, traits.into_boxed_slice()))
+            })
+            .collect();
+
+        #[cfg(debug_assertions)]
+        for (id, attrs) in attrs.iter() {
+            // Verify that we do not store empty slices in the map.
+            if attrs.is_empty() {
+                panic!("Stored empty attributes for {:?}", id);
+            }
+        }
+
+        bodies.sort_by_key(|(k, _)| *k);
+        let bodies = SortedMap::from_presorted_elements(bodies);
+        let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies);
+        let (nodes, parenting) =
+            index::index_hir(self.sess, self.resolver.definitions(), node, &bodies);
+        let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, nodes, bodies };
+        let attrs = {
+            let mut hcx = self.resolver.create_stable_hashing_context();
+            let mut stable_hasher = StableHasher::new();
+            attrs.hash_stable(&mut hcx, &mut stable_hasher);
+            let hash = stable_hasher.finish();
+            hir::AttributeMap { map: attrs, hash }
+        };
+
+        hir::OwnerInfo { nodes, parenting, attrs, trait_map }
+    }
+
+    /// Hash the HIR node twice, one deep and one shallow hash.  This allows to differentiate
+    /// queries which depend on the full HIR tree and those which only depend on the item signature.
+    fn hash_owner(
+        &mut self,
+        node: hir::OwnerNode<'hir>,
+        bodies: &SortedMap<hir::ItemLocalId, &'hir hir::Body<'hir>>,
+    ) -> (Fingerprint, Fingerprint) {
+        let mut hcx = self.resolver.create_stable_hashing_context();
+        let mut stable_hasher = StableHasher::new();
+        hcx.with_hir_bodies(true, node.def_id(), bodies, |hcx| {
+            node.hash_stable(hcx, &mut stable_hasher)
+        });
+        let hash_including_bodies = stable_hasher.finish();
+        let mut stable_hasher = StableHasher::new();
+        hcx.with_hir_bodies(false, node.def_id(), bodies, |hcx| {
+            node.hash_stable(hcx, &mut stable_hasher)
+        });
+        let hash_without_bodies = stable_hasher.finish();
+        (hash_including_bodies, hash_without_bodies)
+    }
+
     /// This method allocates a new `HirId` for the given `NodeId` and stores it in
     /// the `LoweringContext`'s `NodeId => HirId` map.
     /// Take care not to call this method if the resulting `HirId` is then not
@@ -501,6 +549,7 @@ fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
             let owner = self.current_hir_id_owner;
             let local_id = self.item_local_id_counter;
             self.item_local_id_counter.increment_by(1);
+            self.local_node_ids.push(ast_node_id);
             hir::HirId { owner, local_id }
         })
     }
@@ -547,7 +596,7 @@ fn mark_span_with_reason(
             allow_internal_unstable,
             reason,
             self.sess.edition(),
-            self.create_stable_hashing_context(),
+            self.resolver.create_stable_hashing_context(),
         )
     }
 
@@ -791,9 +840,10 @@ fn lower_attrs(&mut self, id: hir::HirId, attrs: &[Attribute]) -> Option<&'hir [
         if attrs.is_empty() {
             None
         } else {
+            debug_assert_eq!(id.owner, self.current_hir_id_owner);
             let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a)));
             debug_assert!(!ret.is_empty());
-            self.attrs.insert(id, ret);
+            self.attrs.insert(id.local_id, ret);
             Some(ret)
         }
     }
@@ -819,9 +869,11 @@ fn lower_attr(&self, attr: &Attribute) -> Attribute {
     }
 
     fn alias_attrs(&mut self, id: hir::HirId, target_id: hir::HirId) {
-        if let Some(&a) = self.attrs.get(&target_id) {
+        debug_assert_eq!(id.owner, self.current_hir_id_owner);
+        debug_assert_eq!(target_id.owner, self.current_hir_id_owner);
+        if let Some(&a) = self.attrs.get(&target_id.local_id) {
             debug_assert!(!a.is_empty());
-            self.attrs.insert(id, a);
+            self.attrs.insert(id.local_id, a);
         }
     }
 
@@ -1435,7 +1487,7 @@ fn generate_opaque_type(
         trace!("registering opaque type with id {:#?}", opaque_ty_id);
         let opaque_ty_item = hir::Item {
             def_id: opaque_ty_id,
-            ident: Ident::invalid(),
+            ident: Ident::empty(),
             kind: opaque_ty_item_kind,
             vis: respan(self.lower_span(span.shrink_to_lo()), hir::VisibilityKind::Inherited),
             span: self.lower_span(opaque_ty_span),
@@ -2066,7 +2118,7 @@ fn stmt_let_pat(
         let hir_id = self.next_id();
         if let Some(a) = attrs {
             debug_assert!(!a.is_empty());
-            self.attrs.insert(hir_id, a);
+            self.attrs.insert(hir_id.local_id, a);
         }
         let local = hir::Local { hir_id, init, pat, source, span: self.lower_span(span), ty: None };
         self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local)))
index 968e9fa3e24802705600c99b3e593cce04ab1b12..793f6504be6f79f030ea168db247a9a4793f1d80 100644 (file)
@@ -113,7 +113,7 @@ fn ban_let_expr(&self, expr: &'a Expr) {
         if sess.opts.unstable_features.is_nightly_build() {
             sess.struct_span_err(expr.span, "`let` expressions are not supported here")
                 .note("only supported directly in conditions of `if`- and `while`-expressions")
-                .note("as well as when nested within `&&` and parenthesis in those conditions")
+                .note("as well as when nested within `&&` and parentheses in those conditions")
                 .emit();
         } else {
             sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
index c24882086e12d16d1b808e6f4270adebd4820658..6d0589b7ba1af7a5ae205dc8a45df5f09ae9257e 100644 (file)
@@ -1675,7 +1675,7 @@ fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
         self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
     }
 
-    // Does `expr` need parenthesis when printed in a condition position?
+    // 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) {}`.
index 8d7f2b65c5a828951fec06833818a621bedee592..719caaabbbf0a343c30138abf75e2153c0690de6 100644 (file)
@@ -802,7 +802,7 @@ pub fn is_signed(self) -> bool {
 /// Valid repr contents: any of the primitive integral type names (see
 /// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
 /// the same discriminant size that the corresponding C enum would or C
-/// structure layout, `packed` to remove padding, and `transparent` to elegate representation
+/// structure layout, `packed` to remove padding, and `transparent` to delegate representation
 /// concerns to the only non-ZST field.
 pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
     use ReprAttr::*;
index ee2ce1d3f74c3035129f153692dcbafeb12740f7..952e18c1e570db6463ce2bf8b9e349bfc0a629f0 100644 (file)
 use std::fmt;
 use std::ops::Index;
 
-crate struct BorrowSet<'tcx> {
+pub struct BorrowSet<'tcx> {
     /// The fundamental map relating bitvector indexes to the borrows
     /// in the MIR. Each borrow is also uniquely identified in the MIR
     /// by the `Location` of the assignment statement in which it
     /// appears on the right hand side. Thus the location is the map
     /// key, and its position in the map corresponds to `BorrowIndex`.
-    crate location_map: FxIndexMap<Location, BorrowData<'tcx>>,
+    pub location_map: FxIndexMap<Location, BorrowData<'tcx>>,
 
     /// Locations which activate borrows.
     /// NOTE: a given location may activate more than one borrow in the future
     /// when more general two-phase borrow support is introduced, but for now we
     /// only need to store one borrow index.
-    crate activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
+    pub activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
 
     /// Map from local to all the borrows on that local.
-    crate local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
+    pub local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
 
     crate locals_state_at_exit: LocalsStateAtExit,
 }
@@ -43,27 +43,27 @@ fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> {
 /// Location where a two-phase borrow is activated, if a borrow
 /// is in fact a two-phase borrow.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-crate enum TwoPhaseActivation {
+pub enum TwoPhaseActivation {
     NotTwoPhase,
     NotActivated,
     ActivatedAt(Location),
 }
 
 #[derive(Debug, Clone)]
-crate struct BorrowData<'tcx> {
+pub struct BorrowData<'tcx> {
     /// Location where the borrow reservation starts.
     /// In many cases, this will be equal to the activation location but not always.
-    crate reserve_location: Location,
+    pub reserve_location: Location,
     /// Location where the borrow is activated.
-    crate activation_location: TwoPhaseActivation,
+    pub activation_location: TwoPhaseActivation,
     /// What kind of borrow this is
-    crate kind: mir::BorrowKind,
+    pub kind: mir::BorrowKind,
     /// The region for which this borrow is live
-    crate region: RegionVid,
+    pub region: RegionVid,
     /// Place from which we are borrowing
-    crate borrowed_place: mir::Place<'tcx>,
+    pub borrowed_place: mir::Place<'tcx>,
     /// Place to which the borrow was stored
-    crate assigned_place: mir::Place<'tcx>,
+    pub assigned_place: mir::Place<'tcx>,
 }
 
 impl<'tcx> fmt::Display for BorrowData<'tcx> {
@@ -78,7 +78,7 @@ fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-crate enum LocalsStateAtExit {
+pub enum LocalsStateAtExit {
     AllAreInvalidated,
     SomeAreInvalidated { has_storage_dead_or_moved: BitSet<Local> },
 }
@@ -315,9 +315,7 @@ fn insert_as_pending_if_two_phase(
         //    TEMP = &foo
         //
         // so extract `temp`.
-        let temp = if let Some(temp) = assigned_place.as_local() {
-            temp
-        } else {
+        let Some(temp) = assigned_place.as_local() else {
             span_bug!(
                 self.body.source_info(start_location).span,
                 "expected 2-phase borrow to assign to a local, not `{:?}`",
index 37398894a202bf5829ba048de43326427bf4784f..439c728798d3a42b1b8c1717fd61a4a873103820 100644 (file)
@@ -11,7 +11,6 @@
 };
 use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
-use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::sym;
 use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -247,6 +246,36 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                                         place_name, partially_str, loop_message
                                     ),
                                 );
+                                let sess = self.infcx.tcx.sess;
+                                let ty = used_place.ty(self.body, self.infcx.tcx).ty;
+                                // If we have a `&mut` ref, we need to reborrow.
+                                if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
+                                    // If we are in a loop this will be suggested later.
+                                    if !is_loop_move {
+                                        err.span_suggestion_verbose(
+                                            move_span.shrink_to_lo(),
+                                            &format!(
+                                                "consider creating a fresh reborrow of {} here",
+                                                self.describe_place(moved_place.as_ref())
+                                                    .map(|n| format!("`{}`", n))
+                                                    .unwrap_or_else(
+                                                        || "the mutable reference".to_string()
+                                                    ),
+                                            ),
+                                            "&mut *".to_string(),
+                                            Applicability::MachineApplicable,
+                                        );
+                                    }
+                                } else if let Ok(snippet) =
+                                    sess.source_map().span_to_snippet(move_span)
+                                {
+                                    err.span_suggestion(
+                                        move_span,
+                                        "consider borrowing to avoid moving into the for loop",
+                                        format!("&{}", snippet),
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                }
                             } else {
                                 err.span_label(
                                     fn_call_span,
@@ -315,35 +344,6 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                         in_pattern = true;
                     }
                 }
-
-                if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
-                    let sess = self.infcx.tcx.sess;
-                    let ty = used_place.ty(self.body, self.infcx.tcx).ty;
-                    // If we have a `&mut` ref, we need to reborrow.
-                    if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
-                        // If we are in a loop this will be suggested later.
-                        if !is_loop_move {
-                            err.span_suggestion_verbose(
-                                move_span.shrink_to_lo(),
-                                &format!(
-                                    "consider creating a fresh reborrow of {} here",
-                                    self.describe_place(moved_place.as_ref())
-                                        .map(|n| format!("`{}`", n))
-                                        .unwrap_or_else(|| "the mutable reference".to_string()),
-                                ),
-                                "&mut *".to_string(),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                    } else if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
-                        err.span_suggestion(
-                            move_span,
-                            "consider borrowing to avoid moving into the for loop",
-                            format!("&{}", snippet),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
             }
 
             use_spans.var_span_label_path_only(
index 855e6850b2efa8d1a3345b39aff153ab571c93ab..692c20d7dfe34ebed24443a863b7966d356528c7 100644 (file)
@@ -5,11 +5,10 @@
 use rustc_mir_dataflow::move_paths::{
     IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
 };
-use rustc_span::source_map::DesugaringKind;
 use rustc_span::{sym, Span, DUMMY_SP};
 use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
 
-use crate::diagnostics::UseSpans;
+use crate::diagnostics::{FnSelfUseKind, UseSpans};
 use crate::prefixes::PrefixSet;
 use crate::MirBorrowckCtxt;
 
@@ -400,19 +399,21 @@ fn report_cannot_move_from_borrowed_content(
             | ty::Opaque(def_id, _) => def_id,
             _ => return err,
         };
-        let is_option = self.infcx.tcx.is_diagnostic_item(sym::Option, def_id);
-        let is_result = self.infcx.tcx.is_diagnostic_item(sym::Result, def_id);
-        if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
+        let diag_name = self.infcx.tcx.get_diagnostic_name(def_id);
+        if matches!(diag_name, Some(sym::Option | sym::Result))
+            && use_spans.map_or(true, |v| !v.for_closure())
+        {
             err.span_suggestion_verbose(
                 span.shrink_to_hi(),
-                &format!(
-                    "consider borrowing the `{}`'s content",
-                    if is_option { "Option" } else { "Result" }
-                ),
+                &format!("consider borrowing the `{}`'s content", diag_name.unwrap()),
                 ".as_ref()".to_string(),
                 Applicability::MaybeIncorrect,
             );
-        } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) {
+        } else if let Some(UseSpans::FnSelfUse {
+            kind: FnSelfUseKind::Normal { implicit_into_iter: true, .. },
+            ..
+        }) = use_spans
+        {
             let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
                 Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
                     type_known_to_meet_bound_modulo_regions(
index 246d2e3208cf232d59c8cf715b96e1208f196523..d5ff4c6766f0fd2c9ee48ccf3c60515c83107872 100644 (file)
@@ -45,12 +45,12 @@ pub(crate) fn report_mutability_error(
         let item_msg;
         let reason;
         let mut opt_source = None;
-        let access_place_desc = self.describe_place(access_place.as_ref());
+        let access_place_desc = self.describe_any_place(access_place.as_ref());
         debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
 
         match the_place_err {
             PlaceRef { local, projection: [] } => {
-                item_msg = format!("`{}`", access_place_desc.unwrap());
+                item_msg = access_place_desc;
                 if access_place.as_local().is_some() {
                     reason = ", as it is not declared as mutable".to_string();
                 } else {
@@ -83,7 +83,7 @@ pub(crate) fn report_mutability_error(
                     // If we deref an immutable ref then the suggestion here doesn't help.
                     return;
                 } else {
-                    item_msg = format!("`{}`", access_place_desc.unwrap());
+                    item_msg = access_place_desc;
                     if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
                         reason = ", as it is not declared as mutable".to_string();
                     } else {
@@ -96,17 +96,17 @@ pub(crate) fn report_mutability_error(
             PlaceRef { local, projection: [ProjectionElem::Deref] }
                 if self.body.local_decls[local].is_ref_for_guard() =>
             {
-                item_msg = format!("`{}`", access_place_desc.unwrap());
+                item_msg = access_place_desc;
                 reason = ", as it is immutable for the pattern guard".to_string();
             }
             PlaceRef { local, projection: [ProjectionElem::Deref] }
                 if self.body.local_decls[local].is_ref_to_static() =>
             {
                 if access_place.projection.len() == 1 {
-                    item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
+                    item_msg = format!("immutable static item {}", access_place_desc);
                     reason = String::new();
                 } else {
-                    item_msg = format!("`{}`", access_place_desc.unwrap());
+                    item_msg = access_place_desc;
                     let local_info = &self.body.local_decls[local].local_info;
                     if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
                         let static_name = &self.infcx.tcx.item_name(def_id);
@@ -121,7 +121,7 @@ pub(crate) fn report_mutability_error(
                     && proj_base.is_empty()
                     && !self.upvars.is_empty()
                 {
-                    item_msg = format!("`{}`", access_place_desc.unwrap());
+                    item_msg = access_place_desc;
                     debug_assert!(
                         self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr()
                     );
@@ -147,7 +147,7 @@ pub(crate) fn report_mutability_error(
                     });
                     let pointer_type = source.describe_for_immutable_place(self.infcx.tcx);
                     opt_source = Some(source);
-                    if let Some(desc) = access_place_desc {
+                    if let Some(desc) = self.describe_place(access_place.as_ref()) {
                         item_msg = format!("`{}`", desc);
                         reason = match error_access {
                             AccessKind::Mutate => format!(", which is behind {}", pointer_type),
index b15e55cd6675e786be24d4fabb6a5362717f6c49..723b57ed970ad6bb16bac57787f39029e9ea4f4f 100644 (file)
@@ -90,9 +90,7 @@ fn compile_all_suggestions(
         let mut unified_already = FxHashSet::default();
 
         for (fr, outlived) in &self.constraints_to_add {
-            let fr_name = if let Some(fr_name) = self.region_vid_to_name(mbcx, *fr) {
-                fr_name
-            } else {
+            let Some(fr_name) = self.region_vid_to_name(mbcx, *fr) else {
                 continue;
             };
 
index e6260157d11a752bda23d4f6b0022fff47477b7d..aca7d3174f6cd567080aafd61b38949ba1154439 100644 (file)
@@ -2,11 +2,11 @@
 
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
-#![cfg_attr(bootstrap, feature(const_panic))]
 #![feature(crate_visibility_modifier)]
 #![feature(format_args_capture)]
 #![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
+#![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(stmt_expr_attributes)]
 #![feature(trusted_step)]
@@ -63,7 +63,7 @@
 
 use self::path_utils::*;
 
-mod borrow_set;
+pub mod borrow_set;
 mod borrowck_errors;
 mod constraint_generation;
 mod constraints;
index 21c26af8178ffaa7c44359bf04e2e88b24c8efbb..22bb3a29425ee1b49d5b44a3bc228030af3d0ac7 100644 (file)
@@ -689,6 +689,16 @@ fn apply_member_constraint(
         // them down.
         let mut choice_regions: Vec<ty::RegionVid> = choice_regions.to_vec();
 
+        // Convert to the SCC representative: sometimes we have inference
+        // variables in the member constraint that wind up equated with
+        // universal regions. The scc representative is the minimal numbered
+        // one from the corresponding scc so it will be the universal region
+        // if one exists.
+        for c_r in &mut choice_regions {
+            let scc = self.constraint_sccs.scc(*c_r);
+            *c_r = self.scc_representatives[scc];
+        }
+
         // The 'member region' in a member constraint is part of the
         // hidden type, which must be in the root universe. Therefore,
         // it cannot have any placeholders in its value.
index 7d4df59902aedbb759d4aecac35fde788168996d..0fa72ed8241bc61086a1c7cf0fd05cb07ffd6872 100644 (file)
@@ -94,6 +94,7 @@ pub(super) fn prove_trait_ref(
             Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
                 trait_ref,
                 constness: ty::BoundConstness::NotConst,
+                polarity: ty::ImplPolarity::Positive,
             }))),
             locations,
             category,
index 70c74940d6235e117b8400a96d8d6eba851f643a..f71cf09ecf6304941c6fb6d2a04497185ed0ad58 100644 (file)
@@ -1,20 +1,18 @@
 use rustc_data_structures::frozen::Frozen;
 use rustc_data_structures::transitive_relation::TransitiveRelation;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
-use rustc_infer::infer::free_regions::FreeRegionRelations;
 use rustc_infer::infer::outlives;
 use rustc_infer::infer::region_constraints::GenericKind;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::query::OutlivesBound;
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
+use rustc_middle::ty::{self, RegionVid, Ty};
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
 use std::rc::Rc;
 use type_op::TypeOpOutput;
 
 use crate::{
-    nll::ToRegionVid,
     type_check::constraint_conversion,
     type_check::{Locations, MirTypeckRegionConstraints},
     universal_regions::UniversalRegions,
@@ -383,21 +381,3 @@ fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
         }
     }
 }
-
-/// This trait is used by the `impl-trait` constraint code to abstract
-/// over the `FreeRegionMap` from lexical regions and
-/// `UniversalRegions` (from NLL)`.
-impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> {
-    fn sub_free_regions(
-        &self,
-        _tcx: TyCtxt<'tcx>,
-        shorter: ty::Region<'tcx>,
-        longer: ty::Region<'tcx>,
-    ) -> bool {
-        let shorter = shorter.to_region_vid();
-        assert!(self.universal_regions.is_universal_region(shorter));
-        let longer = longer.to_region_vid();
-        assert!(self.universal_regions.is_universal_region(longer));
-        self.outlives(longer, shorter)
-    }
-}
index 7bf119863fdc74f2b755f8fb4eada6e5000b7ce2..7e6a481ca69a1b76f62008c1282b3ea676662ac0 100644 (file)
@@ -36,7 +36,6 @@
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::opaque_types::{GenerateMemberConstraints, InferCtxtExt};
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::type_op;
 use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
@@ -185,7 +184,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
         &region_bound_pairs,
         implicit_region_bound,
         &mut borrowck_context,
-        &universal_region_relations,
         |mut cx| {
             cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
             liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
@@ -253,15 +251,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
 }
 
 #[instrument(
-    skip(
-        infcx,
-        body,
-        promoted,
-        region_bound_pairs,
-        borrowck_context,
-        universal_region_relations,
-        extra
-    ),
+    skip(infcx, body, promoted, region_bound_pairs, borrowck_context, extra),
     level = "debug"
 )]
 fn type_check_internal<'a, 'tcx, R>(
@@ -272,7 +262,6 @@ fn type_check_internal<'a, 'tcx, R>(
     region_bound_pairs: &'a RegionBoundPairs<'tcx>,
     implicit_region_bound: ty::Region<'tcx>,
     borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
-    universal_region_relations: &'a UniversalRegionRelations<'tcx>,
     extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R,
 ) -> R {
     let mut checker = TypeChecker::new(
@@ -282,7 +271,6 @@ fn type_check_internal<'a, 'tcx, R>(
         region_bound_pairs,
         implicit_region_bound,
         borrowck_context,
-        universal_region_relations,
     );
     let errors_reported = {
         let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
@@ -901,7 +889,6 @@ struct TypeChecker<'a, 'tcx> {
     implicit_region_bound: ty::Region<'tcx>,
     reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
     borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
-    universal_region_relations: &'a UniversalRegionRelations<'tcx>,
 }
 
 struct BorrowCheckContext<'a, 'tcx> {
@@ -1050,7 +1037,6 @@ fn new(
         region_bound_pairs: &'a RegionBoundPairs<'tcx>,
         implicit_region_bound: ty::Region<'tcx>,
         borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
-        universal_region_relations: &'a UniversalRegionRelations<'tcx>,
     ) -> Self {
         let mut checker = Self {
             infcx,
@@ -1062,7 +1048,6 @@ fn new(
             implicit_region_bound,
             borrowck_context,
             reported_errors: Default::default(),
-            universal_region_relations,
         };
         checker.check_user_type_annotations();
         checker
@@ -1322,8 +1307,6 @@ fn eq_opaque_type_and_type(
             ),
         )?;
 
-        let universal_region_relations = self.universal_region_relations;
-
         // Finally, if we instantiated the anon types successfully, we
         // have to solve any bounds (e.g., `-> impl Iterator` needs to
         // prove that `T: Iterator` where `T` is the type we
@@ -1335,12 +1318,7 @@ fn eq_opaque_type_and_type(
                 ConstraintCategory::OpaqueType,
                 CustomTypeOp::new(
                     |infcx| {
-                        infcx.constrain_opaque_type(
-                            opaque_type_key,
-                            &opaque_decl,
-                            GenerateMemberConstraints::IfNoStaticBound,
-                            universal_region_relations,
-                        );
+                        infcx.constrain_opaque_type(opaque_type_key, &opaque_decl);
                         Ok(InferOk { value: (), obligations: vec![] })
                     },
                     || "opaque_type_map".to_string(),
index c032364c008f34a551f782107b3eb7594a843884..198287f608e3973d318d9d4e6e869be0dbd48c26 100644 (file)
@@ -812,7 +812,7 @@ pub fn expand_global_asm<'cx>(
         Ok(args) => {
             if let Some(inline_asm) = expand_preparsed_asm(ecx, args) {
                 MacEager::items(smallvec![P(ast::Item {
-                    ident: Ident::invalid(),
+                    ident: Ident::empty(),
                     attrs: Vec::new(),
                     id: ast::DUMMY_NODE_ID,
                     kind: ast::ItemKind::GlobalAsm(inline_asm),
index 241c90c157125e5c90daae48737a863c763dead1..31a35b9b7b45ed86662168e575f9ecae9eb3b330 100644 (file)
@@ -85,7 +85,7 @@ fn expand(
 fn dummy_annotatable() -> Annotatable {
     Annotatable::GenericParam(ast::GenericParam {
         id: ast::DUMMY_NODE_ID,
-        ident: Ident::invalid(),
+        ident: Ident::empty(),
         attrs: Default::default(),
         bounds: Default::default(),
         is_placeholder: false,
index cd78c016caa4f3482612efd4f1c215285e5d48f2..a225b328ab6a4fc205c260e5bce01e440866384c 100644 (file)
@@ -724,7 +724,7 @@ fn create_derived_impl(
 
         cx.item(
             self.span,
-            Ident::invalid(),
+            Ident::empty(),
             a,
             ast::ItemKind::Impl(Box::new(ast::ImplKind {
                 unsafety,
index bcf95719db56b839331c689a787245e5c45409f2..fa389a51115782696ef49c9d7a7c860aaab1e624 100644 (file)
@@ -178,7 +178,7 @@ fn inject_impl_of_structural_trait(
 
     let newitem = cx.item(
         span,
-        Ident::invalid(),
+        Ident::empty(),
         attrs,
         ItemKind::Impl(Box::new(ImplKind {
             unsafety: ast::Unsafe::No,
index e0d57267525d9e12980e44b076f81fd688095466..e106f6014a31d597a0a84f18db3473a43d79b9b1 100644 (file)
@@ -77,7 +77,7 @@ pub fn inject(
 
     let use_item = cx.item(
         span,
-        Ident::invalid(),
+        Ident::empty(),
         vec![cx.attribute(cx.meta_word(span, sym::prelude_import))],
         ast::ItemKind::Use(ast::UseTree {
             prefix: cx.path(span, import_path),
index 32cc50eebe4364ad8c6707757c63e87501304196..0a8d6122aa7a79bf4ec870df31498ec93ba9cd16 100644 (file)
@@ -224,7 +224,7 @@ pub(crate) fn run_aot(
                     tcx,
                     (backend_config.clone(), cgu.name()),
                     module_codegen,
-                    rustc_middle::dep_graph::hash_result,
+                    Some(rustc_middle::dep_graph::hash_result),
                 );
 
                 if let Some((id, product)) = work_product {
index 3b77097e9ad00230b058ab0ef63762cb9eabbc96..7c3ed3c5ee9db8d68b0aea669111bd1e9216ad8f 100644 (file)
@@ -118,7 +118,7 @@ fn codegen_llvm_inline_asm(&mut self, _ia: &LlvmInlineAsmInner, _outputs: Vec<Pl
         true
     }
 
-    fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span]) {
+    fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span], _instance: Instance<'_>) {
         let asm_arch = self.tcx.sess.asm_arch.unwrap();
         let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64);
         let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
index 9f96096574fe158734744768d1cff77ed3f1db20..a3b8d328388e0d5154dc88fd667b177b504d1b2c 100644 (file)
@@ -59,7 +59,13 @@ pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (Modul
     let start_time = Instant::now();
 
     let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
-    let (module, _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
+    let (module, _) = tcx.dep_graph.with_task(
+        dep_node,
+        tcx,
+        cgu_name,
+        module_codegen,
+        Some(dep_graph::hash_result),
+    );
     let time_to_codegen = start_time.elapsed();
     drop(prof_timer);
 
index ac908418ee4bf6fcf160a070090705e157c5793c..fff2aa6df7c725ab53bcd2a2c9ba5008c15b72e2 100644 (file)
@@ -915,6 +915,16 @@ fn nonnull_metadata(&mut self, _load: RValue<'gcc>) {
         // TODO(antoyo)
     }
 
+    fn type_metadata(&mut self, _function: RValue<'gcc>, _typeid: String) {
+        // Unsupported.
+    }
+
+    fn typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> {
+        // Unsupported.
+        self.context.new_rvalue_from_int(self.int_type, 0)
+    }
+
+
     fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
         self.store_with_flags(val, ptr, align, MemFlags::empty())
     }
index 375d422cb25c40608565b752f0b555caf54425a4..64bd586662d385a863a45b0bd555d340cda24721 100644 (file)
@@ -367,6 +367,11 @@ fn sideeffect(&mut self) {
         // TODO(antoyo)
     }
 
+    fn type_test(&mut self, _pointer: Self::Value, _typeid: Self::Value) -> Self::Value {
+        // Unsupported.
+        self.context.new_rvalue_from_int(self.int_type, 0)
+    }
+
     fn va_start(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
         unimplemented!();
     }
index a6a553b31a3262b8eb25676f707c02dcdf089029..5f3f533447532c5ffcac8a4b0964dd25356c3f6b 100644 (file)
@@ -11,7 +11,7 @@ doctest = false
 bitflags = "1.0"
 cstr = "0.2"
 libc = "0.2"
-measureme = "9.1.0"
+measureme = "10.0.0"
 snap = "1"
 tracing = "0.1"
 rustc_middle = { path = "../rustc_middle" }
index dca9c1f04d3c0fd40672c6babd21295aeb89473b..bedd3523d899e89f0f8205c28b72ad7e03307c17 100644 (file)
@@ -1,7 +1,6 @@
 use crate::builder::Builder;
 use crate::context::CodegenCx;
 use crate::llvm::{self, AttributePlace};
-use crate::llvm_util;
 use crate::type_::Type;
 use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
@@ -53,15 +52,10 @@ fn apply_attrs_to_callsite(
 }
 
 fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool {
-    // LLVM prior to version 12 has known miscompiles in the presence of
-    // noalias attributes (see #54878). Only enable mutable noalias by
-    // default for versions we believe to be safe.
-    cx.tcx
-        .sess
-        .opts
-        .debugging_opts
-        .mutable_noalias
-        .unwrap_or_else(|| llvm_util::get_version() >= (12, 0, 0))
+    // LLVM prior to version 12 had known miscompiles in the presence of
+    // noalias attributes (see #54878), but we don't support earlier
+    // versions at all anymore. We now enable mutable noalias by default.
+    cx.tcx.sess.opts.debugging_opts.mutable_noalias.unwrap_or(true)
 }
 
 impl ArgAttributesExt for ArgAttributes {
index 341a88824169847f23948d40631592e7f992cf27..f128f76958092214e70afad072253c0aff55054e 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::{bug, span_bug};
+use rustc_middle::{bug, span_bug, ty::Instance};
 use rustc_span::{Pos, Span, Symbol};
 use rustc_target::abi::*;
 use rustc_target::asm::*;
@@ -120,6 +120,7 @@ fn codegen_inline_asm(
         operands: &[InlineAsmOperandRef<'tcx, Self>],
         options: InlineAsmOptions,
         line_spans: &[Span],
+        instance: Instance<'_>,
     ) {
         let asm_arch = self.tcx.sess.asm_arch.unwrap();
 
@@ -135,7 +136,10 @@ fn codegen_inline_asm(
                     let is_target_supported = |reg_class: InlineAsmRegClass| {
                         for &(_, feature) in reg_class.supported_types(asm_arch) {
                             if let Some(feature) = feature {
-                                if self.tcx.sess.target_features.contains(&Symbol::intern(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)
                                 {
                                     return true;
                                 }
index 380dfd387235d1b6037c193db8aefdf8a7d7aa22..82c3c2006eb148f8cb5bb72ac913cc47c8c77686 100644 (file)
@@ -161,6 +161,7 @@ pub fn target_machine_factory(
     let ffunction_sections =
         sess.opts.debugging_opts.function_sections.unwrap_or(sess.target.function_sections);
     let fdata_sections = ffunction_sections;
+    let funique_section_names = !sess.opts.debugging_opts.no_unique_section_names;
 
     let code_model = to_llvm_code_model(sess.code_model());
 
@@ -205,6 +206,7 @@ pub fn target_machine_factory(
                 use_softfp,
                 ffunction_sections,
                 fdata_sections,
+                funique_section_names,
                 trap_unreachable,
                 singlethread,
                 asm_comments,
index 3026c2fa0309aed4c046e3dc3da594fba0927672..8766caef6e37946dafc18feb684dbb8da749e37e 100644 (file)
@@ -113,8 +113,13 @@ pub fn compile_codegen_unit(
     let start_time = Instant::now();
 
     let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
-    let (module, _) =
-        tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
+    let (module, _) = tcx.dep_graph.with_task(
+        dep_node,
+        tcx,
+        cgu_name,
+        module_codegen,
+        Some(dep_graph::hash_result),
+    );
     let time_to_codegen = start_time.elapsed();
 
     // We assume that the cost to run LLVM on a CGU is proportional to
index d5deacf3811304c972fb0cc5919b833c23ac0f97..6c74163fb496c18bf33923b9c2fc0c5f949a2e30 100644 (file)
@@ -604,6 +604,32 @@ fn nonnull_metadata(&mut self, load: &'ll Value) {
         }
     }
 
+    fn type_metadata(&mut self, function: &'ll Value, typeid: String) {
+        let typeid_metadata = self.typeid_metadata(typeid);
+        let v = [self.const_usize(0), typeid_metadata];
+        unsafe {
+            llvm::LLVMGlobalSetMetadata(
+                function,
+                llvm::MD_type as c_uint,
+                llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
+                    self.cx.llcx,
+                    v.as_ptr(),
+                    v.len() as c_uint,
+                )),
+            )
+        }
+    }
+
+    fn typeid_metadata(&mut self, typeid: String) -> Self::Value {
+        unsafe {
+            llvm::LLVMMDStringInContext(
+                self.cx.llcx,
+                typeid.as_ptr() as *const c_char,
+                typeid.as_bytes().len() as c_uint,
+            )
+        }
+    }
+
     fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value {
         self.store_with_flags(val, ptr, align, MemFlags::empty())
     }
@@ -705,7 +731,7 @@ 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 llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() {
+        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);
@@ -717,7 +743,7 @@ fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Val
     }
 
     fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
-        if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() {
+        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);
index 257a0ac89d86ffff881fd814b631841fba8d26dc..1dba264a9614a32a5ae9fa62dce679a1d3fc5318 100644 (file)
@@ -134,9 +134,6 @@ pub unsafe fn create_module(
     let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
 
     let mut target_data_layout = sess.target.data_layout.clone();
-    if llvm_util::get_version() < (12, 0, 0) && sess.target.arch == "powerpc64" {
-        target_data_layout = target_data_layout.replace("-v256:256:256-v512:512:512", "");
-    }
     if llvm_util::get_version() < (13, 0, 0) {
         if sess.target.arch == "powerpc64" {
             target_data_layout = target_data_layout.replace("-S128", "");
@@ -221,6 +218,15 @@ pub unsafe fn create_module(
         llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1);
     }
 
+    if sess.is_sanitizer_cfi_enabled() {
+        // FIXME(rcvalle): Add support for non canonical jump tables.
+        let canonical_jump_tables = "CFI Canonical Jump Tables\0".as_ptr().cast();
+        // FIXME(rcvalle): Add it with Override behavior flag--LLVMRustAddModuleFlag adds it with
+        // Warning behavior flag. Add support for specifying the behavior flag to
+        // LLVMRustAddModuleFlag.
+        llvm::LLVMRustAddModuleFlag(llmod, canonical_jump_tables, 1);
+    }
+
     // Control Flow Guard is currently only supported by the MSVC linker on Windows.
     if sess.target.is_like_msvc {
         match sess.opts.cg.control_flow_guard {
@@ -779,6 +785,8 @@ macro_rules! mk_struct {
             ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void);
         }
 
+        ifn!("llvm.type.test", fn(i8p, self.type_metadata()) -> i1);
+
         if self.sess().opts.debuginfo != DebugInfo::None {
             ifn!("llvm.dbg.declare", fn(self.type_metadata(), self.type_metadata()) -> void);
             ifn!("llvm.dbg.value", fn(self.type_metadata(), t_i64, self.type_metadata()) -> void);
index c43141c769519c790311e3b456f57463598030c1..e63fb22829a3f5b9789f3ab4f95a54ec1e97a404 100644 (file)
@@ -401,6 +401,14 @@ fn sideeffect(&mut self) {
         }
     }
 
+    fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value {
+        // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time
+        // optimization pass replaces calls to this intrinsic with code to test type membership.
+        let i8p_ty = self.type_i8p();
+        let bitcast = self.bitcast(pointer, i8p_ty);
+        self.call_intrinsic("llvm.type.test", &[bitcast, typeid])
+    }
+
     fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
         self.call_intrinsic("llvm.va_start", &[va_list])
     }
index 4c9ae4faf7233f4a1e88ed043eecb73d630b901a..21d2388fc3054f458dcf12a200d2c169324627fb 100644 (file)
@@ -416,6 +416,7 @@ pub enum MetadataType {
     MD_nontemporal = 9,
     MD_mem_parallel_loop_access = 10,
     MD_nonnull = 11,
+    MD_type = 19,
 }
 
 /// LLVMRustAsmDialect
@@ -1002,6 +1003,8 @@ pub fn LLVMStructTypeInContext(
     pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
     pub fn LLVMReplaceAllUsesWith(OldVal: &'a Value, NewVal: &'a Value);
     pub fn LLVMSetMetadata(Val: &'a Value, KindID: c_uint, Node: &'a Value);
+    pub fn LLVMGlobalSetMetadata(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
+    pub fn LLVMValueAsMetadata(Node: &'a Value) -> &Metadata;
 
     // Operations on constants of any type
     pub fn LLVMConstNull(Ty: &Type) -> &Value;
@@ -1770,7 +1773,7 @@ pub fn LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
 
     pub fn LLVMDisposeMessage(message: *mut c_char);
 
-    pub fn LLVMStartMultithreaded() -> Bool;
+    pub fn LLVMIsMultithreaded() -> Bool;
 
     /// Returns a string describing the last error caused by an LLVMRust* call.
     pub fn LLVMRustGetLastError() -> *const c_char;
@@ -2187,6 +2190,7 @@ pub fn LLVMRustCreateTargetMachine(
         UseSoftFP: bool,
         FunctionSections: bool,
         DataSections: bool,
+        UniqueSectionNames: bool,
         TrapUnreachable: bool,
         Singlethread: bool,
         AsmComments: bool,
index b15efcd0dc2b1855504cc6823a69ed9b3cccf7bc..3e0ea92ab81ed08ad61c8e814823a2c3f9b708d8 100644 (file)
 use std::ptr;
 use std::slice;
 use std::str;
-use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Once;
 
-static POISONED: AtomicBool = AtomicBool::new(false);
 static INIT: Once = Once::new();
 
 pub(crate) fn init(sess: &Session) {
     unsafe {
         // Before we touch LLVM, make sure that multithreading is enabled.
+        if llvm::LLVMIsMultithreaded() != 1 {
+            bug!("LLVM compiled without support for threads");
+        }
         INIT.call_once(|| {
-            if llvm::LLVMStartMultithreaded() != 1 {
-                // use an extra bool to make sure that all future usage of LLVM
-                // cannot proceed despite the Once not running more than once.
-                POISONED.store(true, Ordering::SeqCst);
-            }
-
             configure_llvm(sess);
         });
-
-        if POISONED.load(Ordering::SeqCst) {
-            bug!("couldn't enable multi-threaded LLVM");
-        }
     }
 }
 
 fn require_inited() {
-    INIT.call_once(|| bug!("llvm is not initialized"));
-    if POISONED.load(Ordering::SeqCst) {
-        bug!("couldn't enable multi-threaded LLVM");
+    if !INIT.is_completed() {
+        bug!("LLVM is not initialized");
     }
 }
 
@@ -95,8 +85,7 @@ fn llvm_arg_to_arg_name(full_arg: &str) -> &str {
         // Ref:
         // - https://github.com/rust-lang/rust/issues/85351
         // - https://reviews.llvm.org/D103167
-        let llvm_version = llvm_util::get_version();
-        if llvm_version >= (11, 0, 0) && llvm_version < (13, 0, 0) {
+        if llvm_util::get_version() < (13, 0, 0) {
             add("-enable-machine-outliner=never", false);
         }
 
@@ -191,6 +180,7 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> Vec<&'a str> {
         ("aarch64", "dpb2") => vec!["ccdp"],
         ("aarch64", "frintts") => vec!["fptoint"],
         ("aarch64", "fcma") => vec!["complxnum"],
+        ("aarch64", "pmuv3") => vec!["perfmon"],
         (_, s) => vec![s],
     }
 }
@@ -416,11 +406,6 @@ pub fn llvm_global_features(sess: &Session) -> Vec<String> {
     // -Ctarget-features
     features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter));
 
-    // FIXME: Move outline-atomics to target definition when earliest supported LLVM is 12.
-    if get_version() >= (12, 0, 0) && sess.target.llvm_target.contains("aarch64-unknown-linux") {
-        features.push("+outline-atomics".to_string());
-    }
-
     features
 }
 
index cf1c60588978c33085d32337045a460ec8e4e3a0..be50911f4e143a8b5cb91fc4e0c8d344c9600982 100644 (file)
@@ -174,9 +174,8 @@ pub fn each_linked_rlib(
             _ => {}
         }
     }
-    let fmts = match fmts {
-        Some(f) => f,
-        None => return Err("could not find formats for rlibs".to_string()),
+    let Some(fmts) = fmts else {
+        return Err("could not find formats for rlibs".to_string());
     };
     for &cnum in crates {
         match fmts.get(cnum.as_usize() - 1) {
index 4a7090b31b4a9d8bc99247d24866a229563de40a..f80f9965f4d8acd0c651fb0a74dbf867abafa8ad 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_middle::middle::exported_symbols::{
     metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
 };
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::{SymbolName, TyCtxt};
@@ -363,7 +363,7 @@ pub fn provide(providers: &mut Providers) {
     providers.wasm_import_module_map = wasm_import_module_map;
 }
 
-pub fn provide_extern(providers: &mut Providers) {
+pub fn provide_extern(providers: &mut ExternProviders) {
     providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
     providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider;
 }
index 609316ea69fe560487cfd397f28999bab9133512..accb54e464553292fcd567093f4743a4fa453122 100644 (file)
@@ -480,14 +480,11 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
     }
 
     if let Some(trait_ref) = trait_ref {
-        push_item_name(tcx, trait_ref.skip_binder().def_id, true, &mut vtable_name);
+        let trait_ref =
+            tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref);
+        push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
         visited.clear();
-        push_generic_params_internal(
-            tcx,
-            trait_ref.skip_binder().substs,
-            &mut vtable_name,
-            &mut visited,
-        );
+        push_generic_params_internal(tcx, trait_ref.substs, &mut vtable_name, &mut visited);
     } else {
         vtable_name.push_str("_");
     }
index b759e3a7a7a33d72b946bfa2f69e4b7e245ad764..4c87d4d896e2ec8129362eb05464504d68108a26 100644 (file)
@@ -3,6 +3,7 @@
 #![feature(box_patterns)]
 #![feature(try_blocks)]
 #![feature(in_band_lifetimes)]
+#![feature(let_else)]
 #![feature(once_cell)]
 #![feature(nll)]
 #![feature(associated_type_bounds)]
@@ -26,7 +27,7 @@
 use rustc_hir::LangItem;
 use rustc_middle::dep_graph::WorkProduct;
 use rustc_middle::middle::dependency_format::Dependencies;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
 use rustc_session::cstore::{self, CrateSource};
 use rustc_session::utils::NativeLibKind;
@@ -168,7 +169,7 @@ pub fn provide(providers: &mut Providers) {
     crate::target_features::provide(providers);
 }
 
-pub fn provide_extern(providers: &mut Providers) {
+pub fn provide_extern(providers: &mut ExternProviders) {
     crate::back::symbol_export::provide_extern(providers);
 }
 
index b0a5631549df85af3bd872d04f00fd6bac9a84b7..a9471f7b7716052c60f0228c13bfd793c1c52361 100644 (file)
@@ -19,6 +19,7 @@
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
 use rustc_span::source_map::Span;
 use rustc_span::{sym, Symbol};
+use rustc_symbol_mangling::typeid_for_fnabi;
 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
 use rustc_target::abi::{self, HasDataLayout, WrappingRange};
 use rustc_target::spec::abi::Abi;
@@ -818,12 +819,43 @@ fn codegen_call_terminator(
             self.codegen_argument(&mut bx, location, &mut llargs, last_arg);
         }
 
-        let fn_ptr = match (llfn, instance) {
-            (Some(llfn), _) => llfn,
-            (None, Some(instance)) => bx.get_fn_addr(instance),
+        let (is_indirect_call, fn_ptr) = match (llfn, instance) {
+            (Some(llfn), _) => (true, llfn),
+            (None, Some(instance)) => (false, bx.get_fn_addr(instance)),
             _ => span_bug!(span, "no llfn for call"),
         };
 
+        // For backends that support CFI using type membership (i.e., testing whether a given
+        // pointer is associated with a type identifier).
+        if bx.tcx().sess.is_sanitizer_cfi_enabled() && is_indirect_call {
+            // Emit type metadata and checks.
+            // FIXME(rcvalle): Add support for generalized identifiers.
+            // FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers.
+            let typeid = typeid_for_fnabi(bx.tcx(), fn_abi);
+            let typeid_metadata = bx.typeid_metadata(typeid);
+
+            // Test whether the function pointer is associated with the type identifier.
+            let cond = bx.type_test(fn_ptr, typeid_metadata);
+            let mut bx_pass = bx.build_sibling_block("type_test.pass");
+            let mut bx_fail = bx.build_sibling_block("type_test.fail");
+            bx.cond_br(cond, bx_pass.llbb(), bx_fail.llbb());
+
+            helper.do_call(
+                self,
+                &mut bx_pass,
+                fn_abi,
+                fn_ptr,
+                &llargs,
+                destination.as_ref().map(|&(_, target)| (ret_dest, target)),
+                cleanup,
+            );
+
+            bx_fail.abort();
+            bx_fail.unreachable();
+
+            return;
+        }
+
         helper.do_call(
             self,
             &mut bx,
@@ -845,6 +877,7 @@ fn codegen_asm_terminator(
         options: ast::InlineAsmOptions,
         line_spans: &[Span],
         destination: Option<mir::BasicBlock>,
+        instance: Instance<'_>,
     ) {
         let span = terminator.source_info.span;
 
@@ -898,7 +931,7 @@ fn codegen_asm_terminator(
             })
             .collect();
 
-        bx.codegen_inline_asm(template, &operands, options, line_spans);
+        bx.codegen_inline_asm(template, &operands, options, line_spans, instance);
 
         if let Some(target) = destination {
             helper.funclet_br(self, &mut bx, target);
@@ -1029,6 +1062,7 @@ fn codegen_terminator(
                     options,
                     line_spans,
                     destination,
+                    self.instance,
                 );
             }
         }
index 476ddbd93980ca76565fd2d9579fa0c3fc80bc5b..1ef863e84af7fe757b691c6fb0167bcda350f489 100644 (file)
@@ -4,6 +4,7 @@
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
+use rustc_symbol_mangling::typeid_for_fnabi;
 use rustc_target::abi::call::{FnAbi, PassMode};
 
 use std::iter;
@@ -244,6 +245,13 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     for (bb, _) in traversal::reverse_postorder(&mir) {
         fx.codegen_block(bb);
     }
+
+    // For backends that support CFI using type membership (i.e., testing whether a given  pointer
+    // is associated with a type identifier).
+    if cx.tcx().sess.is_sanitizer_cfi_enabled() {
+        let typeid = typeid_for_fnabi(cx.tcx(), fn_abi);
+        bx.type_metadata(llfn, typeid);
+    }
 }
 
 /// Produces, for each argument, a `Value` pointing at the
index ce6cec67ad41ef7b17f7f73bf31925d3671c6c2b..bea55bbc87965a37e12acf89ea8b3e66a0cf754f 100644 (file)
@@ -343,9 +343,7 @@ pub fn store_unsized<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
             .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest))
             .ty;
 
-        let (llptr, llextra) = if let OperandValue::Ref(llptr, Some(llextra), _) = self {
-            (llptr, llextra)
-        } else {
+        let OperandValue::Ref(llptr, Some(llextra), _) = self else {
             bug!("store_unsized called with a sized value")
         };
 
index 8d7e9612f4749d63c0fbb9e6388520627ac85374..caeeb23feb471bf48f86dcc753c44daf94adf7b1 100644 (file)
@@ -19,6 +19,7 @@
     ("crypto", Some(sym::arm_target_feature)),
     ("aes", Some(sym::arm_target_feature)),
     ("sha2", Some(sym::arm_target_feature)),
+    ("i8mm", Some(sym::arm_target_feature)),
     ("v5te", Some(sym::arm_target_feature)),
     ("v6", Some(sym::arm_target_feature)),
     ("v6k", Some(sym::arm_target_feature)),
@@ -35,7 +36,6 @@
     ("thumb-mode", Some(sym::arm_target_feature)),
 ];
 
-// Commented features are not available in LLVM 10.0, or have since been renamed
 const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     // FEAT_AdvSimd
     ("neon", Some(sym::aarch64_target_feature)),
     // FEAT_DIT
     ("dit", Some(sym::aarch64_target_feature)),
     // FEAT_FLAGM
-    // ("flagm", Some(sym::aarch64_target_feature)),
+    ("flagm", Some(sym::aarch64_target_feature)),
     // FEAT_SSBS
     ("ssbs", Some(sym::aarch64_target_feature)),
     // FEAT_SB
     ("sb", Some(sym::aarch64_target_feature)),
     // FEAT_PAUTH
-    // ("pauth", Some(sym::aarch64_target_feature)),
+    ("pauth", Some(sym::aarch64_target_feature)),
     // FEAT_DPB
     ("dpb", Some(sym::aarch64_target_feature)),
     // FEAT_DPB2
     // FEAT_FRINTTS
     ("frintts", Some(sym::aarch64_target_feature)),
     // FEAT_I8MM
-    // ("i8mm", Some(sym::aarch64_target_feature)),
+    ("i8mm", Some(sym::aarch64_target_feature)),
     // FEAT_F32MM
-    // ("f32mm", Some(sym::aarch64_target_feature)),
+    ("f32mm", Some(sym::aarch64_target_feature)),
     // FEAT_F64MM
-    // ("f64mm", Some(sym::aarch64_target_feature)),
+    ("f64mm", Some(sym::aarch64_target_feature)),
     // FEAT_BF16
-    // ("bf16", Some(sym::aarch64_target_feature)),
+    ("bf16", Some(sym::aarch64_target_feature)),
     // FEAT_RAND
     ("rand", Some(sym::aarch64_target_feature)),
     // FEAT_BTI
     ("sha3", Some(sym::aarch64_target_feature)),
     // FEAT_SM3 & FEAT_SM4
     ("sm4", Some(sym::aarch64_target_feature)),
+    // FEAT_PAN
+    ("pan", Some(sym::aarch64_target_feature)),
+    // FEAT_LOR
+    ("lor", Some(sym::aarch64_target_feature)),
+    // FEAT_VHE
+    ("vh", Some(sym::aarch64_target_feature)),
+    // FEAT_PMUv3
+    ("pmuv3", Some(sym::aarch64_target_feature)),
+    // FEAT_SPE
+    ("spe", Some(sym::aarch64_target_feature)),
     ("v8.1a", Some(sym::aarch64_target_feature)),
     ("v8.2a", Some(sym::aarch64_target_feature)),
     ("v8.3a", Some(sym::aarch64_target_feature)),
     ("v8.4a", Some(sym::aarch64_target_feature)),
     ("v8.5a", Some(sym::aarch64_target_feature)),
-    // ("v8.6a", Some(sym::aarch64_target_feature)),
-    // ("v8.7a", Some(sym::aarch64_target_feature)),
+    ("v8.6a", Some(sym::aarch64_target_feature)),
+    ("v8.7a", Some(sym::aarch64_target_feature)),
 ];
 
 const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
index 86f2781a7663b6a605c06764e75a4c0e26aa055b..31f539e1b03dba8f3cdeb548e3f91ca2dff0c477 100644 (file)
@@ -58,6 +58,7 @@ fn codegen_inline_asm(
         operands: &[InlineAsmOperandRef<'tcx, Self>],
         options: InlineAsmOptions,
         line_spans: &[Span],
+        instance: Instance<'_>,
     );
 }
 
index 8129a14fcfdc965b844074c9c9220fb1c3d99225..8fef8314a5ccd1aeea37ee4c83b7659d31e80cda 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_session::{
     config::{self, OutputFilenames, PrintRequest},
@@ -80,7 +80,7 @@ fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
     }
 
     fn provide(&self, _providers: &mut Providers) {}
-    fn provide_extern(&self, _providers: &mut Providers) {}
+    fn provide_extern(&self, _providers: &mut ExternProviders) {}
     fn codegen_crate<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
index e7da96f0adafdaf53b510f3084c7f4ad684b59c3..158e658301eed725410dba017970a4b1d7e18fae 100644 (file)
@@ -158,6 +158,8 @@ fn write_operand_repeatedly(
 
     fn range_metadata(&mut self, load: Self::Value, range: WrappingRange);
     fn nonnull_metadata(&mut self, load: Self::Value);
+    fn type_metadata(&mut self, function: Self::Function, typeid: String);
+    fn typeid_metadata(&mut self, typeid: String) -> Self::Value;
 
     fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;
     fn store_with_flags(
index 777436ad2ae8fd9290405e131d2c15361958a25d..78bf22ef9f2e2066c5ee3d9202c857d80e04b719 100644 (file)
@@ -24,6 +24,8 @@ fn codegen_intrinsic_call(
     ///
     /// Currently has any effect only when LLVM versions prior to 12.0 are used as the backend.
     fn sideeffect(&mut self);
+    /// Trait method used to test whether a given pointer is associated with a type identifier.
+    fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value;
     /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in
     /// Rust defined C-variadic functions.
     fn va_start(&mut self, val: Self::Value) -> Self::Value;
index df4cc295fac5f420eb97061786f51e8e6cd509de..80551518d3c5d8bdbe10341d2fd5d98e8ec1dafb 100644 (file)
@@ -1,6 +1,5 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_middle::hir::map::blocks::FnLikeNode;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::Symbol;
@@ -44,8 +43,8 @@ fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
         } else {
             false
         }
-    } else if let Some(fn_like) = FnLikeNode::from_node(node) {
-        if fn_like.constness() == hir::Constness::Const {
+    } else if let Some(fn_kind) = node.fn_kind() {
+        if fn_kind.constness() == hir::Constness::Const {
             return true;
         }
 
index 202c9cad8eb53aa856336931f37acd700099b885..dacd8f7c12cfd50204f00037a4e3eec8049d5a29 100644 (file)
@@ -30,34 +30,25 @@ fn hook_special_const_fn(
         &mut self,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
-        is_const_fn: bool,
     ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
-        // The list of functions we handle here must be in sync with
-        // `is_lang_special_const_fn` in `transform/check_consts/mod.rs`.
+        // All `#[rustc_do_not_const_check]` functions should be hooked here.
         let def_id = instance.def_id();
 
-        if is_const_fn {
-            if Some(def_id) == self.tcx.lang_items().const_eval_select() {
-                // redirect to const_eval_select_ct
-                if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() {
-                    return Ok(Some(
-                        ty::Instance::resolve(
-                            *self.tcx,
-                            ty::ParamEnv::reveal_all(),
-                            const_eval_select,
-                            instance.substs,
-                        )
-                        .unwrap()
-                        .unwrap(),
-                    ));
-                }
+        if Some(def_id) == self.tcx.lang_items().const_eval_select() {
+            // redirect to const_eval_select_ct
+            if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() {
+                return Ok(Some(
+                    ty::Instance::resolve(
+                        *self.tcx,
+                        ty::ParamEnv::reveal_all(),
+                        const_eval_select,
+                        instance.substs,
+                    )
+                    .unwrap()
+                    .unwrap(),
+                ));
             }
-            return Ok(None);
-        }
-
-        if Some(def_id) == self.tcx.lang_items().panic_fn()
-            || Some(def_id) == self.tcx.lang_items().panic_str()
-            || Some(def_id) == self.tcx.lang_items().panic_display()
+        } else if Some(def_id) == self.tcx.lang_items().panic_display()
             || Some(def_id) == self.tcx.lang_items().begin_panic_fn()
         {
             // &str or &&str
@@ -72,9 +63,7 @@ fn hook_special_const_fn(
             let span = self.find_closest_untracked_caller_location();
             let (file, line, col) = self.location_triple_for_span(span);
             return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into());
-        } else if Some(def_id) == self.tcx.lang_items().panic_fmt()
-            || Some(def_id) == self.tcx.lang_items().begin_panic_fmt()
-        {
+        } else if Some(def_id) == self.tcx.lang_items().panic_fmt() {
             // For panic_fmt, call const_panic_fmt instead.
             if let Some(const_panic_fmt) = self.tcx.lang_items().const_panic_fmt() {
                 return Ok(Some(
@@ -276,31 +265,22 @@ fn find_mir_or_eval_fn(
 
         // Only check non-glue functions
         if let ty::InstanceDef::Item(def) = instance.def {
-            let mut is_const_fn = true;
-
             // Execution might have wandered off into other crates, so we cannot do a stability-
             // sensitive check here.  But we can at least rule out functions that are not const
             // at all.
             if !ecx.tcx.is_const_fn_raw(def.did) {
                 // allow calling functions marked with #[default_method_body_is_const].
                 if !ecx.tcx.has_attr(def.did, sym::default_method_body_is_const) {
-                    is_const_fn = false;
+                    // We certainly do *not* want to actually call the fn
+                    // though, so be sure we return here.
+                    throw_unsup_format!("calling non-const function `{}`", instance)
                 }
             }
 
-            // Some functions we support even if they are non-const -- but avoid testing
-            // that for const fn!
-            // `const_eval_select` is a const fn because it must use const trait bounds.
-            if let Some(new_instance) = ecx.hook_special_const_fn(instance, args, is_const_fn)? {
+            if let Some(new_instance) = ecx.hook_special_const_fn(instance, args)? {
                 // We call another const fn instead.
                 return Self::find_mir_or_eval_fn(ecx, new_instance, _abi, args, _ret, _unwind);
             }
-
-            if !is_const_fn {
-                // We certainly do *not* want to actually call the fn
-                // though, so be sure we return here.
-                throw_unsup_format!("calling non-const function `{}`", instance)
-            }
         }
         // This is a const fn. Call it.
         Ok(Some(ecx.load_mir(instance.def, None)?))
index d4cbba18029311bff2079acb73220ddb4d42bf62..b5e97ec8fe0f466e94fbd39520bda32633831dda 100644 (file)
@@ -80,10 +80,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         line: u32,
         col: u32,
     ) -> MPlaceTy<'tcx, M::PointerTag> {
-        let file =
-            self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not);
-        let line = Scalar::from_u32(line);
-        let col = Scalar::from_u32(col);
+        let loc_details = &self.tcx.sess.opts.debugging_opts.location_detail;
+        let file = if loc_details.file {
+            self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
+        } else {
+            // FIXME: This creates a new allocation each time. It might be preferable to
+            // perform this allocation only once, and re-use the `MPlaceTy`.
+            // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
+            self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not)
+        };
+        let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
+        let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
 
         // Allocate memory for `CallerLocation` struct.
         let loc_ty = self
index eb0fdebb665faa2bea8e83168f0700b8ce916d2d..a16388d5de21928f7d9bf4df269c7d9a0b9122a0 100644 (file)
@@ -35,7 +35,8 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 ty::Closure(def_id, substs)
                 | ty::Generator(def_id, substs, ..)
                 | ty::FnDef(def_id, substs) => {
-                    let unused_params = self.tcx.unused_generic_params(def_id);
+                    let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id));
+                    let unused_params = self.tcx.unused_generic_params(instance);
                     for (index, subst) in substs.into_iter().enumerate() {
                         let index = index
                             .try_into()
index 7ce40b319a1e59dcb7c4d27bb917355d41e188b1..f308e764e861d0422e76464c39014aea20b59d09 100644 (file)
@@ -13,6 +13,7 @@
 #![feature(exact_size_is_empty)]
 #![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
+#![feature(let_else)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
 #![feature(slice_ptr_get)]
index d704c4335c7540503b371e146fb38f31aaf7465a..3a5bc37b85ad6937da526276508e61b31da90e8c 100644 (file)
@@ -12,7 +12,6 @@
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
 use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
-use rustc_mir_dataflow::impls::MaybeMutBorrowedLocals;
 use rustc_mir_dataflow::{self, Analysis};
 use rustc_span::{sym, Span, Symbol};
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use std::ops::Deref;
 
 use super::ops::{self, NonConstOp, Status};
-use super::qualifs::{self, CustomEq, HasMutInterior, NeedsNonConstDrop};
+use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
 use super::resolver::FlowSensitiveAnalysis;
-use super::{is_lang_panic_fn, is_lang_special_const_fn, ConstCx, Qualif};
+use super::{ConstCx, Qualif};
 use crate::const_eval::is_unstable_const_fn;
 
-// We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated
-// through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals`
-// kills locals upon `StorageDead` because a local will never be used after a `StorageDead`.
-type IndirectlyMutableResults<'mir, 'tcx> =
-    rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>;
-
 type QualifResults<'mir, 'tcx, Q> =
     rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
 
 #[derive(Default)]
 pub struct Qualifs<'mir, 'tcx> {
     has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
-    needs_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
-    indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>,
+    needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
+    needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
 }
 
 impl Qualifs<'mir, 'tcx> {
-    pub fn indirectly_mutable(
+    /// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
+    ///
+    /// Only updates the cursor if absolutely necessary
+    pub fn needs_drop(
         &mut self,
         ccx: &'mir ConstCx<'mir, 'tcx>,
         local: Local,
         location: Location,
     ) -> bool {
-        let indirectly_mutable = self.indirectly_mutable.get_or_insert_with(|| {
-            let ConstCx { tcx, body, param_env, .. } = *ccx;
-
-            // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
-            // allowed in a const.
-            //
-            // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
-            // without breaking stable code?
-            MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env)
-                .unsound_ignore_borrow_on_drop()
+        let ty = ccx.body.local_decls[local].ty;
+        if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
+            return false;
+        }
+
+        let needs_drop = self.needs_drop.get_or_insert_with(|| {
+            let ConstCx { tcx, body, .. } = *ccx;
+
+            FlowSensitiveAnalysis::new(NeedsDrop, ccx)
                 .into_engine(tcx, &body)
-                .pass_name("const_qualification")
                 .iterate_to_fixpoint()
                 .into_results_cursor(&body)
         });
 
-        indirectly_mutable.seek_before_primary_effect(location);
-        indirectly_mutable.get().contains(local)
+        needs_drop.seek_before_primary_effect(location);
+        needs_drop.get().contains(local)
     }
 
-    /// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
+    /// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`.
     ///
     /// Only updates the cursor if absolutely necessary
-    pub fn needs_drop(
+    pub fn needs_non_const_drop(
         &mut self,
         ccx: &'mir ConstCx<'mir, 'tcx>,
         local: Local,
@@ -84,7 +78,7 @@ pub fn needs_drop(
             return false;
         }
 
-        let needs_drop = self.needs_drop.get_or_insert_with(|| {
+        let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| {
             let ConstCx { tcx, body, .. } = *ccx;
 
             FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
@@ -93,8 +87,8 @@ pub fn needs_drop(
                 .into_results_cursor(&body)
         });
 
-        needs_drop.seek_before_primary_effect(location);
-        needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+        needs_non_const_drop.seek_before_primary_effect(location);
+        needs_non_const_drop.get().contains(local)
     }
 
     /// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
@@ -121,7 +115,7 @@ pub fn has_mut_interior(
         });
 
         has_mut_interior.seek_before_primary_effect(location);
-        has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+        has_mut_interior.get().contains(local)
     }
 
     fn in_return_place(
@@ -167,12 +161,13 @@ fn in_return_place(
                     .into_results_cursor(&ccx.body);
 
                 cursor.seek_after_primary_effect(return_loc);
-                cursor.contains(RETURN_PLACE)
+                cursor.get().contains(RETURN_PLACE)
             }
         };
 
         ConstQualifs {
             needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
+            needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc),
             has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
             custom_eq,
             error_occured,
@@ -825,6 +820,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                         Binder::dummy(TraitPredicate {
                             trait_ref,
                             constness: ty::BoundConstness::ConstIfConst,
+                            polarity: ty::ImplPolarity::Positive,
                         }),
                     );
 
@@ -888,31 +884,27 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 }
 
                 // At this point, we are calling a function, `callee`, whose `DefId` is known...
-                if is_lang_special_const_fn(tcx, callee) {
-                    // `begin_panic` and `panic_display` are generic functions that accept
-                    // types other than str. Check to enforce that only str can be used in
-                    // const-eval.
-
-                    // const-eval of the `begin_panic` fn assumes the argument is `&str`
-                    if Some(callee) == tcx.lang_items().begin_panic_fn() {
-                        match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
-                            ty::Ref(_, ty, _) if ty.is_str() => (),
-                            _ => self.check_op(ops::PanicNonStr),
-                        }
-                    }
 
-                    // const-eval of the `panic_display` fn assumes the argument is `&&str`
-                    if Some(callee) == tcx.lang_items().panic_display() {
-                        match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
-                            ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
-                                {}
-                            _ => self.check_op(ops::PanicNonStr),
-                        }
+                // `begin_panic` and `panic_display` are generic functions that accept
+                // types other than str. Check to enforce that only str can be used in
+                // const-eval.
+
+                // const-eval of the `begin_panic` fn assumes the argument is `&str`
+                if Some(callee) == tcx.lang_items().begin_panic_fn() {
+                    match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
+                        ty::Ref(_, ty, _) if ty.is_str() => return,
+                        _ => self.check_op(ops::PanicNonStr),
                     }
+                }
 
-                    if is_lang_panic_fn(tcx, callee) {
-                        // run stability check on non-panic special const fns.
-                        return;
+                // const-eval of the `panic_display` fn assumes the argument is `&&str`
+                if Some(callee) == tcx.lang_items().panic_display() {
+                    match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
+                        ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
+                        {
+                            return;
+                        }
+                        _ => self.check_op(ops::PanicNonStr),
                     }
                 }
 
@@ -999,7 +991,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
             }
 
             // Forbid all `Drop` terminators unless the place being dropped is a local with no
-            // projections that cannot be `NeedsDrop`.
+            // projections that cannot be `NeedsNonConstDrop`.
             TerminatorKind::Drop { place: dropped_place, .. }
             | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
                 // If we are checking live drops after drop-elaboration, don't emit duplicate
@@ -1019,15 +1011,15 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                     return;
                 }
 
-                let needs_drop = if let Some(local) = dropped_place.as_local() {
+                let needs_non_const_drop = if let Some(local) = dropped_place.as_local() {
                     // Use the span where the local was declared as the span of the drop error.
                     err_span = self.body.local_decls[local].source_info.span;
-                    self.qualifs.needs_drop(self.ccx, local, location)
+                    self.qualifs.needs_non_const_drop(self.ccx, local, location)
                 } else {
                     true
                 };
 
-                if needs_drop {
+                if needs_non_const_drop {
                     self.check_op_spanned(
                         ops::LiveDrop { dropped_at: Some(terminator.source_info.span) },
                         err_span,
index 0a852282f8f2693600855ec3802d085e607a1227..dc44409d500a04384f3910b24200f34d34895151 100644 (file)
@@ -72,25 +72,6 @@ pub fn fn_sig(&self) -> Option<&'tcx hir::FnSig<'tcx>> {
     }
 }
 
-/// Returns `true` if this `DefId` points to one of the official `panic` lang items.
-pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
-    Some(def_id) == tcx.lang_items().panic_fn()
-        || Some(def_id) == tcx.lang_items().panic_str()
-        || Some(def_id) == tcx.lang_items().panic_display()
-        || Some(def_id) == tcx.lang_items().begin_panic_fn()
-        || Some(def_id) == tcx.lang_items().panic_fmt()
-        || Some(def_id) == tcx.lang_items().begin_panic_fmt()
-}
-
-/// Returns `true` if this `DefId` points to one of the lang items that will be handled differently
-/// in const_eval.
-pub fn is_lang_special_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
-    // We can allow calls to these functions because `hook_special_const_fn` in
-    // `const_eval/machine.rs` ensures the calls are handled specially.
-    // Keep in sync with what that function handles!
-    is_lang_panic_fn(tcx, def_id) || Some(def_id) == tcx.lang_items().const_eval_select()
-}
-
 pub fn rustc_allow_const_fn_unstable(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
index 1a8c8b1c78d0857ef323990cb26ba9bf63d6d6d5..7a2be3c3bad329c8675c500b61fa3288218cce9b 100644 (file)
@@ -97,7 +97,7 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Loc
                 // `src/test/ui/consts/control-flow/drop-pass.rs`; e.g., when an `Option<Vec<T>>` is
                 // initialized with `None` and never changed, it still emits drop glue.
                 // Hence we additionally check the qualifs here to allow more code to pass.
-                if self.qualifs.needs_drop(self.ccx, dropped_place.local, location) {
+                if self.qualifs.needs_non_const_drop(self.ccx, dropped_place.local, location) {
                     // Use the span where the dropped local was declared for the error.
                     let span = self.body.local_decls[dropped_place.local].source_info.span;
                     self.check_live_drop(span);
index 5eb7d7a91cc76d5aeec900c92f91fae4e038c6f6..0fdb772c262dddbbe774fa948551a5c1a5e9e565 100644 (file)
@@ -21,7 +21,8 @@ pub fn in_any_value_of_ty(
 ) -> ConstQualifs {
     ConstQualifs {
         has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
-        needs_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty),
+        needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
+        needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty),
         custom_eq: CustomEq::in_any_value_of_ty(cx, ty),
         error_occured,
     }
@@ -45,6 +46,9 @@ pub trait Qualif {
     /// Whether this `Qualif` is cleared when a local is moved from.
     const IS_CLEARED_ON_MOVE: bool = false;
 
+    /// Whether this `Qualif` might be evaluated after the promotion and can encounter a promoted.
+    const ALLOW_PROMOTED: bool = false;
+
     /// Extracts the field of `ConstQualifs` that corresponds to this `Qualif`.
     fn in_qualifs(qualifs: &ConstQualifs) -> bool;
 
@@ -98,17 +102,40 @@ fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tc
 }
 
 /// Constant containing an ADT that implements `Drop`.
-/// This must be ruled out (a) because we cannot run `Drop` during compile-time
-/// as that might not be a `const fn`, and (b) because implicit promotion would
-/// remove side-effects that occur as part of dropping that value.
+/// This must be ruled out because implicit promotion would remove side-effects
+/// that occur as part of dropping that value. N.B., the implicit promotion has
+/// to reject const Drop implementations because even if side-effects are ruled
+/// out through other means, the execution of the drop could diverge.
+pub struct NeedsDrop;
+
+impl Qualif for NeedsDrop {
+    const ANALYSIS_NAME: &'static str = "flow_needs_drop";
+    const IS_CLEARED_ON_MOVE: bool = true;
+
+    fn in_qualifs(qualifs: &ConstQualifs) -> bool {
+        qualifs.needs_drop
+    }
+
+    fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
+        ty.needs_drop(cx.tcx, cx.param_env)
+    }
+
+    fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {
+        adt.has_dtor(cx.tcx)
+    }
+}
+
+/// Constant containing an ADT that implements non-const `Drop`.
+/// This must be ruled out because we cannot run `Drop` during compile-time.
 pub struct NeedsNonConstDrop;
 
 impl Qualif for NeedsNonConstDrop {
     const ANALYSIS_NAME: &'static str = "flow_needs_nonconst_drop";
     const IS_CLEARED_ON_MOVE: bool = true;
+    const ALLOW_PROMOTED: bool = true;
 
     fn in_qualifs(qualifs: &ConstQualifs) -> bool {
-        qualifs.needs_drop
+        qualifs.needs_non_const_drop
     }
 
     fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool {
@@ -122,9 +149,7 @@ fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool {
             Ok([..]) => {}
         }
 
-        let drop_trait = if let Some(did) = cx.tcx.lang_items().drop_trait() {
-            did
-        } else {
+        let Some(drop_trait) = cx.tcx.lang_items().drop_trait() else {
             // there is no way to define a type that needs non-const drop
             // without having the lang item present.
             return false;
@@ -137,6 +162,7 @@ fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool {
             ty::Binder::dummy(ty::TraitPredicate {
                 trait_ref,
                 constness: ty::BoundConstness::ConstIfConst,
+                polarity: ty::ImplPolarity::Positive,
             }),
         );
 
@@ -232,6 +258,9 @@ pub fn in_rvalue<Q, F>(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, rvalue: &Rvalue
                 if Q::in_adt_inherently(cx, def, substs) {
                     return true;
                 }
+                if def.is_union() && Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) {
+                    return true;
+                }
             }
 
             // Otherwise, proceed structurally...
@@ -289,9 +318,12 @@ pub fn in_operand<Q, F>(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, operand: &Oper
     // 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 {
-            assert!(promoted.is_none());
+            // 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.
+            assert!(promoted.is_none() || Q::ALLOW_PROMOTED);
             // Don't peek inside trait associated constants.
-            if cx.tcx.trait_of_item(def.did).is_none() {
+            if promoted.is_none() && cx.tcx.trait_of_item(def.did).is_none() {
                 let qualifs = if let Some((did, param_did)) = def.as_const_arg() {
                     cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did))
                 } else {
index 8e1b69a1d7413e48215c3ddf798f02d1929f501f..fcce829eba4121a23c0f0336cd0023ec2310b6dd 100644 (file)
@@ -4,8 +4,12 @@
 
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{self, BasicBlock, Local, Location};
+use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementKind};
+use rustc_mir_dataflow::fmt::DebugWithContext;
+use rustc_mir_dataflow::JoinSemiLattice;
+use rustc_span::DUMMY_SP;
 
+use std::fmt;
 use std::marker::PhantomData;
 
 use super::{qualifs, ConstCx, Qualif};
 /// A `Visitor` that propagates qualifs between locals. This defines the transfer function of
 /// `FlowSensitiveAnalysis`.
 ///
-/// This transfer does nothing when encountering an indirect assignment. Consumers should rely on
-/// the `MaybeMutBorrowedLocals` dataflow pass to see if a `Local` may have become qualified via
-/// an indirect assignment or function call.
+/// To account for indirect assignments, data flow conservatively assumes that local becomes
+/// qualified immediately after it is borrowed or its address escapes. The borrow must allow for
+/// mutation, which includes shared borrows of places with interior mutability. The type of
+/// borrowed place must contain the qualif.
 struct TransferFunction<'a, 'mir, 'tcx, Q> {
     ccx: &'a ConstCx<'mir, 'tcx>,
-    qualifs_per_local: &'a mut BitSet<Local>,
-
+    state: &'a mut State,
     _qualif: PhantomData<Q>,
 }
 
@@ -27,27 +31,38 @@ impl<Q> TransferFunction<'a, 'mir, 'tcx, Q>
 where
     Q: Qualif,
 {
-    fn new(ccx: &'a ConstCx<'mir, 'tcx>, qualifs_per_local: &'a mut BitSet<Local>) -> Self {
-        TransferFunction { ccx, qualifs_per_local, _qualif: PhantomData }
+    fn new(ccx: &'a ConstCx<'mir, 'tcx>, state: &'a mut State) -> Self {
+        TransferFunction { ccx, state, _qualif: PhantomData }
     }
 
     fn initialize_state(&mut self) {
-        self.qualifs_per_local.clear();
+        self.state.qualif.clear();
+        self.state.borrow.clear();
 
         for arg in self.ccx.body.args_iter() {
             let arg_ty = self.ccx.body.local_decls[arg].ty;
             if Q::in_any_value_of_ty(self.ccx, arg_ty) {
-                self.qualifs_per_local.insert(arg);
+                self.state.qualif.insert(arg);
             }
         }
     }
 
-    fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) {
+    fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, mut value: bool) {
         debug_assert!(!place.is_indirect());
 
+        if !value {
+            for (base, _elem) in place.iter_projections() {
+                let base_ty = base.ty(self.ccx.body, self.ccx.tcx);
+                if base_ty.ty.is_union() && Q::in_any_value_of_ty(self.ccx, base_ty.ty) {
+                    value = true;
+                    break;
+                }
+            }
+        }
+
         match (value, place.as_ref()) {
             (true, mir::PlaceRef { local, .. }) => {
-                self.qualifs_per_local.insert(local);
+                self.state.qualif.insert(local);
             }
 
             // For now, we do not clear the qualif if a local is overwritten in full by
@@ -55,7 +70,7 @@ fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) {
             // with aggregates where we overwrite all fields with assignments, which would not
             // get this feature.
             (false, mir::PlaceRef { local: _, projection: &[] }) => {
-                // self.qualifs_per_local.remove(*local);
+                // self.state.qualif.remove(*local);
             }
 
             _ => {}
@@ -78,6 +93,37 @@ fn apply_call_return_effect(
             self.assign_qualif_direct(&return_place, qualif);
         }
     }
+
+    fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool {
+        // Exact set of permissions granted by AddressOf is undecided. Conservatively assume that
+        // it might allow mutation until resolution of #56604.
+        true
+    }
+
+    fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
+        match kind {
+            mir::BorrowKind::Mut { .. } => true,
+            mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
+                self.shared_borrow_allows_mutation(place)
+            }
+        }
+    }
+
+    /// `&` only allow mutation if the borrowed place is `!Freeze`.
+    ///
+    /// This assumes that it is UB to take the address of a struct field whose type is
+    /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
+    /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
+    /// have to check the type of the borrowed **local** instead of the borrowed **place**
+    /// below. See [rust-lang/unsafe-code-guidelines#134].
+    ///
+    /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
+    fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
+        !place
+            .ty(self.ccx.body, self.ccx.tcx)
+            .ty
+            .is_freeze(self.ccx.tcx.at(DUMMY_SP), self.ccx.param_env)
+    }
 }
 
 impl<Q> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q>
@@ -95,7 +141,12 @@ fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
         // it no longer needs to be dropped.
         if let mir::Operand::Move(place) = operand {
             if let Some(local) = place.as_local() {
-                self.qualifs_per_local.remove(local);
+                // For backward compatibility with the MaybeMutBorrowedLocals used in an earlier
+                // implementation we retain qualif if a local had been borrowed before. This might
+                // not be strictly necessary since the local is no longer initialized.
+                if !self.state.borrow.contains(local) {
+                    self.state.qualif.remove(local);
+                }
             }
         }
     }
@@ -106,11 +157,8 @@ fn visit_assign(
         rvalue: &mir::Rvalue<'tcx>,
         location: Location,
     ) {
-        let qualif = qualifs::in_rvalue::<Q, _>(
-            self.ccx,
-            &mut |l| self.qualifs_per_local.contains(l),
-            rvalue,
-        );
+        let qualif =
+            qualifs::in_rvalue::<Q, _>(self.ccx, &mut |l| self.state.qualif.contains(l), rvalue);
         if !place.is_indirect() {
             self.assign_qualif_direct(place, qualif);
         }
@@ -120,6 +168,58 @@ fn visit_assign(
         self.super_assign(place, rvalue, location);
     }
 
+    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
+        self.super_rvalue(rvalue, location);
+
+        match rvalue {
+            mir::Rvalue::AddressOf(mt, borrowed_place) => {
+                if !borrowed_place.is_indirect()
+                    && self.address_of_allows_mutation(*mt, *borrowed_place)
+                {
+                    let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
+                    if Q::in_any_value_of_ty(self.ccx, place_ty) {
+                        self.state.qualif.insert(borrowed_place.local);
+                        self.state.borrow.insert(borrowed_place.local);
+                    }
+                }
+            }
+
+            mir::Rvalue::Ref(_, kind, borrowed_place) => {
+                if !borrowed_place.is_indirect() && self.ref_allows_mutation(*kind, *borrowed_place)
+                {
+                    let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
+                    if Q::in_any_value_of_ty(self.ccx, place_ty) {
+                        self.state.qualif.insert(borrowed_place.local);
+                        self.state.borrow.insert(borrowed_place.local);
+                    }
+                }
+            }
+
+            mir::Rvalue::Cast(..)
+            | mir::Rvalue::ShallowInitBox(..)
+            | mir::Rvalue::Use(..)
+            | mir::Rvalue::ThreadLocalRef(..)
+            | mir::Rvalue::Repeat(..)
+            | mir::Rvalue::Len(..)
+            | mir::Rvalue::BinaryOp(..)
+            | mir::Rvalue::CheckedBinaryOp(..)
+            | mir::Rvalue::NullaryOp(..)
+            | mir::Rvalue::UnaryOp(..)
+            | mir::Rvalue::Discriminant(..)
+            | mir::Rvalue::Aggregate(..) => {}
+        }
+    }
+
+    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
+        match statement.kind {
+            StatementKind::StorageDead(local) => {
+                self.state.qualif.remove(local);
+                self.state.borrow.remove(local);
+            }
+            _ => self.super_statement(statement, location),
+        }
+    }
+
     fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
         // The effect of assignment to the return place in `TerminatorKind::Call` is not applied
         // here; that occurs in `apply_call_return_effect`.
@@ -127,7 +227,7 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Loc
         if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind {
             let qualif = qualifs::in_operand::<Q, _>(
                 self.ccx,
-                &mut |l| self.qualifs_per_local.contains(l),
+                &mut |l| self.state.qualif.contains(l),
                 value,
             );
 
@@ -136,6 +236,9 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Loc
             }
         }
 
+        // We ignore borrow on drop because custom drop impls are not allowed in consts.
+        // FIXME: Reconsider if accounting for borrows in drops is necessary for const drop.
+
         // We need to assign qualifs to the dropped location before visiting the operand that
         // replaces it since qualifs can be cleared on move.
         self.super_terminator(terminator, location);
@@ -156,24 +259,76 @@ pub(super) fn new(_: Q, ccx: &'a ConstCx<'mir, 'tcx>) -> Self {
         FlowSensitiveAnalysis { ccx, _qualif: PhantomData }
     }
 
-    fn transfer_function(
-        &self,
-        state: &'a mut BitSet<Local>,
-    ) -> TransferFunction<'a, 'mir, 'tcx, Q> {
+    fn transfer_function(&self, state: &'a mut State) -> TransferFunction<'a, 'mir, 'tcx, Q> {
         TransferFunction::<Q>::new(self.ccx, state)
     }
 }
 
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(super) struct State {
+    /// Describes whether a local contains qualif.
+    pub qualif: BitSet<Local>,
+    /// Describes whether a local's address escaped and it might become qualified as a result an
+    /// indirect mutation.
+    pub borrow: BitSet<Local>,
+}
+
+impl State {
+    #[inline]
+    pub(super) fn contains(&self, local: Local) -> bool {
+        self.qualif.contains(local)
+    }
+}
+
+impl<C> DebugWithContext<C> for State {
+    fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("qualif: ")?;
+        self.qualif.fmt_with(ctxt, f)?;
+        f.write_str(" borrow: ")?;
+        self.borrow.fmt_with(ctxt, f)?;
+        Ok(())
+    }
+
+    fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self == old {
+            return Ok(());
+        }
+
+        if self.qualif != old.qualif {
+            f.write_str("qualif: ")?;
+            self.qualif.fmt_diff_with(&old.qualif, ctxt, f)?;
+            f.write_str("\n")?;
+        }
+
+        if self.borrow != old.borrow {
+            f.write_str("borrow: ")?;
+            self.qualif.fmt_diff_with(&old.borrow, ctxt, f)?;
+            f.write_str("\n")?;
+        }
+
+        Ok(())
+    }
+}
+
+impl JoinSemiLattice for State {
+    fn join(&mut self, other: &Self) -> bool {
+        self.qualif.join(&other.qualif) || self.borrow.join(&other.borrow)
+    }
+}
+
 impl<Q> rustc_mir_dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
 where
     Q: Qualif,
 {
-    type Domain = BitSet<Local>;
+    type Domain = State;
 
     const NAME: &'static str = Q::ANALYSIS_NAME;
 
     fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
-        BitSet::new_empty(body.local_decls.len())
+        State {
+            qualif: BitSet::new_empty(body.local_decls.len()),
+            borrow: BitSet::new_empty(body.local_decls.len()),
+        }
     }
 
     fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) {
index 7cfe3d7f809e923e3bd1e59eeea6683c6840877c..7bf378601e053317963dcdc036129b94c05be7e3 100644 (file)
@@ -26,7 +26,7 @@
 use std::cell::Cell;
 use std::{cmp, iter, mem};
 
-use crate::transform::check_consts::{is_lang_special_const_fn, qualifs, ConstCx};
+use crate::transform::check_consts::{qualifs, ConstCx};
 use crate::transform::MirPass;
 
 /// A `MirPass` for promotion.
@@ -230,7 +230,7 @@ fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
 
                         // We cannot promote things that need dropping, since the promoted value
                         // would not get dropped.
-                        if self.qualif_local::<qualifs::NeedsNonConstDrop>(place.local) {
+                        if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
                             return Err(Unpromotable);
                         }
 
@@ -656,9 +656,7 @@ fn validate_call(
         }
 
         let is_const_fn = match *fn_ty.kind() {
-            ty::FnDef(def_id, _) => {
-                self.tcx.is_const_fn_raw(def_id) || is_lang_special_const_fn(self.tcx, def_id)
-            }
+            ty::FnDef(def_id, _) => self.tcx.is_const_fn_raw(def_id),
             _ => false,
         };
         if !is_const_fn {
@@ -837,11 +835,7 @@ fn promote_temp(&mut self, temp: Local) -> Local {
         new_temp
     }
 
-    fn promote_candidate(
-        mut self,
-        candidate: Candidate,
-        next_promoted_id: usize,
-    ) -> Option<Body<'tcx>> {
+    fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) -> Body<'tcx> {
         let def = self.source.source.with_opt_param();
         let mut rvalue = {
             let promoted = &mut self.promoted;
@@ -940,7 +934,7 @@ fn promote_candidate(
 
         let span = self.promoted.span;
         self.assign(RETURN_PLACE, rvalue, span);
-        Some(self.promoted)
+        self.promoted
     }
 }
 
@@ -1013,11 +1007,9 @@ pub fn promote_candidates<'tcx>(
             keep_original: false,
         };
 
-        //FIXME(oli-obk): having a `maybe_push()` method on `IndexVec` might be nice
-        if let Some(mut promoted) = promoter.promote_candidate(candidate, promotions.len()) {
-            promoted.source.promoted = Some(promotions.next_index());
-            promotions.push(promoted);
-        }
+        let mut promoted = promoter.promote_candidate(candidate, promotions.len());
+        promoted.source.promoted = Some(promotions.next_index());
+        promotions.push(promoted);
     }
 
     // Insert each of `extra_statements` before its indicated location, which
index 49962570129704a91392ec7117e379e53d0aa040..e3395df35908c847c1c83f6fa5501483a828ece0 100644 (file)
@@ -23,7 +23,7 @@ rustc-hash = "1.1.0"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_index = { path = "../rustc_index", package = "rustc_index" }
 bitflags = "1.2.1"
-measureme = "9.1.0"
+measureme = "10.0.0"
 libc = "0.2"
 stacker = "0.1.14"
 tempfile = "3.2"
index 81e2501ecbeadeb8732d808e9940f10f8b336636..3c7bea27124096f35fd2cda702e5cb7ccc930b96 100644 (file)
@@ -14,7 +14,7 @@
 
 #[inline]
 pub fn push_str(mut n: u128, base: usize, output: &mut String) {
-    debug_assert!((2..=MAX_BASE).contains(&base));
+    debug_assert!(base >= 2 && base <= MAX_BASE);
     let mut s = [0u8; 128];
     let mut index = 0;
 
index 9ff401c3c7aad19d78a73c057b4001bce31d123e..1aa7ac024d94e239d2acd5275dadd2515585e6e0 100644 (file)
@@ -206,11 +206,17 @@ pub fn adjacent_edges(
         AdjacentEdges { graph: self, direction, next: first_edge }
     }
 
-    pub fn successor_nodes(&self, source: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ {
+    pub fn successor_nodes<'a>(
+        &'a self,
+        source: NodeIndex,
+    ) -> impl Iterator<Item = NodeIndex> + 'a {
         self.outgoing_edges(source).targets()
     }
 
-    pub fn predecessor_nodes(&self, target: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ {
+    pub fn predecessor_nodes<'a>(
+        &'a self,
+        target: NodeIndex,
+    ) -> impl Iterator<Item = NodeIndex> + 'a {
         self.incoming_edges(target).sources()
     }
 
index 1c6979dc489a6ad979d5deb9fca0bc4342ea6326..a9db3497b23908a50548e9a24ab74f189feed37d 100644 (file)
@@ -48,7 +48,7 @@ struct PostOrderFrame<Node, Iter> {
         let node = frame.node;
         visited[node] = true;
 
-        for successor in frame.iter.by_ref() {
+        while let Some(successor) = frame.iter.next() {
             if !visited[successor] {
                 stack.push(PostOrderFrame { node: successor, iter: graph.successors(successor) });
                 continue 'recurse;
@@ -112,7 +112,7 @@ pub fn push_start_node(&mut self, start_node: G::Node) {
     /// This is equivalent to just invoke `next` repeatedly until
     /// you get a `None` result.
     pub fn complete_search(&mut self) {
-        for _ in self {}
+        while let Some(_) = self.next() {}
     }
 
     /// Returns true if node has been visited thus far.
index 94e115ed498564ae4cdc81be69a8be8222016ac0..77784bf1705234d0018ef5aca044267902dd6735 100644 (file)
@@ -11,7 +11,6 @@
 #![feature(associated_type_bounds)]
 #![feature(auto_traits)]
 #![feature(bool_to_option)]
-#![cfg_attr(bootstrap, feature(const_panic))]
 #![feature(control_flow_enum)]
 #![feature(core_intrinsics)]
 #![feature(extend_one)]
index caf515b0d192a5331ed9067da1a366049a29c335..25b7a84b3a06929fa5c0df1c8f1c3f92848727e0 100644 (file)
@@ -390,7 +390,7 @@ pub fn to_errors<E: Clone>(&mut self, error: E) -> Vec<Error<O, E>> {
             .map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) })
             .collect();
 
-        self.compress(|_| unreachable!());
+        self.compress(|_| assert!(false));
         errors
     }
 
@@ -612,7 +612,7 @@ fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, in
     fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) {
         let orig_nodes_len = self.nodes.len();
         let mut node_rewrites: Vec<_> = std::mem::take(&mut self.reused_node_vec);
-        assert!(node_rewrites.is_empty());
+        debug_assert!(node_rewrites.is_empty());
         node_rewrites.extend(0..orig_nodes_len);
         let mut dead_nodes = 0;
 
@@ -623,13 +623,13 @@ fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) {
         //     self.nodes[0..index - dead_nodes] are the first remaining nodes
         //     self.nodes[index - dead_nodes..index] are all dead
         //     self.nodes[index..] are unchanged
-        for (index, node_rewrite) in node_rewrites.iter_mut().enumerate() {
+        for index in 0..orig_nodes_len {
             let node = &self.nodes[index];
             match node.state.get() {
                 NodeState::Pending | NodeState::Waiting => {
                     if dead_nodes > 0 {
                         self.nodes.swap(index, index - dead_nodes);
-                        *node_rewrite -= dead_nodes;
+                        node_rewrites[index] -= dead_nodes;
                     }
                 }
                 NodeState::Done => {
@@ -646,7 +646,7 @@ fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) {
                     }
                     // Extract the success stories.
                     outcome_cb(&node.obligation);
-                    *node_rewrite = orig_nodes_len;
+                    node_rewrites[index] = orig_nodes_len;
                     dead_nodes += 1;
                 }
                 NodeState::Error => {
@@ -655,7 +655,7 @@ fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) {
                     // check against.
                     self.active_cache.remove(&node.obligation.as_cache_key());
                     self.insert_into_error_cache(index);
-                    *node_rewrite = orig_nodes_len;
+                    node_rewrites[index] = orig_nodes_len;
                     dead_nodes += 1;
                 }
                 NodeState::Success => unreachable!(),
index 0bbd0eda0c6e1cdd0130013c598eb0c83a395b6b..c21939209fc3bfecb7fcea268f8d0900273402ea 100644 (file)
@@ -110,12 +110,14 @@ struct EventFilter: u32 {
         const FUNCTION_ARGS       = 1 << 6;
         const LLVM                = 1 << 7;
         const INCR_RESULT_HASHING = 1 << 8;
+        const ARTIFACT_SIZES = 1 << 9;
 
         const DEFAULT = Self::GENERIC_ACTIVITIES.bits |
                         Self::QUERY_PROVIDERS.bits |
                         Self::QUERY_BLOCKED.bits |
                         Self::INCR_CACHE_LOADS.bits |
-                        Self::INCR_RESULT_HASHING.bits;
+                        Self::INCR_RESULT_HASHING.bits |
+                        Self::ARTIFACT_SIZES.bits;
 
         const ARGS = Self::QUERY_KEYS.bits | Self::FUNCTION_ARGS.bits;
     }
@@ -136,6 +138,7 @@ struct EventFilter: u32 {
     ("args", EventFilter::ARGS),
     ("llvm", EventFilter::LLVM),
     ("incr-result-hashing", EventFilter::INCR_RESULT_HASHING),
+    ("artifact-sizes", EventFilter::ARTIFACT_SIZES),
 ];
 
 /// Something that uniquely identifies a query invocation.
@@ -285,6 +288,33 @@ pub fn generic_activity_with_arg<A>(
         })
     }
 
+    /// Record the size of an artifact that the compiler produces
+    ///
+    /// `artifact_kind` is the class of artifact (e.g., query_cache, object_file, etc.)
+    /// `artifact_name` is an identifier to the specific artifact being stored (usually a filename)
+    #[inline(always)]
+    pub fn artifact_size<A>(&self, artifact_kind: &str, artifact_name: A, size: u64)
+    where
+        A: Borrow<str> + Into<String>,
+    {
+        drop(self.exec(EventFilter::ARTIFACT_SIZES, |profiler| {
+            let builder = EventIdBuilder::new(&profiler.profiler);
+            let event_label = profiler.get_or_alloc_cached_string(artifact_kind);
+            let event_arg = profiler.get_or_alloc_cached_string(artifact_name);
+            let event_id = builder.from_label_and_arg(event_label, event_arg);
+            let thread_id = get_thread_id();
+
+            profiler.profiler.record_integer_event(
+                profiler.artifact_size_event_kind,
+                event_id,
+                thread_id,
+                size,
+            );
+
+            TimingGuard::none()
+        }))
+    }
+
     #[inline(always)]
     pub fn generic_activity_with_args(
         &self,
@@ -372,7 +402,7 @@ fn instant_query_event(
     ) {
         drop(self.exec(event_filter, |profiler| {
             let event_id = StringId::new_virtual(query_invocation_id.0);
-            let thread_id = std::thread::current().id().as_u64().get() as u32;
+            let thread_id = get_thread_id();
 
             profiler.profiler.record_instant_event(
                 event_kind(profiler),
@@ -425,6 +455,7 @@ pub struct SelfProfiler {
     incremental_result_hashing_event_kind: StringId,
     query_blocked_event_kind: StringId,
     query_cache_hit_event_kind: StringId,
+    artifact_size_event_kind: StringId,
 }
 
 impl SelfProfiler {
@@ -447,6 +478,7 @@ pub fn new(
             profiler.alloc_string("IncrementalResultHashing");
         let query_blocked_event_kind = profiler.alloc_string("QueryBlocked");
         let query_cache_hit_event_kind = profiler.alloc_string("QueryCacheHit");
+        let artifact_size_event_kind = profiler.alloc_string("ArtifactSize");
 
         let mut event_filter_mask = EventFilter::empty();
 
@@ -491,6 +523,7 @@ pub fn new(
             incremental_result_hashing_event_kind,
             query_blocked_event_kind,
             query_cache_hit_event_kind,
+            artifact_size_event_kind,
         })
     }
 
@@ -561,7 +594,7 @@ pub fn start(
         event_kind: StringId,
         event_id: EventId,
     ) -> TimingGuard<'a> {
-        let thread_id = std::thread::current().id().as_u64().get() as u32;
+        let thread_id = get_thread_id();
         let raw_profiler = &profiler.profiler;
         let timing_guard =
             raw_profiler.start_recording_interval_event(event_kind, event_id, thread_id);
@@ -655,6 +688,10 @@ pub fn duration_to_secs_str(dur: std::time::Duration) -> String {
     format!("{:.3}", dur.as_secs_f64())
 }
 
+fn get_thread_id() -> u32 {
+    std::thread::current().id().as_u64().get() as u32
+}
+
 // Memory reporting
 cfg_if! {
     if #[cfg(windows)] {
index e80db0845a7be405a04b5c3c1ca4d543b8a731d0..9efea1228ab29e8ad42783aee9adc7165ef2f5a8 100644 (file)
@@ -1,3 +1,4 @@
+use crate::stable_hasher::{HashStable, StableHasher};
 use std::borrow::Borrow;
 use std::cmp::Ordering;
 use std::iter::FromIterator;
 /// stores data in a more compact way. It also supports accessing contiguous
 /// ranges of elements as a slice, and slices of already sorted elements can be
 /// inserted efficiently.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encodable, Decodable)]
-pub struct SortedMap<K: Ord, V> {
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
+pub struct SortedMap<K, V> {
     data: Vec<(K, V)>,
 }
 
-impl<K: Ord, V> SortedMap<K, V> {
+impl<K, V> Default for SortedMap<K, V> {
+    #[inline]
+    fn default() -> SortedMap<K, V> {
+        SortedMap { data: Vec::new() }
+    }
+}
+
+impl<K, V> SortedMap<K, V> {
     #[inline]
-    pub fn new() -> SortedMap<K, V> {
-        SortedMap { data: vec![] }
+    pub const fn new() -> SortedMap<K, V> {
+        SortedMap { data: Vec::new() }
     }
+}
 
+impl<K: Ord, V> SortedMap<K, V> {
     /// Construct a `SortedMap` from a presorted set of elements. This is faster
     /// than creating an empty map and then inserting the elements individually.
     ///
@@ -205,10 +215,10 @@ fn range_slice_indices<R>(&self, range: R) -> (usize, usize)
         R: RangeBounds<K>,
     {
         let start = match range.start_bound() {
-            Bound::Included(k) => match self.lookup_index_for(k) {
+            Bound::Included(ref k) => match self.lookup_index_for(k) {
                 Ok(index) | Err(index) => index,
             },
-            Bound::Excluded(k) => match self.lookup_index_for(k) {
+            Bound::Excluded(ref k) => match self.lookup_index_for(k) {
                 Ok(index) => index + 1,
                 Err(index) => index,
             },
@@ -216,11 +226,11 @@ fn range_slice_indices<R>(&self, range: R) -> (usize, usize)
         };
 
         let end = match range.end_bound() {
-            Bound::Included(k) => match self.lookup_index_for(k) {
+            Bound::Included(ref k) => match self.lookup_index_for(k) {
                 Ok(index) => index + 1,
                 Err(index) => index,
             },
-            Bound::Excluded(k) => match self.lookup_index_for(k) {
+            Bound::Excluded(ref k) => match self.lookup_index_for(k) {
                 Ok(index) | Err(index) => index,
             },
             Bound::Unbounded => self.data.len(),
@@ -281,5 +291,12 @@ fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
     }
 }
 
+impl<K: HashStable<CTX>, V: HashStable<CTX>, CTX> HashStable<CTX> for SortedMap<K, V> {
+    #[inline]
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        self.data.hash_stable(ctx, hasher);
+    }
+}
+
 #[cfg(test)]
 mod tests;
index 1395bb16e875c62ef81f909792ed5e3745322ee2..e92db9ea128057f4c82556a55ff27d3d728aafb0 100644 (file)
@@ -75,7 +75,7 @@ pub fn get(&self, idx: I) -> Option<&(K, V)> {
     ///
     /// If there are multiple items that are equivalent to `key`, they will be yielded in
     /// insertion order.
-    pub fn get_by_key(&self, key: K) -> impl Iterator<Item = &V> {
+    pub fn get_by_key(&'a self, key: K) -> impl 'a + Iterator<Item = &'a V> {
         self.get_by_key_enumerated(key).map(|(_, v)| v)
     }
 
@@ -84,7 +84,7 @@ pub fn get_by_key(&self, key: K) -> impl Iterator<Item = &V> {
     ///
     /// If there are multiple items that are equivalent to `key`, they will be yielded in
     /// insertion order.
-    pub fn get_by_key_enumerated(&self, key: K) -> impl Iterator<Item = (I, &V)> {
+    pub fn get_by_key_enumerated(&'a self, key: K) -> impl '_ + Iterator<Item = (I, &V)> {
         let lower_bound = self.idx_sorted_by_item_key.partition_point(|&i| self.items[i].0 < key);
         self.idx_sorted_by_item_key[lower_bound..].iter().map_while(move |&i| {
             let (k, v) = &self.items[i];
index d4274e99f1cffc071184bd34a12054dc7815d494..2de05cd4e56794180ae27b5fb476bed3f07e101c 100644 (file)
@@ -257,7 +257,11 @@ pub fn insert(&mut self, key: K, value: V) -> Option<V> {
     pub fn remove(&mut self, key: &K) -> Option<V> {
         match self {
             SsoHashMap::Array(array) => {
-                array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index).1)
+                if let Some(index) = array.iter().position(|(k, _v)| k == key) {
+                    Some(array.swap_remove(index).1)
+                } else {
+                    None
+                }
             }
             SsoHashMap::Map(map) => map.remove(key),
         }
@@ -268,7 +272,11 @@ pub fn remove(&mut self, key: &K) -> Option<V> {
     pub fn remove_entry(&mut self, key: &K) -> Option<(K, V)> {
         match self {
             SsoHashMap::Array(array) => {
-                array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index))
+                if let Some(index) = array.iter().position(|(k, _v)| k == key) {
+                    Some(array.swap_remove(index))
+                } else {
+                    None
+                }
             }
             SsoHashMap::Map(map) => map.remove_entry(key),
         }
@@ -415,14 +423,14 @@ fn into_iter(self) -> Self::IntoIter {
 
 /// adapts Item of array reference iterator to Item of hashmap reference iterator.
 #[inline(always)]
-fn adapt_array_ref_it<K, V>(pair: &(K, V)) -> (&K, &V) {
+fn adapt_array_ref_it<K, V>(pair: &'a (K, V)) -> (&'a K, &'a V) {
     let (a, b) = pair;
     (a, b)
 }
 
 /// adapts Item of array mut reference iterator to Item of hashmap mut reference iterator.
 #[inline(always)]
-fn adapt_array_mut_it<K, V>(pair: &mut (K, V)) -> (&K, &mut V) {
+fn adapt_array_mut_it<K, V>(pair: &'a mut (K, V)) -> (&'a K, &'a mut V) {
     let (a, b) = pair;
     (a, b)
 }
index f71522d37148ad8b86217000570356f4b0540a2b..29baf4e1ddb661c4a4a421e9c58e3b0a81e50afc 100644 (file)
@@ -75,7 +75,7 @@ pub fn is_empty(&self) -> bool {
     /// An iterator visiting all elements in arbitrary order.
     /// The iterator element type is `&'a T`.
     #[inline]
-    pub fn iter(&self) -> impl Iterator<Item = &T> {
+    pub fn iter(&'a self) -> impl Iterator<Item = &'a T> {
         self.into_iter()
     }
 
index 2e992e762273c1c3b1fab6dd6a2ab2df273e7ee9..f800ec6a6a12c49425d69ae8fbe8d3c65cae82c4 100644 (file)
@@ -229,14 +229,14 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
 
 impl<CTX> HashStable<CTX> for f32 {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        let val: u32 = self.to_bits();
+        let val: u32 = unsafe { ::std::mem::transmute(*self) };
         val.hash_stable(ctx, hasher);
     }
 }
 
 impl<CTX> HashStable<CTX> for f64 {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        let val: u64 = self.to_bits();
+        let val: u64 = unsafe { ::std::mem::transmute(*self) };
         val.hash_stable(ctx, hasher);
     }
 }
@@ -301,6 +301,13 @@ impl<T: HashStable<CTX>, CTX> HashStable<CTX> for [T] {
     }
 }
 
+impl<CTX> HashStable<CTX> for [u8] {
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        self.len().hash_stable(ctx, hasher);
+        hasher.write(self);
+    }
+}
+
 impl<T: HashStable<CTX>, CTX> HashStable<CTX> for Vec<T> {
     #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
index ba22c7f9b979966627712c6cab0b2475e613f90f..a4964b7aa0cc8c95f72f9f90807beb89da952d98 100644 (file)
@@ -5,7 +5,6 @@
 
 // Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then
 // on. This flag has performance relevant characteristics. Don't set it too high.
-#[allow(clippy::identity_op)]
 const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB
 
 /// Grows the stack on demand to prevent stack overflow. Call this in strategic locations
index a3ece6550473cce4ce080bbdc5e28f15b69e1cc2..a1ffbae8b15f6dd7d3c02264ade7a1c2faf2d24d 100644 (file)
@@ -34,7 +34,7 @@ pub fn new(value: T) -> Self {
     #[track_caller]
     pub fn borrow(&self) -> MappedReadGuard<'_, T> {
         let borrow = self.value.borrow();
-        if borrow.is_none() {
+        if let None = &*borrow {
             panic!("attempted to read from stolen value: {}", std::any::type_name::<T>());
         }
         ReadGuard::map(borrow, |opt| opt.as_ref().unwrap())
index 9e605ea2d982c950b22d044a07d768718bc8b7b3..9b07f86846eb32089b26b5834dcdb72ab0b29e9e 100644 (file)
@@ -48,7 +48,7 @@ pub fn remove(&mut self, data: &T) -> bool {
     #[inline]
     pub fn contains(&self, data: &T) -> bool {
         let mut elem = self.head.as_ref();
-        while let Some(e) = elem {
+        while let Some(ref e) = elem {
             if &e.data == data {
                 return true;
             }
index ce60d40b24b44e1087a5428c02d214c0379f8e89..1cf030d852e9fc8153388b6897a55da453bccf02 100644 (file)
@@ -2,8 +2,8 @@
 
 pub fn iter<Ls>(
     first: Option<Ls::LinkIndex>,
-    links: &Ls,
-) -> impl Iterator<Item = Ls::LinkIndex> + '_
+    links: &'a Ls,
+) -> impl Iterator<Item = Ls::LinkIndex> + 'a
 where
     Ls: Links,
 {
index 8e8bea9525dc9bdea4d59438bd9a77478ed53e80..2e9050dd672e171b17e3dc12acb055dbce881882 100644 (file)
@@ -59,23 +59,23 @@ fn call_with_pp_support<'tcx, A, F>(
 }
 fn call_with_pp_support_hir<A, F>(ppmode: &PpHirMode, tcx: TyCtxt<'_>, f: F) -> A
 where
-    F: FnOnce(&dyn HirPrinterSupport<'_>, &hir::Crate<'_>) -> A,
+    F: FnOnce(&dyn HirPrinterSupport<'_>, hir_map::Map<'_>) -> A,
 {
     match *ppmode {
         PpHirMode::Normal => {
             let annotation = NoAnn { sess: tcx.sess, tcx: Some(tcx) };
-            f(&annotation, tcx.hir().krate())
+            f(&annotation, tcx.hir())
         }
 
         PpHirMode::Identified => {
             let annotation = IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) };
-            f(&annotation, tcx.hir().krate())
+            f(&annotation, tcx.hir())
         }
         PpHirMode::Typed => {
             abort_on_err(tcx.analysis(()), tcx.sess);
 
             let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) };
-            tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir().krate()))
+            tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir()))
         }
     }
 }
@@ -443,17 +443,27 @@ pub fn print_after_hir_lowering<'tcx>(
             format!("{:#?}", krate)
         }
 
-        Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, krate| {
+        Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| {
             debug!("pretty printing HIR {:?}", s);
             let sess = annotation.sess();
             let sm = sess.source_map();
-            pprust_hir::print_crate(sm, krate, src_name, src, annotation.pp_ann())
+            let attrs = |id| hir_map.attrs(id);
+            pprust_hir::print_crate(
+                sm,
+                hir_map.root_module(),
+                src_name,
+                src,
+                &attrs,
+                annotation.pp_ann(),
+            )
         }),
 
-        HirTree => call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, krate| {
-            debug!("pretty printing HIR tree");
-            format!("{:#?}", krate)
-        }),
+        HirTree => {
+            call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, hir_map| {
+                debug!("pretty printing HIR tree");
+                format!("{:#?}", hir_map.krate())
+            })
+        }
 
         _ => unreachable!(),
     };
index 724e3f7fed3996e1aeb2638a71681fda46a5a2ca..42ce849c64d6a1ec14ea677c021006bd7c5660d8 100644 (file)
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
-//  E0019, merged into E0015
-//  E0035, merged into E0087/E0089
-//  E0036, merged into E0087/E0089
+//  E0019, // merged into E0015
+//  E0035, // merged into E0087/E0089
+//  E0036, // merged into E0087/E0089
 //  E0068,
 //  E0085,
 //  E0086,
 //  E0134,
 //  E0135,
 //  E0141,
-//  E0153, unused error code
-//  E0157, unused error code
+//  E0153, // unused error code
+//  E0157, // unused error code
 //  E0159, // use of trait `{}` as struct constructor
 //  E0163, // merged into E0071
 //  E0167,
            // between structures with the same definition
 //  E0385, // {} in an aliasable location
 //  E0402, // cannot use an outer type parameter in this context
-//  E0406, merged into 420
-//  E0410, merged into 408
-//  E0413, merged into 530
-//  E0414, merged into 530
-//  E0417, merged into 532
-//  E0418, merged into 532
-//  E0419, merged into 531
-//  E0420, merged into 532
-//  E0421, merged into 531
-//  E0427, merged into 530
+//  E0406, // merged into 420
+//  E0410, // merged into 408
+//  E0413, // merged into 530
+//  E0414, // merged into 530
+//  E0417, // merged into 532
+//  E0418, // merged into 532
+//  E0419, // merged into 531
+//  E0420, // merged into 532
+//  E0421, // merged into 531
+//  E0427, // merged into 530
 //  E0456, // plugin `..` is not available for triple `..`
     E0457, // plugin `..` only found in rlib format, but must be available...
     E0460, // found possibly newer version of crate `..`
     E0461, // couldn't find crate `..` with expected target triple ..
     E0462, // found staticlib `..` instead of rlib or dylib
     E0465, // multiple .. candidates for `..` found
-//  E0467, removed
-//  E0470, removed
+//  E0467, // removed
+//  E0470, // removed
 //  E0471, // constant evaluation error (in pattern)
     E0472, // llvm_asm! is unsupported on this target
 //  E0473, // dereference of reference outside its lifetime
     E0490, // a value of type `..` is borrowed for too long
     E0514, // metadata version mismatch
     E0519, // local crate and dependency have same (crate-name, disambiguator)
-    // two dependencies have same (crate-name, disambiguator) but different SVH
-    E0523,
+    E0523, // two dependencies have same (crate-name, disambiguator) but different SVH
 //  E0526, // shuffle indices are not constant
 //  E0540, // multiple rustc_deprecated attributes
 //  E0548, // replaced with a generic attribute input check
     E0711, // a feature has been declared with conflicting stability attributes
     E0717, // rustc_promotable without stability attribute
 //  E0721, // `await` keyword
-//  E0723, unstable feature in `const` context
+//  E0723, // unstable feature in `const` context
     E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
 //  E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
     E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`.
index 58ebf43cc98ced9ff3652ea13f49b10f067400c1..ad363816e1890dada37f084ab48f9ae1a9e5a0ef 100644 (file)
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 A lifetime of a returned value does not outlive the function call.
 
 Erroneous code example:
 
-```compile_fail,E0482
+```compile_fail,E0700
 fn prefix<'a>(
     words: impl Iterator<Item = &'a str>
 ) -> impl Iterator<Item = String> { // error!
@@ -41,7 +43,7 @@ fn prefix(
 
 A similar lifetime problem might arise when returning closures:
 
-```compile_fail,E0482
+```compile_fail,E0700
 fn foo(
     x: &mut Vec<i32>
 ) -> impl FnMut(&mut Vec<i32>) -> &[i32] { // error!
index d9068950bdfee67361ed6702156762c564ea663e..62d5565df27989e3b2fa667b0e701dff7ddaa3c0 100644 (file)
@@ -1,35 +1,51 @@
-An underscore `_` character has been used as the identifier for a lifetime.
+`'_` lifetime name or `&T` without an explicit lifetime name has been used
+on illegal place.
 
 Erroneous code example:
 
 ```compile_fail,E0106,E0637
-fn longest<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
-         //^^ `'_` is a reserved lifetime name
+fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
+                     //^^ `'_` is a reserved lifetime name
     if str1.len() > str2.len() {
         str1
     } else {
         str2
     }
 }
+
+fn and_without_explicit_lifetime<T>()
+where
+    T: Into<&u32>,
+          //^ `&` without an explicit lifetime name
+{
+}
 ```
 
-`'_`, cannot be used as a lifetime identifier because it is a reserved for the
-anonymous lifetime. To fix this, use a lowercase letter such as 'a, or a series
-of lowercase letters such as `'foo`.  For more information, see [the
-book][bk-no].  For more information on using the anonymous lifetime in rust
-nightly, see [the nightly book][bk-al].
+First, `'_` cannot be used as a lifetime identifier in some places
+because it is a reserved for the anonymous lifetime. Second, `&T`
+without an explicit lifetime name cannot also be used in some places.
+To fix them, use a lowercase letter such as `'a`, or a series
+of lowercase letters such as `'foo`. For more information about lifetime
+identifier, see [the book][bk-no]. For more information on using
+the anonymous lifetime in Rust 2018, see [the Rust 2018 blog post][blog-al].
 
 Corrected example:
 
 ```
-fn longest<'a>(str1: &'a str, str2: &'a str) -> &'a str {
+fn underscore_lifetime<'a>(str1: &'a str, str2: &'a str) -> &'a str {
     if str1.len() > str2.len() {
         str1
     } else {
         str2
     }
 }
+
+fn and_without_explicit_lifetime<'foo, T>()
+where
+    T: Into<&'foo u32>,
+{
+}
 ```
 
 [bk-no]: https://doc.rust-lang.org/book/appendix-02-operators.html#non-operator-symbols
-[bk-al]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/ownership-and-lifetimes/the-anonymous-lifetime.html
+[blog-al]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html#more-lifetime-elision-rules
index 41a73268f467345df99ff6b6e57fb967fd2aada6..f2381d75c565fd6d365edf242f363b44c0836722 100644 (file)
@@ -465,10 +465,14 @@ pub fn span_suggestions(
         suggestions: impl Iterator<Item = String>,
         applicability: Applicability,
     ) -> &mut Self {
+        let mut suggestions: Vec<_> = suggestions.collect();
+        suggestions.sort();
+        let substitutions = suggestions
+            .into_iter()
+            .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
+            .collect();
         self.suggestions.push(CodeSuggestion {
-            substitutions: suggestions
-                .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
-                .collect(),
+            substitutions,
             msg: msg.to_owned(),
             style: SuggestionStyle::ShowCode,
             applicability,
index 778d58eeadcf0344ae3ec63c72c9c661259b6988..e16ff9741229148c75827914ede58af494849180 100644 (file)
@@ -15,7 +15,7 @@
 use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
 use crate::styled_buffer::StyledBuffer;
 use crate::{
-    CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SubstitutionHighlight,
+    CodeSuggestion, Diagnostic, DiagnosticId, Handler, Level, SubDiagnostic, SubstitutionHighlight,
     SuggestionStyle,
 };
 
@@ -449,11 +449,7 @@ fn fix_multispans_in_extern_macros(
         span: &mut MultiSpan,
         children: &mut Vec<SubDiagnostic>,
     ) {
-        let source_map = if let Some(ref sm) = source_map {
-            sm
-        } else {
-            return;
-        };
+        let Some(source_map) = source_map else { return };
         debug!("fix_multispans_in_extern_macros: before: span={:?} children={:?}", span, children);
         self.fix_multispan_in_extern_macros(source_map, span);
         for child in children.iter_mut() {
@@ -527,14 +523,27 @@ fn supports_color(&self) -> bool {
     }
 }
 
-/// An emitter that does nothing when emitting a diagnostic.
-pub struct SilentEmitter;
+/// An emitter that does nothing when emitting a non-fatal diagnostic.
+/// Fatal diagnostics are forwarded to `fatal_handler` to avoid silent
+/// failures of rustc, as witnessed e.g. in issue #89358.
+pub struct SilentEmitter {
+    pub fatal_handler: Handler,
+    pub fatal_note: Option<String>,
+}
 
 impl Emitter for SilentEmitter {
     fn source_map(&self) -> Option<&Lrc<SourceMap>> {
         None
     }
-    fn emit_diagnostic(&mut self, _: &Diagnostic) {}
+    fn emit_diagnostic(&mut self, d: &Diagnostic) {
+        if d.level == Level::Fatal {
+            let mut d = d.clone();
+            if let Some(ref note) = self.fatal_note {
+                d.note(note);
+            }
+            self.fatal_handler.emit_diagnostic(&d);
+        }
+    }
 }
 
 /// Maximum number of lines we will print for a multiline suggestion; arbitrary.
@@ -2054,8 +2063,26 @@ fn num_decimal_digits(num: usize) -> usize {
     MAX_DIGITS
 }
 
+// We replace some characters so the CLI output is always consistent and underlines aligned.
+const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
+    ('\t', "    "),   // We do our own tab replacement
+    ('\u{202A}', ""), // The following unicode text flow control characters are inconsistently
+    ('\u{202B}', ""), // supported accross CLIs and can cause confusion due to the bytes on disk
+    ('\u{202D}', ""), // not corresponding to the visible source code, so we replace them always.
+    ('\u{202E}', ""),
+    ('\u{2066}', ""),
+    ('\u{2067}', ""),
+    ('\u{2068}', ""),
+    ('\u{202C}', ""),
+    ('\u{2069}', ""),
+];
+
 fn replace_tabs(str: &str) -> String {
-    str.replace('\t', "    ")
+    let mut s = str.to_string();
+    for (c, replacement) in OUTPUT_REPLACEMENTS {
+        s = s.replace(*c, replacement);
+    }
+    s
 }
 
 fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
index 9b2094adb150c1a0dd62a2ae975c56afaff6bc21..b6cf332f511ec2fe39e4eda5fbbd5982d92539a6 100644 (file)
@@ -8,6 +8,7 @@
 #![feature(if_let_guard)]
 #![feature(format_args_capture)]
 #![feature(iter_zip)]
+#![feature(let_else)]
 #![feature(nll)]
 
 #[macro_use]
index 38c099fa4f59ce8556b78a15454bff1d5e7329ae..1b123520961a6601106571a5d53e43dde4a31f33 100644 (file)
@@ -171,7 +171,7 @@ fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feat
             }
 
             if let Some(allowed) = sess.opts.debugging_opts.allow_features.as_ref() {
-                if allowed.iter().find(|&f| name.as_str() == *f).is_none() {
+                if allowed.iter().all(|f| name.as_str() != *f) {
                     struct_span_err!(
                         span_handler,
                         mi.span(),
index f548e2848a771b143f1c3d99694459d3cd5047b8..89dbd64ed8168171e82b3577e8c440b865e4a17d 100644 (file)
@@ -383,7 +383,7 @@ pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
                 Unsafe::No,
                 ModKind::Loaded(krate.items, Inline::Yes, krate.span)
             ),
-            ident: Ident::invalid(),
+            ident: Ident::empty(),
             id: ast::DUMMY_NODE_ID,
             vis: ast::Visibility {
                 span: krate.span.shrink_to_lo(),
@@ -447,9 +447,7 @@ pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragm
         let mut undetermined_invocations = Vec::new();
         let (mut progress, mut force) = (false, !self.monotonic);
         loop {
-            let (invoc, ext) = if let Some(invoc) = invocations.pop() {
-                invoc
-            } else {
+            let Some((invoc, ext)) = invocations.pop() else {
                 self.resolve_imports();
                 if undetermined_invocations.is_empty() {
                     break;
@@ -1426,7 +1424,7 @@ fn visit_block(&mut self, block: &mut P<Block>) {
                     _ => unreachable!(),
                 })
             }
-            ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::invalid() => {
+            ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::empty() => {
                 let (file_path, dir_path, dir_ownership) = match mod_kind {
                     ModKind::Loaded(_, inline, _) => {
                         // Inline `mod foo { ... }`, but we still need to push directories.
@@ -1508,7 +1506,7 @@ fn visit_block(&mut self, block: &mut P<Block>) {
             _ => {
                 item.attrs = attrs;
                 // The crate root is special - don't assign an ID to it.
-                if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::invalid()) {
+                if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::empty()) {
                     assign_id!(self, &mut item.id, || noop_flat_map_item(item, self))
                 } else {
                     noop_flat_map_item(item, self)
index 6dfeb047ec94cf26d38e6bd12cb8b0fc72e60d95..521ca2135c6f217ad573c1ffbf437ade2652c08b 100644 (file)
@@ -4,6 +4,7 @@
 #![feature(format_args_capture)]
 #![feature(if_let_guard)]
 #![feature(iter_zip)]
+#![feature(let_else)]
 #![feature(proc_macro_diagnostic)]
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_span)]
index 363cc72b52c3e5bc46483c5b94f796bde701144f..dedc6c618b9a482442828018babc4780bcff0e6e 100644 (file)
@@ -204,7 +204,7 @@ fn parse_tree(
                         pprust::token_to_string(&token),
                     );
                     sess.span_diagnostic.span_err(token.span, &msg);
-                    TokenTree::MetaVar(token.span, Ident::invalid())
+                    TokenTree::MetaVar(token.span, Ident::empty())
                 }
 
                 // There are no more tokens. Just return the `$` we already have.
index 9ed5c8b8ffba5c814d4177fe50772285d1f36ec8..88e1623012ba0a43f0b475e828c25e7f99485055 100644 (file)
@@ -19,9 +19,7 @@
 struct Marker(LocalExpnId, Transparency);
 
 impl MutVisitor for Marker {
-    fn token_visiting_enabled(&self) -> bool {
-        true
-    }
+    const VISIT_TOKENS: bool = true;
 
     fn visit_span(&mut self, span: &mut Span) {
         *span = span.apply_mark(self.0.to_expn_id(), self.1)
@@ -116,10 +114,8 @@ pub(super) fn transcribe<'a>(
 
     loop {
         // Look at the last frame on the stack.
-        let tree = if let Some(tree) = stack.last_mut().unwrap().next() {
-            // If it still has a TokenTree we have not looked at yet, use that tree.
-            tree
-        } else {
+        // If it still has a TokenTree we have not looked at yet, use that tree.
+        let Some(tree) = stack.last_mut().unwrap().next() else {
             // This else-case never produces a value for `tree` (it `continue`s or `return`s).
 
             // Otherwise, if we have just reached the end of a sequence and we can keep repeating,
@@ -190,9 +186,7 @@ pub(super) fn transcribe<'a>(
                     LockstepIterSize::Constraint(len, _) => {
                         // We do this to avoid an extra clone above. We know that this is a
                         // sequence already.
-                        let (sp, seq) = if let mbe::TokenTree::Sequence(sp, seq) = seq {
-                            (sp, seq)
-                        } else {
+                        let mbe::TokenTree::Sequence(sp, seq) = seq else {
                             unreachable!()
                         };
 
index 0068539fb3bd4b075c2176305abe776351b871a2..8974d45b4d8cfeaddced965b4cc7eab4db5ed3ec 100644 (file)
@@ -15,9 +15,8 @@ fn print_crate_items(krate: &ast::Crate) -> String {
 struct ToZzIdentMutVisitor;
 
 impl MutVisitor for ToZzIdentMutVisitor {
-    fn token_visiting_enabled(&self) -> bool {
-        true
-    }
+    const VISIT_TOKENS: bool = true;
+
     fn visit_ident(&mut self, ident: &mut Ident) {
         *ident = Ident::from_str("zz");
     }
index 8e78fcbb8dbc14a40110def4bda0c03506a63947..12b6bc7bbe7689efffaca0447e1e11af197a7e1f 100644 (file)
@@ -23,7 +23,7 @@ fn mac_placeholder() -> ast::MacCall {
         }
     }
 
-    let ident = Ident::invalid();
+    let ident = Ident::empty();
     let attrs = Vec::new();
     let vis = vis.unwrap_or(ast::Visibility {
         span: DUMMY_SP,
index 0d7a2afb6367d6b92d6dfd26d7ae3f01097342cb..941d957103c0cef98dd5e474ee99fd13caa5ba72 100644 (file)
@@ -297,6 +297,8 @@ macro_rules! declare_features {
     (accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None),
     /// Allows panicking during const eval (producing compile-time errors).
     (accepted, const_panic, "1.57.0", Some(51999), None),
+    /// Lessens the requirements for structs to implement `Unsize`.
+    (accepted, relaxed_struct_unsize, "1.58.0", Some(81793), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
index f7c0597909e8bfb805d31a8863329885c0b54f76..1c6f1344e8a1ecca19866b582b413ef804533d6e 100644 (file)
@@ -101,9 +101,13 @@ pub fn set(&self, features: &mut Features, span: Span) {
     }
 }
 
+// See https://rustc-dev-guide.rust-lang.org/feature-gates.html#feature-gates for more
+// documentation about handling feature gates.
+//
 // If you change this, please modify `src/doc/unstable-book` as well.
 //
-// Don't ever remove anything from this list; move them to `removed.rs`.
+// Don't ever remove anything from this list; move them to `accepted.rs` if
+// accepted or `removed.rs` if removed.
 //
 // The version numbers here correspond to the version in which the current status
 // was set. This is most important for knowing when a particular feature became
@@ -589,9 +593,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows `extern "C-cmse-nonsecure-call" fn()`.
     (active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None),
 
-    /// Lessens the requirements for structs to implement `Unsize`.
-    (active, relaxed_struct_unsize, "1.51.0", Some(81793), None),
-
     /// Allows associated types in inherent impls.
     (incomplete, inherent_associated_types, "1.52.0", Some(8995), None),
 
@@ -684,6 +685,13 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows using the `non_exhaustive_omitted_patterns` lint.
     (active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
 
+    /// Allows creation of instances of a struct by moving fields that have
+    /// not changed from prior instances of the same struct (RFC #2528)
+    (incomplete, type_changing_struct_update, "1.58.0", Some(86555), None),
+
+    /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
+    (active, doc_auto_cfg, "1.58.0", Some(43781), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
index 85b0db468d1258cd1727a8e08ccc7e75075ccb55..33188d375f5d5e2f333ff8605a5414cf58b796ac 100644 (file)
@@ -556,6 +556,7 @@ macro_rules! experimental {
     rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)),
     rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)),
     rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word)),
+    rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word)),
     rustc_attr!(TEST, rustc_variance, Normal, template!(Word)),
     rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
     rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
index e69289b71f97f9feee16f51ad18f61fe67a01477..27390fd2e4d9117b784b786a7c466bdffb1d79eb 100644 (file)
@@ -512,7 +512,7 @@ fn escape_str(s: &str) -> String {
     pub fn to_dot_string(&self) -> String {
         match *self {
             LabelStr(ref s) => format!("\"{}\"", s.escape_default()),
-            EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(s)),
+            EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s)),
             HtmlStr(ref s) => format!("<{}>", s),
         }
     }
index 3b6e6db72d1f7128e42a099c2c2fef6001e9c5f1..41c63440ba3cd86f72d5e055dd5bcd73c6fbcf00 100644 (file)
@@ -17,4 +17,4 @@ rustc_serialize = { path = "../rustc_serialize" }
 rustc_ast = { path = "../rustc_ast" }
 tracing = "0.1"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
-odht = { version = "0.3.0", features = ["nightly"] }
+odht = { version = "0.3.1", features = ["nightly"] }
index f07e52e04daa9d8020ee9b6ee58c2d6f72de845f..1a34dd0442855ffdf2dc06b472c20d3f859c8068 100644 (file)
@@ -19,6 +19,7 @@ macro_rules! arena_types {
             [] attribute: rustc_ast::Attribute,
             [] block: rustc_hir::Block<$tcx>,
             [] bare_fn_ty: rustc_hir::BareFnTy<$tcx>,
+            [] body: rustc_hir::Body<$tcx>,
             [] generic_arg: rustc_hir::GenericArg<$tcx>,
             [] generic_args: rustc_hir::GenericArgs<$tcx>,
             [] generic_bound: rustc_hir::GenericBound<$tcx>,
@@ -36,6 +37,7 @@ macro_rules! arena_types {
             [few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>,
             [] local: rustc_hir::Local<$tcx>,
             [few] mod_: rustc_hir::Mod<$tcx>,
+            [] owner_info: rustc_hir::OwnerInfo<$tcx>,
             [] param: rustc_hir::Param<$tcx>,
             [] pat: rustc_hir::Pat<$tcx>,
             [] path: rustc_hir::Path<$tcx>,
index 11d0178e93ba447b7b17722bb5b78245566b8755..a441a635c1eb37ce6b0e3474eeefd97eba449243 100644 (file)
@@ -1,6 +1,7 @@
 use crate::def::{CtorKind, DefKind, Res};
-use crate::def_id::{DefId, CRATE_DEF_ID};
+use crate::def_id::DefId;
 crate use crate::hir_id::{HirId, ItemLocalId};
+use crate::intravisit::FnKind;
 use crate::LangItem;
 
 use rustc_ast::util::parser::ExprPrecedence;
@@ -9,7 +10,9 @@
 pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
 pub use rustc_ast::{CaptureBy, Movability, Mutability};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sorted_map::SortedMap;
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable_Generic;
 use rustc_span::source_map::Spanned;
@@ -20,7 +23,6 @@
 use rustc_target::spec::abi::Abi;
 
 use smallvec::SmallVec;
-use std::collections::BTreeMap;
 use std::fmt;
 
 #[derive(Copy, Clone, Encodable, HashStable_Generic)]
@@ -121,7 +123,7 @@ pub fn ident(&self) -> Ident {
         match *self {
             LifetimeName::ImplicitObjectLifetimeDefault
             | LifetimeName::Implicit
-            | LifetimeName::Error => Ident::invalid(),
+            | LifetimeName::Error => Ident::empty(),
             LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
             LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
             LifetimeName::Param(param_name) => param_name.ident(),
@@ -233,7 +235,7 @@ pub fn from_ident(ident: Ident) -> PathSegment<'hir> {
     }
 
     pub fn invalid() -> Self {
-        Self::from_ident(Ident::invalid())
+        Self::from_ident(Ident::empty())
     }
 
     pub fn args(&self) -> &GenericArgs<'hir> {
@@ -310,7 +312,7 @@ pub fn is_const(&self) -> bool {
     }
 
     pub fn is_synthetic(&self) -> bool {
-        matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::invalid())
+        matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::empty())
     }
 
     pub fn descr(&self) -> &'static str {
@@ -662,49 +664,84 @@ pub struct WhereEqPredicate<'hir> {
     pub rhs_ty: &'hir Ty<'hir>,
 }
 
-/// The top-level data structure that stores the entire contents of
-/// the crate currently being compiled.
-///
-/// For more details, see the [rustc dev guide].
+/// HIR node coupled with its parent's id in the same HIR owner.
 ///
-/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
-#[derive(Debug)]
-pub struct Crate<'hir> {
-    pub owners: IndexVec<LocalDefId, Option<OwnerNode<'hir>>>,
-    pub bodies: BTreeMap<BodyId, Body<'hir>>,
-
-    /// Map indicating what traits are in scope for places where this
-    /// is relevant; generated by resolve.
-    pub trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Box<[TraitCandidate]>>>,
-
-    /// Collected attributes from HIR nodes.
-    pub attrs: BTreeMap<HirId, &'hir [Attribute]>,
+/// The parent is trash when the node is a HIR owner.
+#[derive(Clone, Debug)]
+pub struct ParentedNode<'tcx> {
+    pub parent: ItemLocalId,
+    pub node: Node<'tcx>,
 }
 
-impl Crate<'hir> {
-    pub fn module(&self) -> &'hir Mod<'hir> {
-        if let Some(OwnerNode::Crate(m)) = self.owners[CRATE_DEF_ID] { m } else { panic!() }
-    }
+/// Attributes owned by a HIR owner.
+#[derive(Debug)]
+pub struct AttributeMap<'tcx> {
+    pub map: SortedMap<ItemLocalId, &'tcx [Attribute]>,
+    pub hash: Fingerprint,
+}
 
-    pub fn item(&self, id: ItemId) -> &'hir Item<'hir> {
-        self.owners[id.def_id].as_ref().unwrap().expect_item()
-    }
+impl<'tcx> AttributeMap<'tcx> {
+    pub const EMPTY: &'static AttributeMap<'static> =
+        &AttributeMap { map: SortedMap::new(), hash: Fingerprint::ZERO };
 
-    pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
-        self.owners[id.def_id].as_ref().unwrap().expect_trait_item()
+    #[inline]
+    pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] {
+        self.map.get(&id).copied().unwrap_or(&[])
     }
+}
 
-    pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
-        self.owners[id.def_id].as_ref().unwrap().expect_impl_item()
-    }
+/// Map of all HIR nodes inside the current owner.
+/// These nodes are mapped by `ItemLocalId` alongside the index of their parent node.
+/// The HIR tree, including bodies, is pre-hashed.
+#[derive(Debug)]
+pub struct OwnerNodes<'tcx> {
+    /// Pre-computed hash of the full HIR.
+    pub hash_including_bodies: Fingerprint,
+    /// Pre-computed hash of the item signature, sithout recursing into the body.
+    pub hash_without_bodies: Fingerprint,
+    /// Full HIR for the current owner.
+    // The zeroth node's parent should never be accessed: the owner's parent is computed by the
+    // hir_owner_parent query.  It is set to `ItemLocalId::INVALID` to force an ICE if accidentally
+    // used.
+    pub nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
+    /// Content of local bodies.
+    pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>,
+}
+
+/// Full information resulting from lowering an AST node.
+#[derive(Debug, HashStable_Generic)]
+pub struct OwnerInfo<'hir> {
+    /// Contents of the HIR.
+    pub nodes: OwnerNodes<'hir>,
+    /// Map from each nested owner to its parent's local id.
+    pub parenting: FxHashMap<LocalDefId, ItemLocalId>,
+    /// Collected attributes of the HIR nodes.
+    pub attrs: AttributeMap<'hir>,
+    /// Map indicating what traits are in scope for places where this
+    /// is relevant; generated by resolve.
+    pub trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>,
+}
 
-    pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
-        self.owners[id.def_id].as_ref().unwrap().expect_foreign_item()
+impl<'tcx> OwnerInfo<'tcx> {
+    #[inline]
+    pub fn node(&self) -> OwnerNode<'tcx> {
+        use rustc_index::vec::Idx;
+        let node = self.nodes.nodes[ItemLocalId::new(0)].as_ref().unwrap().node;
+        let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode.
+        node
     }
+}
 
-    pub fn body(&self, id: BodyId) -> &Body<'hir> {
-        &self.bodies[&id]
-    }
+/// The top-level data structure that stores the entire contents of
+/// the crate currently being compiled.
+///
+/// For more details, see the [rustc dev guide].
+///
+/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
+#[derive(Debug)]
+pub struct Crate<'hir> {
+    pub owners: IndexVec<LocalDefId, Option<OwnerInfo<'hir>>>,
+    pub hir_hash: Fingerprint,
 }
 
 /// A block of statements `{ .. }`, which may have a label (in this case the
@@ -3222,6 +3259,32 @@ pub fn as_owner(self) -> Option<OwnerNode<'hir>> {
             _ => None,
         }
     }
+
+    pub fn fn_kind(self) -> Option<FnKind<'hir>> {
+        match self {
+            Node::Item(i) => match i.kind {
+                ItemKind::Fn(ref sig, ref generics, _) => {
+                    Some(FnKind::ItemFn(i.ident, generics, sig.header, &i.vis))
+                }
+                _ => None,
+            },
+            Node::TraitItem(ti) => match ti.kind {
+                TraitItemKind::Fn(ref sig, TraitFn::Provided(_)) => {
+                    Some(FnKind::Method(ti.ident, sig, None))
+                }
+                _ => None,
+            },
+            Node::ImplItem(ii) => match ii.kind {
+                ImplItemKind::Fn(ref sig, _) => Some(FnKind::Method(ii.ident, sig, Some(&ii.vis))),
+                _ => None,
+            },
+            Node::Expr(e) => match e.kind {
+                ExprKind::Closure(..) => Some(FnKind::Closure),
+                _ => None,
+            },
+            _ => None,
+        }
+    }
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
index 0b25ebc27bd3f9d671432daa8da9548b0a5633ae..39552eb9f3102afa193135fcad0722cfd7a5dfe9 100644 (file)
@@ -1,5 +1,4 @@
 use crate::def_id::{LocalDefId, CRATE_DEF_INDEX};
-use rustc_index::vec::IndexVec;
 use std::fmt;
 
 /// Uniquely identifies a node in the HIR of the current crate. It is
@@ -56,76 +55,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     pub struct ItemLocalId { .. }
 }
 rustc_data_structures::impl_stable_hash_via_hash!(ItemLocalId);
+impl ItemLocalId {
+    /// Signal local id which should never be used.
+    pub const INVALID: ItemLocalId = ItemLocalId::MAX;
+}
 
 /// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`.
 pub const CRATE_HIR_ID: HirId = HirId {
     owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
     local_id: ItemLocalId::from_u32(0),
 };
-
-/// N.B. This collection is currently unused, but will be used by #72015 and future PRs.
-#[derive(Clone, Default, Debug, Encodable, Decodable)]
-pub struct HirIdVec<T> {
-    map: IndexVec<LocalDefId, IndexVec<ItemLocalId, T>>,
-}
-
-impl<T> HirIdVec<T> {
-    pub fn push_owner(&mut self, id: LocalDefId) {
-        self.map.ensure_contains_elem(id, IndexVec::new);
-    }
-
-    pub fn push(&mut self, id: HirId, value: T) {
-        if id.local_id == ItemLocalId::from_u32(0) {
-            self.push_owner(id.owner);
-        }
-        let submap = &mut self.map[id.owner];
-        let _ret_id = submap.push(value);
-        debug_assert_eq!(_ret_id, id.local_id);
-    }
-
-    pub fn push_sparse(&mut self, id: HirId, value: T)
-    where
-        T: Default,
-    {
-        self.map.ensure_contains_elem(id.owner, IndexVec::new);
-        let submap = &mut self.map[id.owner];
-        let i = id.local_id.index();
-        let len = submap.len();
-        if i >= len {
-            submap.extend(std::iter::repeat_with(T::default).take(i - len + 1));
-        }
-        submap[id.local_id] = value;
-    }
-
-    pub fn get(&self, id: HirId) -> Option<&T> {
-        self.map.get(id.owner)?.get(id.local_id)
-    }
-
-    pub fn get_owner(&self, id: LocalDefId) -> &IndexVec<ItemLocalId, T> {
-        &self.map[id]
-    }
-
-    pub fn iter(&self) -> impl Iterator<Item = &T> {
-        self.map.iter().flat_map(|la| la.iter())
-    }
-
-    pub fn iter_enumerated(&self) -> impl Iterator<Item = (HirId, &T)> {
-        self.map.iter_enumerated().flat_map(|(owner, la)| {
-            la.iter_enumerated().map(move |(local_id, attr)| (HirId { owner, local_id }, attr))
-        })
-    }
-}
-
-impl<T> std::ops::Index<HirId> for HirIdVec<T> {
-    type Output = T;
-
-    fn index(&self, id: HirId) -> &T {
-        &self.map[id.owner][id.local_id]
-    }
-}
-
-impl<T> std::ops::IndexMut<HirId> for HirIdVec<T> {
-    fn index_mut(&mut self, id: HirId) -> &mut T {
-        &mut self.map[id.owner][id.local_id]
-    }
-}
index 1ac2625dd475483edce4e66030a81f5f222eb741..cff543760f42af954123f20e1bd85c4876e92e02 100644 (file)
@@ -117,6 +117,14 @@ pub fn header(&self) -> Option<&FnHeader> {
             FnKind::Closure => None,
         }
     }
+
+    pub fn constness(self) -> Constness {
+        self.header().map_or(Constness::NotConst, |header| header.constness)
+    }
+
+    pub fn asyncness(self) -> IsAsync {
+        self.header().map_or(IsAsync::NotAsync, |header| header.asyncness)
+    }
 }
 
 /// An abstract representation of the HIR `rustc_middle::hir::map::Map`.
@@ -130,6 +138,28 @@ pub trait Map<'hir> {
     fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir>;
 }
 
+// Used when no map is actually available, forcing manual implementation of nested visitors.
+impl Map<'hir> for ! {
+    fn find(&self, _: HirId) -> Option<Node<'hir>> {
+        unreachable!()
+    }
+    fn body(&self, _: BodyId) -> &'hir Body<'hir> {
+        unreachable!()
+    }
+    fn item(&self, _: ItemId) -> &'hir Item<'hir> {
+        unreachable!()
+    }
+    fn trait_item(&self, _: TraitItemId) -> &'hir TraitItem<'hir> {
+        unreachable!()
+    }
+    fn impl_item(&self, _: ImplItemId) -> &'hir ImplItem<'hir> {
+        unreachable!()
+    }
+    fn foreign_item(&self, _: ForeignItemId) -> &'hir ForeignItem<'hir> {
+        unreachable!()
+    }
+}
+
 /// 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>);
index f35353dbfb581493539b931a1240cf268fae2af4..3037996d48bc03bb8e1a0ca1cc4847b53c7d082f 100644 (file)
@@ -281,18 +281,17 @@ pub fn extract<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<(Sym
     // in the sense that a crate is not required to have it defined to use it, but a final product
     // is required to define it somewhere. Additionally, there are restrictions on crates that use
     // a weak lang item, but do not have it defined.
-    Panic,                   sym::panic,               panic_fn,                   Target::Fn,             GenericRequirement::None;
+    Panic,                   sym::panic,               panic_fn,                   Target::Fn,             GenericRequirement::Exact(0);
     PanicFmt,                sym::panic_fmt,           panic_fmt,                  Target::Fn,             GenericRequirement::None;
     PanicDisplay,            sym::panic_display,       panic_display,              Target::Fn,             GenericRequirement::None;
     PanicStr,                sym::panic_str,           panic_str,                  Target::Fn,             GenericRequirement::None;
     ConstPanicFmt,           sym::const_panic_fmt,     const_panic_fmt,            Target::Fn,             GenericRequirement::None;
-    PanicBoundsCheck,        sym::panic_bounds_check,  panic_bounds_check_fn,      Target::Fn,             GenericRequirement::None;
+    PanicBoundsCheck,        sym::panic_bounds_check,  panic_bounds_check_fn,      Target::Fn,             GenericRequirement::Exact(0);
     PanicInfo,               sym::panic_info,          panic_info,                 Target::Struct,         GenericRequirement::None;
     PanicLocation,           sym::panic_location,      panic_location,             Target::Struct,         GenericRequirement::None;
     PanicImpl,               sym::panic_impl,          panic_impl,                 Target::Fn,             GenericRequirement::None;
     /// libstd panic entry point. Necessary for const eval to be able to catch it
     BeginPanic,              sym::begin_panic,         begin_panic_fn,             Target::Fn,             GenericRequirement::None;
-    BeginPanicFmt,           sym::begin_panic_fmt,     begin_panic_fmt,            Target::Fn,             GenericRequirement::None;
 
     ExchangeMalloc,          sym::exchange_malloc,     exchange_malloc_fn,         Target::Fn,             GenericRequirement::None;
     BoxFree,                 sym::box_free,            box_free_fn,                Target::Fn,             GenericRequirement::Minimum(1);
index f5ea044e248652fb2dea7a1bdabab5330558d34f..93224d388c00fe6053353b6e7a78bccbc6eaec68 100644 (file)
@@ -2,10 +2,12 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
 
+#![feature(const_btree_new)]
 #![feature(crate_visibility_modifier)]
 #![feature(in_band_lifetimes)]
 #![feature(once_cell)]
 #![feature(min_specialization)]
+#![feature(never_type)]
 #![recursion_limit = "256"]
 
 #[macro_use]
index 9d5ef279dd784cff501452d63af5bf70658f9a75..6e7b765a0c4413b62242640973b3d2681c669c53 100644 (file)
@@ -1,8 +1,8 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 
 use crate::hir::{
-    BodyId, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem,
-    TraitItemId, Ty, VisibilityKind,
+    AttributeMap, BodyId, Crate, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item,
+    ItemId, Mod, OwnerNodes, TraitCandidate, TraitItem, TraitItemId, Ty, VisibilityKind,
 };
 use crate::hir_id::{HirId, ItemLocalId};
 use rustc_span::def_id::DefPathHash;
@@ -21,6 +21,7 @@ pub trait HashStableContext:
     fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher);
     fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher);
     fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F);
+    fn hash_hir_trait_candidate(&mut self, _: &TraitCandidate, hasher: &mut StableHasher);
 }
 
 impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
@@ -209,3 +210,35 @@ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
         });
     }
 }
+
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'tcx> {
+    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+        // We ignore the `nodes` and `bodies` fields since these refer to information included in
+        // `hash` which is hashed in the collector and used for the crate hash.
+        let OwnerNodes { hash_including_bodies, hash_without_bodies: _, nodes: _, bodies: _ } =
+            *self;
+        hash_including_bodies.hash_stable(hcx, hasher);
+    }
+}
+
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap<'tcx> {
+    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+        // We ignore the `map` since it refers to information included in `hash` which is hashed in
+        // the collector and used for the crate hash.
+        let AttributeMap { hash, map: _ } = *self;
+        hash.hash_stable(hcx, hasher);
+    }
+}
+
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Crate<'_> {
+    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+        let Crate { owners: _, hir_hash } = self;
+        hir_hash.hash_stable(hcx, hasher)
+    }
+}
+
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitCandidate {
+    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+        hcx.hash_hir_trait_candidate(self, hasher)
+    }
+}
index 9196344cb3ffd0a7082747f95742ace62944cf17..9c2927111a66c9f40df85bde1462725fa6bd524f 100644 (file)
@@ -15,7 +15,6 @@
 
 use std::borrow::Cow;
 use std::cell::Cell;
-use std::collections::BTreeMap;
 use std::vec;
 
 pub fn id_to_string(map: &dyn rustc_hir::intravisit::Map<'_>, hir_id: hir::HirId) -> String {
@@ -69,7 +68,7 @@ fn nested(&self, state: &mut State<'_>, nested: Nested) {
 pub struct State<'a> {
     pub s: pp::Printer,
     comments: Option<Comments<'a>>,
-    attrs: &'a BTreeMap<hir::HirId, &'a [ast::Attribute]>,
+    attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute],
     ann: &'a (dyn PpAnn + 'a),
 }
 
@@ -146,17 +145,18 @@ fn print_generic_args(&mut self, _: &ast::GenericArgs, _colons_before_params: bo
 /// it can scan the input text for comments to copy forward.
 pub fn print_crate<'a>(
     sm: &'a SourceMap,
-    krate: &hir::Crate<'_>,
+    krate: &hir::Mod<'_>,
     filename: FileName,
     input: String,
+    attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute],
     ann: &'a dyn PpAnn,
 ) -> String {
-    let mut s = State::new_from_input(sm, filename, input, &krate.attrs, ann);
+    let mut s = State::new_from_input(sm, filename, input, attrs, ann);
 
     // When printing the AST, we sometimes need to inject `#[no_std]` here.
     // Since you can't compile the HIR, it's not necessary.
 
-    s.print_mod(&krate.module(), s.attrs(hir::CRATE_HIR_ID));
+    s.print_mod(krate, (*attrs)(hir::CRATE_HIR_ID));
     s.print_remaining_comments();
     s.s.eof()
 }
@@ -166,7 +166,7 @@ pub fn new_from_input(
         sm: &'a SourceMap,
         filename: FileName,
         input: String,
-        attrs: &'a BTreeMap<hir::HirId, &[ast::Attribute]>,
+        attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute],
         ann: &'a dyn PpAnn,
     ) -> State<'a> {
         State {
@@ -178,7 +178,7 @@ pub fn new_from_input(
     }
 
     fn attrs(&self, id: hir::HirId) -> &'a [ast::Attribute] {
-        self.attrs.get(&id).map_or(&[], |la| *la)
+        (self.attrs)(id)
     }
 }
 
@@ -186,8 +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: &BTreeMap::default(), ann };
+    let mut printer = State { s: pp::mk_printer(), comments: None, attrs: &|_| &[], ann };
     f(&mut printer);
     printer.s.eof()
 }
@@ -1168,7 +1167,7 @@ fn print_let(&mut self, pat: &hir::Pat<'_>, expr: &hir::Expr<'_>) {
         self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
     }
 
-    // Does `expr` need parenthesis when printed in a condition position?
+    // 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) {}`.
index d42e2f7a99c8a233dea069c8743b4013ef0391d0..571337a8dcbc6a3e2ec3ad13acdb56cfac8996f4 100644 (file)
@@ -126,30 +126,36 @@ fn process_attrs(&mut self, hir_id: hir::HirId) {
             if attr.has_name(sym::rustc_if_this_changed) {
                 let dep_node_interned = self.argument(attr);
                 let dep_node = match dep_node_interned {
-                    None => DepNode::from_def_path_hash(def_path_hash, DepKind::hir_owner),
-                    Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) {
-                        Ok(n) => n,
-                        Err(()) => {
-                            self.tcx.sess.span_fatal(
-                                attr.span,
-                                &format!("unrecognized DepNode variant {:?}", n),
-                            );
+                    None => {
+                        DepNode::from_def_path_hash(self.tcx, def_path_hash, DepKind::hir_owner)
+                    }
+                    Some(n) => {
+                        match DepNode::from_label_string(self.tcx, &n.as_str(), def_path_hash) {
+                            Ok(n) => n,
+                            Err(()) => {
+                                self.tcx.sess.span_fatal(
+                                    attr.span,
+                                    &format!("unrecognized DepNode variant {:?}", n),
+                                );
+                            }
                         }
-                    },
+                    }
                 };
                 self.if_this_changed.push((attr.span, def_id.to_def_id(), dep_node));
             } else if attr.has_name(sym::rustc_then_this_would_need) {
                 let dep_node_interned = self.argument(attr);
                 let dep_node = match dep_node_interned {
-                    Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) {
-                        Ok(n) => n,
-                        Err(()) => {
-                            self.tcx.sess.span_fatal(
-                                attr.span,
-                                &format!("unrecognized DepNode variant {:?}", n),
-                            );
+                    Some(n) => {
+                        match DepNode::from_label_string(self.tcx, &n.as_str(), def_path_hash) {
+                            Ok(n) => n,
+                            Err(()) => {
+                                self.tcx.sess.span_fatal(
+                                    attr.span,
+                                    &format!("unrecognized DepNode variant {:?}", n),
+                                );
+                            }
                         }
-                    },
+                    }
                     None => {
                         self.tcx.sess.span_fatal(attr.span, "missing DepNode variant");
                     }
index f089cbcfca6e5f150a2bdc40776eb3ab0d1bbc6f..dd3f8c937f81abd400017a7885e74a02990ada60 100644 (file)
@@ -2,6 +2,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(in_band_lifetimes)]
+#![feature(let_else)]
 #![feature(nll)]
 #![recursion_limit = "256"]
 
index 55286384de359522b3855c3ad7216bbc8a98a7b1..b2eaf61b7d14560912011fcea60ed46f8723e739 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_ast::{self as ast, Attribute, NestedMetaItem};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::Node as HirNode;
@@ -302,18 +302,6 @@ fn resolve_labels(&self, item: &NestedMetaItem, value: Symbol) -> Labels {
         out
     }
 
-    fn dep_nodes<'l>(
-        &self,
-        labels: &'l Labels,
-        def_id: DefId,
-    ) -> impl Iterator<Item = DepNode> + 'l {
-        let def_path_hash = self.tcx.def_path_hash(def_id);
-        labels.iter().map(move |label| match DepNode::from_label_string(label, def_path_hash) {
-            Ok(dep_node) => dep_node,
-            Err(()) => unreachable!("label: {}", label),
-        })
-    }
-
     fn dep_node_str(&self, dep_node: &DepNode) -> String {
         if let Some(def_id) = dep_node.extract_def_id(self.tcx) {
             format!("{:?}({})", dep_node.kind, self.tcx.def_path_str(def_id))
@@ -345,16 +333,19 @@ fn assert_clean(&self, item_span: Span, dep_node: DepNode) {
     }
 
     fn check_item(&mut self, item_id: LocalDefId, item_span: Span) {
+        let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id());
         for attr in self.tcx.get_attrs(item_id.to_def_id()).iter() {
             let assertion = match self.assertion_maybe(item_id, attr) {
                 Some(a) => a,
                 None => continue,
             };
             self.checked_attrs.insert(attr.id);
-            for dep_node in self.dep_nodes(&assertion.clean, item_id.to_def_id()) {
+            for label in assertion.clean {
+                let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
                 self.assert_clean(item_span, dep_node);
             }
-            for dep_node in self.dep_nodes(&assertion.dirty, item_id.to_def_id()) {
+            for label in assertion.dirty {
+                let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
                 self.assert_dirty(item_span, dep_node);
             }
         }
index 572a4fc69717380aa6a8867a175425fd270da670..392c5bdc15ad204472ec07f3d6cced7028d3bf53 100644 (file)
@@ -95,6 +95,12 @@ pub(crate) fn save_in<F>(sess: &Session, path_buf: PathBuf, name: &str, encode:
         return;
     }
 
+    sess.prof.artifact_size(
+        &name.replace(' ', "_"),
+        path_buf.file_name().unwrap().to_string_lossy(),
+        encoder.position() as u64,
+    );
+
     debug!("save: data written to disk successfully");
 }
 
index 2ed0539841aa30b42f896132fbf02779b70354c6..38cbf5314ef314361e3bf869a9a99a9ebf37c1c5 100644 (file)
@@ -241,9 +241,7 @@ pub fn prepare_session_directory(
         // have already tried before.
         let source_directory = find_source_directory(&crate_dir, &source_directories_already_tried);
 
-        let source_directory = if let Some(dir) = source_directory {
-            dir
-        } else {
+        let Some(source_directory) = source_directory else {
             // There's nowhere to copy from, we're done
             debug!(
                 "no source directory found. Continuing with empty session \
@@ -397,15 +395,14 @@ fn copy_files(sess: &Session, target_dir: &Path, source_dir: &Path) -> Result<bo
     // We acquire a shared lock on the lock file of the directory, so that
     // nobody deletes it out from under us while we are reading from it.
     let lock_file_path = lock_file_path(source_dir);
-    let _lock = if let Ok(lock) = flock::Lock::new(
+
+    // not exclusive
+    let Ok(_lock) = flock::Lock::new(
         &lock_file_path,
         false, // don't wait,
         false, // don't create
         false,
-    ) {
-        // not exclusive
-        lock
-    } else {
+    ) else {
         // Could not acquire the lock, don't try to copy from here
         return Err(());
     };
index 573124c8ec9a8fa3d0d9bb030272bc81e6a4b685..67b3cec0a3e59111fb3e897d060e4147e6dd75fd 100644 (file)
@@ -990,8 +990,9 @@ pub fn union_row_with(&mut self, with: &BitSet<C>, write: R) -> bool {
     pub fn insert_all_into_row(&mut self, row: R) {
         assert!(row.index() < self.num_rows);
         let (start, end) = self.range(row);
-        for word in self.words[start..end].iter_mut() {
-            *word = !0;
+        let words = &mut self.words[..];
+        for index in start..end {
+            words[index] = !0;
         }
         self.clear_excess_bits(row);
     }
@@ -1143,7 +1144,7 @@ pub fn rows(&self) -> impl Iterator<Item = R> {
 
     /// Iterates through all the columns set to true in a given row of
     /// the matrix.
-    pub fn iter(&self, row: R) -> impl Iterator<Item = C> + '_ {
+    pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
         self.row(row).into_iter().flat_map(|r| r.iter())
     }
 
index 69578e85f278175564365086d13d8f4bb22cea4e..45639bad24313164070e1ce4ae9162b3e71aa8b7 100644 (file)
@@ -124,10 +124,7 @@ impl $type {
 
             #[inline]
             $v const fn from_usize(value: usize) -> Self {
-                #[cfg(not(bootstrap))]
                 assert!(value <= ($max as usize));
-                #[cfg(bootstrap)]
-                [()][(value > ($max as usize)) as usize];
                 unsafe {
                     Self::from_u32_unchecked(value as u32)
                 }
@@ -135,10 +132,7 @@ impl $type {
 
             #[inline]
             $v const fn from_u32(value: u32) -> Self {
-                #[cfg(not(bootstrap))]
                 assert!(value <= $max);
-                #[cfg(bootstrap)]
-                [()][(value > $max) as usize];
                 unsafe {
                     Self::from_u32_unchecked(value)
                 }
@@ -634,15 +628,18 @@ pub fn iter_enumerated_mut(
     }
 
     #[inline]
-    pub fn drain<R: RangeBounds<usize>>(&mut self, range: R) -> impl Iterator<Item = T> + '_ {
+    pub fn drain<'a, R: RangeBounds<usize>>(
+        &'a mut self,
+        range: R,
+    ) -> impl Iterator<Item = T> + 'a {
         self.raw.drain(range)
     }
 
     #[inline]
-    pub fn drain_enumerated<R: RangeBounds<usize>>(
-        &mut self,
+    pub fn drain_enumerated<'a, R: RangeBounds<usize>>(
+        &'a mut self,
         range: R,
-    ) -> impl Iterator<Item = (I, T)> + '_ {
+    ) -> impl Iterator<Item = (I, T)> + 'a {
         self.raw.drain(range).enumerate().map(|(n, t)| (I::new(n), t))
     }
 
index 3f54247ecef211bcd48e6e621b05d39037193e15..09bfb3290f4ca7d8f4956d6cb379bf2cde3fec34 100644 (file)
@@ -866,6 +866,7 @@ fn binders<T>(
         Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
     fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         debug_assert_eq!(t, _t);
         debug!("ConstInferUnifier: t={:?}", t);
@@ -941,6 +942,7 @@ fn regions(
         }
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
     fn consts(
         &mut self,
         c: &'tcx ty::Const<'tcx>,
@@ -951,29 +953,38 @@ fn consts(
 
         match c.val {
             ty::ConstKind::Infer(InferConst::Var(vid)) => {
-                let mut inner = self.infcx.inner.borrow_mut();
-                let variable_table = &mut inner.const_unification_table();
-
                 // Check if the current unification would end up
                 // unifying `target_vid` with a const which contains
                 // an inference variable which is unioned with `target_vid`.
                 //
                 // Not doing so can easily result in stack overflows.
-                if variable_table.unioned(self.target_vid, vid) {
+                if self
+                    .infcx
+                    .inner
+                    .borrow_mut()
+                    .const_unification_table()
+                    .unioned(self.target_vid, vid)
+                {
                     return Err(TypeError::CyclicConst(c));
                 }
 
-                let var_value = variable_table.probe_value(vid);
+                let var_value =
+                    self.infcx.inner.borrow_mut().const_unification_table().probe_value(vid);
                 match var_value.val {
                     ConstVariableValue::Known { value: u } => self.consts(u, u),
                     ConstVariableValue::Unknown { universe } => {
                         if self.for_universe.can_name(universe) {
                             Ok(c)
                         } else {
-                            let new_var_id = variable_table.new_key(ConstVarValue {
-                                origin: var_value.origin,
-                                val: ConstVariableValue::Unknown { universe: self.for_universe },
-                            });
+                            let new_var_id =
+                                self.infcx.inner.borrow_mut().const_unification_table().new_key(
+                                    ConstVarValue {
+                                        origin: var_value.origin,
+                                        val: ConstVariableValue::Unknown {
+                                            universe: self.for_universe,
+                                        },
+                                    },
+                                );
                             Ok(self.tcx().mk_const_var(new_var_id, c.ty))
                         }
                     }
index 126c25f0c38c7819164eebe6f65ac658f11ef73a..2173ff1f9ab035823c013e08abc3d757ea9602d3 100644 (file)
@@ -386,21 +386,6 @@ pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) {
 
                         self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit();
                     }
-
-                    RegionResolutionError::MemberConstraintFailure {
-                        hidden_ty,
-                        member_region,
-                        span,
-                    } => {
-                        let hidden_ty = self.resolve_vars_if_possible(hidden_ty);
-                        unexpected_hidden_region_diagnostic(
-                            self.tcx,
-                            span,
-                            hidden_ty,
-                            member_region,
-                        )
-                        .emit();
-                    }
                 }
             }
         }
@@ -438,8 +423,7 @@ fn process_errors(
             RegionResolutionError::GenericBoundFailure(..) => true,
             RegionResolutionError::ConcreteFailure(..)
             | RegionResolutionError::SubSupConflict(..)
-            | RegionResolutionError::UpperBoundUniverseConflict(..)
-            | RegionResolutionError::MemberConstraintFailure { .. } => false,
+            | RegionResolutionError::UpperBoundUniverseConflict(..) => false,
         };
 
         let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
@@ -454,7 +438,6 @@ fn process_errors(
             RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
             RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
             RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
-            RegionResolutionError::MemberConstraintFailure { span, .. } => span,
         });
         errors
     }
index 1b35c4032f44c5d14e3fe30e935deb79a7dc4a64..ac57796763fb3cf30082f085707e5428cdd6785e 100644 (file)
@@ -7,7 +7,10 @@
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::SubregionOrigin;
 
-use rustc_errors::{struct_span_err, ErrorReported};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
+use rustc_hir as hir;
+use rustc_hir::{GenericParamKind, Ty};
+use rustc_middle::ty::Region;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when both the concerned regions are anonymous.
@@ -160,11 +163,13 @@ pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> {
                 }
             };
 
-        let mut e = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
+        let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
 
-        e.span_label(span_1, main_label);
-        e.span_label(span_2, String::new());
-        e.span_label(span, span_label);
+        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
@@ -178,14 +183,87 @@ pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> {
                     (_, "") => None,
                     _ => Some(s),
                 })
-                .unwrap_or("{unnamed_type}".to_string());
+                .unwrap_or_else(|| "{unnamed_type}".to_string());
 
-            e.span_label(
+            err.span_label(
                 t.span,
                 &format!("this `async fn` implicitly returns an `impl Future<Output = {}>`", snip),
             );
         }
-        e.emit();
+        err.emit();
         Some(ErrorReported)
     }
+
+    fn suggest_adding_lifetime_params(
+        &self,
+        sub: Region<'tcx>,
+        ty_sup: &Ty<'_>,
+        ty_sub: &Ty<'_>,
+        err: &mut DiagnosticBuilder<'_>,
+    ) {
+        if let (
+            hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
+            hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
+        ) = (ty_sub, ty_sup)
+        {
+            if lifetime_sub.name.is_elided() && lifetime_sup.name.is_elided() {
+                if let Some(anon_reg) = self.tcx().is_suitable_region(sub) {
+                    let hir_id = self.tcx().hir().local_def_id_to_hir_id(anon_reg.def_id);
+                    if let hir::Node::Item(&hir::Item {
+                        kind: hir::ItemKind::Fn(_, ref generics, ..),
+                        ..
+                    }) = self.tcx().hir().get(hir_id)
+                    {
+                        let (suggestion_param_name, introduce_new) = generics
+                            .params
+                            .iter()
+                            .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+                            .and_then(|p| self.tcx().sess.source_map().span_to_snippet(p.span).ok())
+                            .map(|name| (name, false))
+                            .unwrap_or_else(|| ("'a".to_string(), true));
+
+                        let mut suggestions = vec![
+                            if let hir::LifetimeName::Underscore = lifetime_sub.name {
+                                (lifetime_sub.span, suggestion_param_name.clone())
+                            } else {
+                                (
+                                    lifetime_sub.span.shrink_to_hi(),
+                                    suggestion_param_name.clone() + " ",
+                                )
+                            },
+                            if let hir::LifetimeName::Underscore = lifetime_sup.name {
+                                (lifetime_sup.span, suggestion_param_name.clone())
+                            } else {
+                                (
+                                    lifetime_sup.span.shrink_to_hi(),
+                                    suggestion_param_name.clone() + " ",
+                                )
+                            },
+                        ];
+
+                        if introduce_new {
+                            let new_param_suggestion = match &generics.params {
+                                [] => (generics.span, format!("<{}>", suggestion_param_name)),
+                                [first, ..] => (
+                                    first.span.shrink_to_lo(),
+                                    format!("{}, ", suggestion_param_name),
+                                ),
+                            };
+
+                            suggestions.push(new_param_suggestion);
+                        }
+
+                        err.multipart_suggestion(
+                            "consider introducing a named lifetime parameter",
+                            suggestions,
+                            Applicability::MaybeIncorrect,
+                        );
+                        err.note(
+                            "each elided lifetime in input position becomes a distinct lifetime",
+                        );
+                    }
+                }
+            }
+        }
+    }
 }
index 7fba6a823d75ee4e40a62365a655dee1aed4c99e..c6ccd9b60a9c44ba0a788cc067c95ca7aae116b4 100644 (file)
@@ -263,9 +263,7 @@ pub fn suggest_new_region_bound(
         match fn_return.kind {
             TyKind::OpaqueDef(item_id, _) => {
                 let item = tcx.hir().item(item_id);
-                let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
-                    opaque
-                } else {
+                let ItemKind::OpaqueTy(opaque) = &item.kind else {
                     return;
                 };
 
index ea9d0eae17e2c46b27a713da65513ef1351e6af9..b9e7ee12bc86df55872e82a103729820232a1483 100644 (file)
@@ -9,10 +9,13 @@
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
-use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::print::RegionHighlightMode;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+
 use rustc_span::{MultiSpan, Span, Symbol};
 
+use std::ops::ControlFlow;
+
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
     pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorReported> {
@@ -69,6 +72,47 @@ fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id:
             .tcx()
             .sess
             .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
+
+        // Mark all unnamed regions in the type with a number.
+        // This diagnostic is called in response to lifetime errors, so be informative.
+        struct HighlightBuilder<'tcx> {
+            highlight: RegionHighlightMode,
+            tcx: TyCtxt<'tcx>,
+            counter: usize,
+        }
+
+        impl HighlightBuilder<'tcx> {
+            fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode {
+                let mut builder =
+                    HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1, tcx };
+                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)
+            }
+
+            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);
+                    self.counter += 1;
+                }
+                r.super_visit_with(self)
+            }
+        }
+
+        let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
+        let expected = self
+            .infcx
+            .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
+            .name;
+        let found_highlight = HighlightBuilder::build(self.tcx(), found);
+        let found =
+            self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
+
         err.span_label(sp, &format!("found `{}`", found));
         err.span_label(trait_sp, &format!("expected `{}`", expected));
 
@@ -96,15 +140,8 @@ fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id:
             );
         }
 
-        if let Some((expected, found)) =
-            self.infcx.expected_found_str_ty(ExpectedFound { expected, found })
-        {
-            // Highlighted the differences when showing the "expected/found" note.
-            err.note_expected_found(&"", expected, &"", found);
-        } else {
-            // This fallback shouldn't be necessary, but let's keep it in just in case.
-            err.note(&format!("expected `{}`\n   found `{}`", expected, found));
-        }
+        err.note(&format!("expected `{}`\n   found `{}`", expected, found));
+
         err.span_help(
             type_param_span,
             "the lifetime requirements from the `impl` do not correspond to the requirements in \
index 8dcdd4b149ea6c23ebe17f76468726dc4ed92ae2..90bc5b3b2fed1296849bd54b73816031674f7747 100644 (file)
@@ -143,9 +143,8 @@ 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_like = rustc_middle::hir::map::blocks::FnLikeNode::from_node(node)?;
-
-        Some(fn_like.asyncness())
+        let fn_kind = node.fn_kind()?;
+        Some(fn_kind.asyncness())
     }
 
     // Here, we check for the case where the anonymous region
index 5f99a23f86e88b1d2df0045f1f0264e585b27fe2..167a8893a11c88aded07e7fac752865577cd5816 100644 (file)
@@ -53,9 +53,6 @@ pub(super) fn note_region_origin(
             infer::RelateObjectBound(span) => {
                 label_or_note(span, "...so that it can be closed over into an object");
             }
-            infer::CallReturn(span) => {
-                label_or_note(span, "...so that return value is valid for the call");
-            }
             infer::DataBorrowed(ty, span) => {
                 label_or_note(
                     span,
@@ -281,23 +278,6 @@ pub(super) fn report_concrete_failure(
                 );
                 err
             }
-            infer::CallReturn(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0482,
-                    "lifetime of return value does not outlive the function call"
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "the return value is only valid for ",
-                    sup,
-                    "",
-                    None,
-                );
-                err
-            }
             infer::DataBorrowed(ty, span) => {
                 let mut err = struct_span_err!(
                     self.tcx.sess,
index 728dc2de370319897fee6eb3dff68a2e66940bd1..4814b65e320abaaadcad162517586d594dc87b47 100644 (file)
@@ -66,8 +66,6 @@ pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
     /// follows. If we know that `r_b: 'static`, then this function
     /// will return true, even though we don't know anything that
     /// directly relates `r_a` and `r_b`.
-    ///
-    /// Also available through the `FreeRegionRelations` trait below.
     pub fn sub_free_regions(
         &self,
         tcx: TyCtxt<'tcx>,
@@ -131,27 +129,6 @@ pub fn lub_free_regions(
     }
 }
 
-/// The NLL region handling code represents free region relations in a
-/// slightly different way; this trait allows functions to be abstract
-/// over which version is in use.
-pub trait FreeRegionRelations<'tcx> {
-    /// Tests whether `r_a <= r_b`. Both must be free regions or
-    /// `'static`.
-    fn sub_free_regions(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        shorter: ty::Region<'tcx>,
-        longer: ty::Region<'tcx>,
-    ) -> bool;
-}
-
-impl<'tcx> FreeRegionRelations<'tcx> for FreeRegionMap<'tcx> {
-    fn sub_free_regions(&self, tcx: TyCtxt<'tcx>, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
-        // invoke the "inherent method"
-        self.sub_free_regions(tcx, r_a, r_b)
-    }
-}
-
 impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
     type Lifted = FreeRegionMap<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
index 869fd225d5114766625630418f73d2b61023dd1c..4c9dcab26b14f073e0a7ecf578b5d4b5c13d3ec1 100644 (file)
@@ -2,7 +2,6 @@
 
 use crate::infer::region_constraints::Constraint;
 use crate::infer::region_constraints::GenericKind;
-use crate::infer::region_constraints::MemberConstraint;
 use crate::infer::region_constraints::RegionConstraintData;
 use crate::infer::region_constraints::VarInfos;
 use crate::infer::region_constraints::VerifyBound;
@@ -20,7 +19,6 @@
 use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
 use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
 use rustc_middle::ty::{Region, RegionVid};
-use rustc_span::Span;
 use std::fmt;
 
 /// This function performs lexical region resolution given a complete
 /// iteration to find region values which satisfy all constraints,
 /// assuming such values can be found. It returns the final values of
 /// all the variables as well as a set of errors that must be reported.
+#[instrument(level = "debug", skip(region_rels, var_infos, data))]
 pub fn resolve<'tcx>(
     region_rels: &RegionRelations<'_, 'tcx>,
     var_infos: VarInfos,
     data: RegionConstraintData<'tcx>,
     mode: RegionckMode,
 ) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) {
-    debug!("RegionConstraintData: resolve_regions()");
     let mut errors = vec![];
     let mut resolver = LexicalResolver { region_rels, var_infos, data };
     match mode {
@@ -109,11 +107,6 @@ pub enum RegionResolutionError<'tcx> {
         SubregionOrigin<'tcx>, // cause of the constraint
         Region<'tcx>,          // the placeholder `'b`
     ),
-
-    /// Indicates a failure of a `MemberConstraint`. These arise during
-    /// impl trait processing explicitly -- basically, the impl trait's hidden type
-    /// included some region that it was not supposed to.
-    MemberConstraintFailure { span: Span, hidden_ty: Ty<'tcx>, member_region: Region<'tcx> },
 }
 
 struct RegionAndOrigin<'tcx> {
@@ -150,12 +143,7 @@ fn infer_variable_values(
 
         let graph = self.construct_graph();
         self.expand_givens(&graph);
-        loop {
-            self.expansion(&mut var_data);
-            if !self.enforce_member_constraints(&graph, &mut var_data) {
-                break;
-            }
-        }
+        self.expansion(&mut var_data);
         self.collect_errors(&mut var_data, errors);
         self.collect_var_errors(&var_data, &graph, errors);
         var_data
@@ -233,120 +221,6 @@ fn expand_givens(&mut self, graph: &RegionGraph<'_>) {
         }
     }
 
-    /// Enforce all member constraints and return true if anything
-    /// changed. See `enforce_member_constraint` for more details.
-    fn enforce_member_constraints(
-        &self,
-        graph: &RegionGraph<'tcx>,
-        var_values: &mut LexicalRegionResolutions<'tcx>,
-    ) -> bool {
-        // Note: we don't use the `any` combinator because we don't
-        // want to stop at the first constraint that makes a change.
-        let mut any_changed = false;
-        for member_constraint in &self.data.member_constraints {
-            any_changed |= self.enforce_member_constraint(graph, member_constraint, var_values);
-        }
-        any_changed
-    }
-
-    /// Enforce a constraint like
-    ///
-    /// ```
-    /// 'r member of ['c...]
-    /// ```
-    ///
-    /// We look for all choice regions from the list `'c...` that:
-    ///
-    /// (a) are greater than the current value of `'r` (which is a lower bound)
-    ///
-    /// and
-    ///
-    /// (b) are compatible with the upper bounds of `'r` that we can
-    /// find by traversing the graph.
-    ///
-    /// From that list, we look for a *minimal* option `'c_min`. If we
-    /// find one, then we can enforce that `'r: 'c_min`.
-    fn enforce_member_constraint(
-        &self,
-        graph: &RegionGraph<'tcx>,
-        member_constraint: &MemberConstraint<'tcx>,
-        var_values: &mut LexicalRegionResolutions<'tcx>,
-    ) -> bool {
-        debug!("enforce_member_constraint(member_constraint={:#?})", member_constraint);
-
-        // The constraint is some inference variable (`vid`) which
-        // must be equal to one of the options.
-        let member_vid = match member_constraint.member_region {
-            ty::ReVar(vid) => *vid,
-            _ => return false,
-        };
-
-        // The current value of `vid` is a lower bound LB -- i.e., we
-        // know that `LB <= vid` must be true.
-        let member_lower_bound: ty::Region<'tcx> = match var_values.value(member_vid) {
-            VarValue::ErrorValue => return false,
-            VarValue::Value(r) => r,
-        };
-
-        // Find all the "upper bounds" -- that is, each region `b` such that
-        // `r0 <= b` must hold.
-        let (member_upper_bounds, ..) =
-            self.collect_bounding_regions(graph, member_vid, OUTGOING, None);
-
-        // Get an iterator over the *available choice* -- that is,
-        // each choice region `c` where `lb <= c` and `c <= ub` for all the
-        // upper bounds `ub`.
-        debug!("enforce_member_constraint: upper_bounds={:#?}", member_upper_bounds);
-        let mut options = member_constraint.choice_regions.iter().filter(|option| {
-            self.sub_concrete_regions(member_lower_bound, option)
-                && member_upper_bounds
-                    .iter()
-                    .all(|upper_bound| self.sub_concrete_regions(option, upper_bound.region))
-        });
-
-        // If there is more than one option, we only make a choice if
-        // there is a single *least* choice -- i.e., some available
-        // region that is `<=` all the others.
-        let mut least_choice: ty::Region<'tcx> = match options.next() {
-            Some(&r) => r,
-            None => return false,
-        };
-        debug!("enforce_member_constraint: least_choice={:?}", least_choice);
-        for &option in options {
-            debug!("enforce_member_constraint: option={:?}", option);
-            if !self.sub_concrete_regions(least_choice, option) {
-                if self.sub_concrete_regions(option, least_choice) {
-                    debug!("enforce_member_constraint: new least choice");
-                    least_choice = option;
-                } else {
-                    debug!("enforce_member_constraint: no least choice");
-                    return false;
-                }
-            }
-        }
-
-        // (#72087) Different `ty::Regions` can be known to be equal, for
-        // example, we know that `'a` and `'static` are equal in a function
-        // with a parameter of type `&'static &'a ()`.
-        //
-        // When we have two equal regions like this `expansion` will use
-        // `lub_concrete_regions` to pick a canonical representative. The same
-        // choice is needed here so that we don't end up in a cycle of
-        // `expansion` changing the region one way and the code here changing
-        // it back.
-        let lub = self.lub_concrete_regions(least_choice, member_lower_bound);
-        debug!(
-            "enforce_member_constraint: final least choice = {:?}\nlub = {:?}",
-            least_choice, lub
-        );
-        if lub != member_lower_bound {
-            *var_values.value_mut(member_vid) = VarValue::Value(least_choice);
-            true
-        } else {
-            false
-        }
-    }
-
     fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
         let mut constraints = IndexVec::from_elem_n(Vec::new(), var_values.values.len());
         let mut changes = Vec::new();
@@ -461,6 +335,7 @@ fn expand_node(
     }
 
     /// True if `a <= b`, but not defined over inference variables.
+    #[instrument(level = "trace", skip(self))]
     fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
         let tcx = self.tcx();
         let sub_free_regions = |r1, r2| self.region_rels.free_regions.sub_free_regions(tcx, r1, r2);
@@ -492,6 +367,7 @@ fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
     ///
     /// Neither `a` nor `b` may be an inference variable (hence the
     /// term "concrete regions").
+    #[instrument(level = "trace", skip(self))]
     fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
         let r = match (a, b) {
             (&ReLateBound(..), _) | (_, &ReLateBound(..)) | (&ReErased, _) | (_, &ReErased) => {
@@ -562,13 +438,14 @@ fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx>
     /// After expansion is complete, go and check upper bounds (i.e.,
     /// cases where the region cannot grow larger than a fixed point)
     /// and check that they are satisfied.
+    #[instrument(skip(self, var_data, errors))]
     fn collect_errors(
         &self,
         var_data: &mut LexicalRegionResolutions<'tcx>,
         errors: &mut Vec<RegionResolutionError<'tcx>>,
     ) {
         for (constraint, origin) in &self.data.constraints {
-            debug!("collect_errors: constraint={:?} origin={:?}", constraint, origin);
+            debug!(?constraint, ?origin);
             match *constraint {
                 Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
                     // Expansion will ensure that these constraints hold. Ignore.
@@ -580,7 +457,7 @@ fn collect_errors(
                     }
 
                     debug!(
-                        "collect_errors: region error at {:?}: \
+                        "region error at {:?}: \
                          cannot verify that {:?} <= {:?}",
                         origin, sub, sup
                     );
@@ -606,7 +483,7 @@ fn collect_errors(
                     // collect them later.
                     if !self.sub_concrete_regions(a_region, b_region) {
                         debug!(
-                            "collect_errors: region error at {:?}: \
+                            "region error at {:?}: \
                             cannot verify that {:?}={:?} <= {:?}",
                             origin, a_vid, a_region, b_region
                         );
@@ -616,23 +493,6 @@ fn collect_errors(
             }
         }
 
-        // Check that all member constraints are satisfied.
-        for member_constraint in &self.data.member_constraints {
-            let member_region = var_data.normalize(self.tcx(), member_constraint.member_region);
-            let choice_regions = member_constraint
-                .choice_regions
-                .iter()
-                .map(|&choice_region| var_data.normalize(self.tcx(), choice_region));
-            if !choice_regions.clone().any(|choice_region| member_region == choice_region) {
-                let span = self.tcx().def_span(member_constraint.opaque_type_def_id);
-                errors.push(RegionResolutionError::MemberConstraintFailure {
-                    span,
-                    hidden_ty: member_constraint.hidden_ty,
-                    member_region,
-                });
-            }
-        }
-
         for verify in &self.data.verifys {
             debug!("collect_errors: verify={:?}", verify);
             let sub = var_data.normalize(self.tcx(), verify.region);
index ad716c76c80aa3ef21f87b0ec5300b0cca3fb491..9dae978dcde7d9b79dd59c74335b6d2529a0684c 100644 (file)
@@ -417,9 +417,6 @@ pub enum SubregionOrigin<'tcx> {
     /// (&'a &'b T) where a >= b
     ReferenceOutlivesReferent(Ty<'tcx>, Span),
 
-    /// Region in return type of invoked fn must enclose call
-    CallReturn(Span),
-
     /// Comparing the signature and requirements of an impl method against
     /// the containing trait.
     CompareImplMethodObligation {
@@ -1818,7 +1815,6 @@ pub fn span(&self) -> Span {
             ReborrowUpvar(a, _) => a,
             DataBorrowed(_, a) => a,
             ReferenceOutlivesReferent(_, a) => a,
-            CallReturn(a) => a,
             CompareImplMethodObligation { span, .. } => span,
             CompareImplTypeObligation { span, .. } => span,
         }
index d0883f23a4e6bb9237a7c8b83aa17f0dca6beb2c..e2e07f2072e498ea907e7fb176ed0ff9e9d811f2 100644 (file)
@@ -1,8 +1,17 @@
+use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::infer::{InferCtxt, InferOk};
+use crate::traits;
+use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_hir as hir;
-use rustc_middle::ty::{OpaqueTypeKey, Ty};
+use rustc_hir::def_id::LocalDefId;
+use rustc_middle::ty::fold::BottomUpFolder;
+use rustc_middle::ty::subst::{GenericArgKind, Subst};
+use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 use rustc_span::Span;
 
+use std::ops::ControlFlow;
+
 pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
 
 /// Information about the opaque types whose values we
@@ -45,3 +54,584 @@ pub struct OpaqueTypeDecl<'tcx> {
     /// The origin of the opaque type.
     pub origin: hir::OpaqueTyOrigin,
 }
+
+impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+    /// Replaces all opaque types in `value` with fresh inference variables
+    /// and creates appropriate obligations. For example, given the input:
+    ///
+    ///     impl Iterator<Item = impl Debug>
+    ///
+    /// this method would create two type variables, `?0` and `?1`. It would
+    /// return the type `?0` but also the obligations:
+    ///
+    ///     ?0: Iterator<Item = ?1>
+    ///     ?1: Debug
+    ///
+    /// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to
+    /// info about the `impl Iterator<..>` type and `?1` to info about
+    /// the `impl Debug` type.
+    ///
+    /// # Parameters
+    ///
+    /// - `parent_def_id` -- the `DefId` of the function in which the opaque type
+    ///   is defined
+    /// - `body_id` -- the body-id with which the resulting obligations should
+    ///   be associated
+    /// - `param_env` -- the in-scope parameter environment to be used for
+    ///   obligations
+    /// - `value` -- the value within which we are instantiating opaque types
+    /// - `value_span` -- the span where the value came from, used in error reporting
+    pub fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
+        &self,
+        body_id: hir::HirId,
+        param_env: ty::ParamEnv<'tcx>,
+        value: T,
+        value_span: Span,
+    ) -> InferOk<'tcx, T> {
+        debug!(
+            "instantiate_opaque_types(value={:?}, body_id={:?}, \
+             param_env={:?}, value_span={:?})",
+            value, body_id, param_env, value_span,
+        );
+        let mut instantiator =
+            Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
+        let value = instantiator.instantiate_opaque_types_in_map(value);
+        InferOk { value, obligations: instantiator.obligations }
+    }
+
+    /// Given the map `opaque_types` containing the opaque
+    /// `impl Trait` types whose underlying, hidden types are being
+    /// inferred, this method adds constraints to the regions
+    /// appearing in those underlying hidden types to ensure that they
+    /// at least do not refer to random scopes within the current
+    /// function. These constraints are not (quite) sufficient to
+    /// guarantee that the regions are actually legal values; that
+    /// final condition is imposed after region inference is done.
+    ///
+    /// # The Problem
+    ///
+    /// Let's work through an example to explain how it works. Assume
+    /// the current function is as follows:
+    ///
+    /// ```text
+    /// fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>)
+    /// ```
+    ///
+    /// Here, we have two `impl Trait` types whose values are being
+    /// inferred (the `impl Bar<'a>` and the `impl
+    /// Bar<'b>`). Conceptually, this is sugar for a setup where we
+    /// define underlying opaque types (`Foo1`, `Foo2`) and then, in
+    /// the return type of `foo`, we *reference* those definitions:
+    ///
+    /// ```text
+    /// type Foo1<'x> = impl Bar<'x>;
+    /// type Foo2<'x> = impl Bar<'x>;
+    /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
+    ///                    //  ^^^^ ^^
+    ///                    //  |    |
+    ///                    //  |    substs
+    ///                    //  def_id
+    /// ```
+    ///
+    /// As indicating in the comments above, each of those references
+    /// is (in the compiler) basically a substitution (`substs`)
+    /// applied to the type of a suitable `def_id` (which identifies
+    /// `Foo1` or `Foo2`).
+    ///
+    /// Now, at this point in compilation, what we have done is to
+    /// replace each of the references (`Foo1<'a>`, `Foo2<'b>`) with
+    /// fresh inference variables C1 and C2. We wish to use the values
+    /// of these variables to infer the underlying types of `Foo1` and
+    /// `Foo2`. That is, this gives rise to higher-order (pattern) unification
+    /// constraints like:
+    ///
+    /// ```text
+    /// for<'a> (Foo1<'a> = C1)
+    /// for<'b> (Foo1<'b> = C2)
+    /// ```
+    ///
+    /// For these equation to be satisfiable, the types `C1` and `C2`
+    /// can only refer to a limited set of regions. For example, `C1`
+    /// can only refer to `'static` and `'a`, and `C2` can only refer
+    /// to `'static` and `'b`. The job of this function is to impose that
+    /// constraint.
+    ///
+    /// Up to this point, C1 and C2 are basically just random type
+    /// inference variables, and hence they may contain arbitrary
+    /// regions. In fact, it is fairly likely that they do! Consider
+    /// this possible definition of `foo`:
+    ///
+    /// ```text
+    /// fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) {
+    ///         (&*x, &*y)
+    ///     }
+    /// ```
+    ///
+    /// Here, the values for the concrete types of the two impl
+    /// traits will include inference variables:
+    ///
+    /// ```text
+    /// &'0 i32
+    /// &'1 i32
+    /// ```
+    ///
+    /// Ordinarily, the subtyping rules would ensure that these are
+    /// sufficiently large. But since `impl Bar<'a>` isn't a specific
+    /// type per se, we don't get such constraints by default. This
+    /// is where this function comes into play. It adds extra
+    /// constraints to ensure that all the regions which appear in the
+    /// inferred type are regions that could validly appear.
+    ///
+    /// This is actually a bit of a tricky constraint in general. We
+    /// want to say that each variable (e.g., `'0`) can only take on
+    /// values that were supplied as arguments to the opaque type
+    /// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in
+    /// scope. We don't have a constraint quite of this kind in the current
+    /// region checker.
+    ///
+    /// # The Solution
+    ///
+    /// We generally prefer to make `<=` constraints, since they
+    /// integrate best into the region solver. To do that, we find the
+    /// "minimum" of all the arguments that appear in the substs: that
+    /// is, some region which is less than all the others. In the case
+    /// of `Foo1<'a>`, that would be `'a` (it's the only choice, after
+    /// all). Then we apply that as a least bound to the variables
+    /// (e.g., `'a <= '0`).
+    ///
+    /// In some cases, there is no minimum. Consider this example:
+    ///
+    /// ```text
+    /// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... }
+    /// ```
+    ///
+    /// Here we would report a more complex "in constraint", like `'r
+    /// in ['a, 'b, 'static]` (where `'r` is some region appearing in
+    /// the hidden type).
+    ///
+    /// # Constrain regions, not the hidden concrete type
+    ///
+    /// Note that generating constraints on each region `Rc` is *not*
+    /// the same as generating an outlives constraint on `Tc` iself.
+    /// For example, if we had a function like this:
+    ///
+    /// ```rust
+    /// fn foo<'a, T>(x: &'a u32, y: T) -> impl Foo<'a> {
+    ///   (x, y)
+    /// }
+    ///
+    /// // Equivalent to:
+    /// type FooReturn<'a, T> = impl Foo<'a>;
+    /// fn foo<'a, T>(..) -> FooReturn<'a, T> { .. }
+    /// ```
+    ///
+    /// then the hidden type `Tc` would be `(&'0 u32, T)` (where `'0`
+    /// is an inference variable). If we generated a constraint that
+    /// `Tc: 'a`, then this would incorrectly require that `T: 'a` --
+    /// but this is not necessary, because the opaque type we
+    /// create will be allowed to reference `T`. So we only generate a
+    /// constraint that `'0: 'a`.
+    ///
+    /// # The `free_region_relations` parameter
+    ///
+    /// The `free_region_relations` argument is used to find the
+    /// "minimum" of the regions supplied to a given opaque type.
+    /// It must be a relation that can answer whether `'a <= 'b`,
+    /// where `'a` and `'b` are regions that appear in the "substs"
+    /// for the opaque type references (the `<'a>` in `Foo1<'a>`).
+    ///
+    /// Note that we do not impose the constraints based on the
+    /// generic regions from the `Foo1` definition (e.g., `'x`). This
+    /// is because the constraints we are imposing here is basically
+    /// the concern of the one generating the constraining type C1,
+    /// which is the current function. It also means that we can
+    /// take "implied bounds" into account in some cases:
+    ///
+    /// ```text
+    /// trait SomeTrait<'a, 'b> { }
+    /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. }
+    /// ```
+    ///
+    /// Here, the fact that `'b: 'a` is known only because of the
+    /// implied bounds from the `&'a &'b u32` parameter, and is not
+    /// "inherent" to the opaque type definition.
+    ///
+    /// # Parameters
+    ///
+    /// - `opaque_types` -- the map produced by `instantiate_opaque_types`
+    /// - `free_region_relations` -- something that can be used to relate
+    ///   the free regions (`'a`) that appear in the impl trait.
+    #[instrument(level = "debug", skip(self))]
+    pub fn constrain_opaque_type(
+        &self,
+        opaque_type_key: OpaqueTypeKey<'tcx>,
+        opaque_defn: &OpaqueTypeDecl<'tcx>,
+    ) {
+        let def_id = opaque_type_key.def_id;
+
+        let tcx = self.tcx;
+
+        let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
+
+        debug!(?concrete_ty);
+
+        let first_own_region = match opaque_defn.origin {
+            hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => {
+                // We lower
+                //
+                // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
+                //
+                // into
+                //
+                // type foo::<'p0..'pn>::Foo<'q0..'qm>
+                // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
+                //
+                // For these types we only iterate over `'l0..lm` below.
+                tcx.generics_of(def_id).parent_count
+            }
+            // These opaque type inherit all lifetime parameters from their
+            // parent, so we have to check them all.
+            hir::OpaqueTyOrigin::TyAlias => 0,
+        };
+
+        // For a case like `impl Foo<'a, 'b>`, we would generate a constraint
+        // `'r in ['a, 'b, 'static]` for each region `'r` that appears in the
+        // hidden type (i.e., it must be equal to `'a`, `'b`, or `'static`).
+        //
+        // `conflict1` and `conflict2` are the two region bounds that we
+        // detected which were unrelated. They are used for diagnostics.
+
+        // Create the set of choice regions: each region in the hidden
+        // type can be equal to any of the region parameters of the
+        // opaque type definition.
+        let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
+            opaque_type_key.substs[first_own_region..]
+                .iter()
+                .filter_map(|arg| match arg.unpack() {
+                    GenericArgKind::Lifetime(r) => Some(r),
+                    GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
+                })
+                .chain(std::iter::once(self.tcx.lifetimes.re_static))
+                .collect(),
+        );
+
+        concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
+            tcx: self.tcx,
+            op: |r| {
+                self.member_constraint(
+                    opaque_type_key.def_id,
+                    opaque_defn.definition_span,
+                    concrete_ty,
+                    r,
+                    &choice_regions,
+                )
+            },
+        });
+    }
+}
+
+// Visitor that requires that (almost) all regions in the type visited outlive
+// `least_region`. We cannot use `push_outlives_components` because regions in
+// closure signatures are not included in their outlives components. We need to
+// ensure all regions outlive the given bound so that we don't end up with,
+// say, `ReVar` appearing in a return type and causing ICEs when other
+// functions end up with region constraints involving regions from other
+// functions.
+//
+// We also cannot use `for_each_free_region` because for closures it includes
+// the regions parameters from the enclosing item.
+//
+// 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>,
+    op: OP,
+}
+
+impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, 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>,
+    ) -> ControlFlow<Self::BreakTy> {
+        t.as_ref().skip_binder().visit_with(self);
+        ControlFlow::CONTINUE
+    }
+
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+        match *r {
+            // ignore bound regions, keep visiting
+            ty::ReLateBound(_, _) => ControlFlow::CONTINUE,
+            _ => {
+                (self.op)(r);
+                ControlFlow::CONTINUE
+            }
+        }
+    }
+
+    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) {
+            return ControlFlow::CONTINUE;
+        }
+
+        match ty.kind() {
+            ty::Closure(_, ref substs) => {
+                // Skip lifetime parameters of the enclosing item(s)
+
+                substs.as_closure().tupled_upvars_ty().visit_with(self);
+                substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
+            }
+
+            ty::Generator(_, ref substs, _) => {
+                // Skip lifetime parameters of the enclosing item(s)
+                // Also skip the witness type, because that has no free regions.
+
+                substs.as_generator().tupled_upvars_ty().visit_with(self);
+                substs.as_generator().return_ty().visit_with(self);
+                substs.as_generator().yield_ty().visit_with(self);
+                substs.as_generator().resume_ty().visit_with(self);
+            }
+            _ => {
+                ty.super_visit_with(self);
+            }
+        }
+
+        ControlFlow::CONTINUE
+    }
+}
+
+struct Instantiator<'a, 'tcx> {
+    infcx: &'a InferCtxt<'a, 'tcx>,
+    body_id: hir::HirId,
+    param_env: ty::ParamEnv<'tcx>,
+    value_span: Span,
+    obligations: Vec<traits::PredicateObligation<'tcx>>,
+}
+
+impl<'a, 'tcx> Instantiator<'a, 'tcx> {
+    fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
+        let tcx = self.infcx.tcx;
+        value.fold_with(&mut BottomUpFolder {
+            tcx,
+            ty_op: |ty| {
+                if ty.references_error() {
+                    return tcx.ty_error();
+                } else if let ty::Opaque(def_id, substs) = ty.kind() {
+                    // Check that this is `impl Trait` type is
+                    // declared by `parent_def_id` -- i.e., one whose
+                    // value we are inferring.  At present, this is
+                    // always true during the first phase of
+                    // type-check, but not always true later on during
+                    // NLL. Once we support named opaque types more fully,
+                    // this same scenario will be able to arise during all phases.
+                    //
+                    // Here is an example using type alias `impl Trait`
+                    // that indicates the distinction we are checking for:
+                    //
+                    // ```rust
+                    // mod a {
+                    //   pub type Foo = impl Iterator;
+                    //   pub fn make_foo() -> Foo { .. }
+                    // }
+                    //
+                    // mod b {
+                    //   fn foo() -> a::Foo { a::make_foo() }
+                    // }
+                    // ```
+                    //
+                    // Here, the return type of `foo` references an
+                    // `Opaque` indeed, but not one whose value is
+                    // presently being inferred. You can get into a
+                    // similar situation with closure return types
+                    // today:
+                    //
+                    // ```rust
+                    // fn foo() -> impl Iterator { .. }
+                    // fn bar() {
+                    //     let x = || foo(); // returns the Opaque assoc with `foo`
+                    // }
+                    // ```
+                    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 def_scope_default = || {
+                            let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
+                            parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
+                        };
+                        let (in_definition_scope, origin) =
+                            match tcx.hir().expect_item(opaque_hir_id).kind {
+                                // Anonymous `impl Trait`
+                                hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+                                    impl_trait_fn: Some(parent),
+                                    origin,
+                                    ..
+                                }) => (parent == parent_def_id.to_def_id(), origin),
+                                // Named `type Foo = impl Bar;`
+                                hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+                                    impl_trait_fn: None,
+                                    origin,
+                                    ..
+                                }) => (
+                                    may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
+                                    origin,
+                                ),
+                                _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
+                            };
+                        if in_definition_scope {
+                            let opaque_type_key =
+                                OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
+                            return self.fold_opaque_ty(ty, opaque_type_key, origin);
+                        }
+
+                        debug!(
+                            "instantiate_opaque_types_in_map: \
+                             encountered opaque outside its definition scope \
+                             def_id={:?}",
+                            def_id,
+                        );
+                    }
+                }
+
+                ty
+            },
+            lt_op: |lt| lt,
+            ct_op: |ct| ct,
+        })
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn fold_opaque_ty(
+        &mut self,
+        ty: Ty<'tcx>,
+        opaque_type_key: OpaqueTypeKey<'tcx>,
+        origin: hir::OpaqueTyOrigin,
+    ) -> Ty<'tcx> {
+        let infcx = self.infcx;
+        let tcx = infcx.tcx;
+        let OpaqueTypeKey { def_id, substs } = opaque_type_key;
+
+        // Use the same type variable if the exact same opaque type appears more
+        // than once in the return type (e.g., if it's passed to a type alias).
+        if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
+            debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
+            return opaque_defn.concrete_ty;
+        }
+
+        let ty_var = infcx.next_ty_var(TypeVariableOrigin {
+            kind: TypeVariableOriginKind::TypeInference,
+            span: self.value_span,
+        });
+
+        // Ideally, we'd get the span where *this specific `ty` came
+        // from*, but right now we just use the span from the overall
+        // value being folded. In simple cases like `-> impl Foo`,
+        // these are the same span, but not in cases like `-> (impl
+        // Foo, impl Bar)`.
+        let definition_span = self.value_span;
+
+        {
+            let mut infcx = self.infcx.inner.borrow_mut();
+            infcx.opaque_types.insert(
+                OpaqueTypeKey { def_id, substs },
+                OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
+            );
+            infcx.opaque_types_vars.insert(ty_var, ty);
+        }
+
+        debug!("generated new type inference var {:?}", ty_var.kind());
+
+        let item_bounds = tcx.explicit_item_bounds(def_id);
+
+        self.obligations.reserve(item_bounds.len());
+        for (predicate, _) in item_bounds {
+            debug!(?predicate);
+            let predicate = predicate.subst(tcx, substs);
+            debug!(?predicate);
+
+            // 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,
+                ty_op: |ty| match ty.kind() {
+                    ty::Projection(projection_ty) => infcx.infer_projection(
+                        self.param_env,
+                        *projection_ty,
+                        traits::ObligationCause::misc(self.value_span, self.body_id),
+                        0,
+                        &mut self.obligations,
+                    ),
+                    _ => ty,
+                },
+                lt_op: |lt| lt,
+                ct_op: |ct| ct,
+            });
+            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.
+                    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);
+
+            // Require that the predicate holds for the concrete type.
+            debug!(?predicate);
+            self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
+        }
+
+        ty_var
+    }
+}
+
+/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`.
+///
+/// Example:
+/// ```rust
+/// pub mod foo {
+///     pub mod bar {
+///         pub trait Bar { .. }
+///
+///         pub type Baz = impl Bar;
+///
+///         fn f1() -> Baz { .. }
+///     }
+///
+///     fn f2() -> bar::Baz { .. }
+/// }
+/// ```
+///
+/// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`),
+/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`.
+/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
+fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool {
+    let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+    // Named opaque types can be defined by any siblings or children of siblings.
+    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);
+    }
+    // Syntactically, we are allowed to define the concrete type if:
+    let res = hir_id == scope;
+    trace!(
+        "may_define_opaque_type(def={:?}, opaque_node={:?}) = {}",
+        tcx.hir().find(hir_id),
+        tcx.hir().get(opaque_hir_id),
+        res
+    );
+    res
+}
index a4cfaddeeb96f40cce76d3b1cb6f9d098348edca..d0f1ff649d058a0558f80ef9258234fac1fd165a 100644 (file)
@@ -17,6 +17,7 @@
 #![feature(box_patterns)]
 #![feature(extend_one)]
 #![feature(iter_zip)]
+#![feature(let_else)]
 #![feature(never_type)]
 #![feature(in_band_lifetimes)]
 #![feature(control_flow_enum)]
index e1d6982f164448c1f279779e78a2dc55960917ce..e8622b3c819d2316316daa9c3a46aaddcc35181d 100644 (file)
@@ -10,7 +10,7 @@
 
 use rustc_hir as hir;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, Const, Ty};
+use rustc_middle::ty::{self, Const, Ty, TyCtxt};
 use rustc_span::Span;
 
 pub use self::FulfillmentErrorCode::*;
@@ -55,6 +55,20 @@ pub struct Obligation<'tcx, T> {
 pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
 pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
 
+impl PredicateObligation<'tcx> {
+    /// Flips the polarity of the inner predicate.
+    ///
+    /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
+    pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<PredicateObligation<'tcx>> {
+        Some(PredicateObligation {
+            cause: self.cause.clone(),
+            param_env: self.param_env,
+            predicate: self.predicate.flip_polarity(tcx)?,
+            recursion_depth: self.recursion_depth,
+        })
+    }
+}
+
 // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(PredicateObligation<'_>, 32);
@@ -129,6 +143,10 @@ pub fn new(
 }
 
 impl<'tcx> TraitObligation<'tcx> {
+    pub fn polarity(&self) -> ty::ImplPolarity {
+        self.predicate.skip_binder().polarity
+    }
+
     pub fn self_ty(&self) -> ty::Binder<'tcx, Ty<'tcx>> {
         self.predicate.map_bound(|p| p.self_ty())
     }
index 0861bd290df772abaa4c98bb2f293d1e1313d6e5..7a6a643e3d0bb27ed53eb4e764da2f8989dae487 100644 (file)
@@ -38,7 +38,7 @@ pub struct Compiler {
     pub(crate) output_file: Option<PathBuf>,
     pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
     pub(crate) override_queries:
-        Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,
+        Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
 }
 
 impl Compiler {
@@ -75,7 +75,10 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
         let cfg = cfgspecs
             .into_iter()
             .map(|s| {
-                let sess = ParseSess::with_silent_emitter();
+                let sess = ParseSess::with_silent_emitter(Some(format!(
+                    "this error occurred on the command line: `--cfg={}`",
+                    s
+                )));
                 let filename = FileName::cfg_spec_source_code(&s);
                 let mut parser = new_parser_from_source_str(&sess, filename, s.to_string());
 
@@ -152,7 +155,7 @@ pub struct Config {
     ///
     /// The second parameter is local providers and the third parameter is external providers.
     pub override_queries:
-        Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,
+        Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
 
     /// This is a callback from the driver that is called to create a codegen backend.
     pub make_codegen_backend:
index bcfa0ef3520fcc743071ced434ff1b86ab5795b5..62f5f09aa48279a7a1eed4031bd3c858cc11f42d 100644 (file)
@@ -19,7 +19,7 @@
 use rustc_metadata::{encode_metadata, EncodedMetadata};
 use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::DepGraph;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
 use rustc_mir_build as mir_build;
 use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
@@ -764,8 +764,8 @@ pub fn prepare_outputs(
     *providers
 });
 
-pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy<Providers> = SyncLazy::new(|| {
-    let mut extern_providers = *DEFAULT_QUERY_PROVIDERS;
+pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy<ExternProviders> = SyncLazy::new(|| {
+    let mut extern_providers = ExternProviders::default();
     rustc_metadata::provide_extern(&mut extern_providers);
     rustc_codegen_ssa::provide_extern(&mut extern_providers);
     extern_providers
@@ -816,7 +816,6 @@ pub fn create_global_ctxt<'tcx>(
     codegen_backend.provide(&mut local_providers);
 
     let mut extern_providers = *DEFAULT_EXTERN_QUERY_PROVIDERS;
-    codegen_backend.provide(&mut extern_providers);
     codegen_backend.provide_extern(&mut extern_providers);
 
     if let Some(callback) = compiler.override_queries {
@@ -838,6 +837,7 @@ pub fn create_global_ctxt<'tcx>(
                 dep_graph,
                 queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn),
                 queries.as_dyn(),
+                rustc_query_impl::query_callbacks(arena),
                 crate_name,
                 outputs,
             )
index 844e5ab56a420e6bd30fe42caffa51d2d0252f81..2d3cb52f5fd478fc6718f715765ce8375479f73d 100644 (file)
@@ -5,7 +5,9 @@
 use rustc_session::config::InstrumentCoverage;
 use rustc_session::config::Strip;
 use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
-use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
+use rustc_session::config::{
+    rustc_optgroups, ErrorOutputType, ExternLocation, LocationDetail, Options, Passes,
+};
 use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
 use rustc_session::config::{
     Externs, OutputType, OutputTypes, SymbolManglingVersion, WasiExecModel,
@@ -733,6 +735,7 @@ macro_rules! tracked {
     tracked!(instrument_mcount, true);
     tracked!(link_only, true);
     tracked!(llvm_plugins, vec![String::from("plugin_name")]);
+    tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
     tracked!(merge_functions, Some(MergeFunctions::Disabled));
     tracked!(mir_emit_retag, true);
     tracked!(mir_opt_level, Some(4));
@@ -741,6 +744,7 @@ macro_rules! tracked {
     tracked!(new_llvm_pass_manager, Some(true));
     tracked!(no_generate_arange_section, true);
     tracked!(no_link, true);
+    tracked!(no_unique_section_names, true);
     tracked!(no_profiler_runtime, true);
     tracked!(osx_rpath_install_name, true);
     tracked!(panic_abort_tests, true);
index 804dc657f2d473b624610de24a648fe9c556e186..b970c9e4911fafb36ff0612c0e30fb417d46437f 100644 (file)
@@ -68,10 +68,11 @@ pub enum EscapeError {
 impl EscapeError {
     /// Returns true for actual errors, as opposed to warnings.
     pub fn is_fatal(&self) -> bool {
-        !matches!(
-            self,
-            EscapeError::UnskippedWhitespaceWarning | EscapeError::MultipleSkippedLinesWarning
-        )
+        match self {
+            EscapeError::UnskippedWhitespaceWarning => false,
+            EscapeError::MultipleSkippedLinesWarning => false,
+            _ => true,
+        }
     }
 }
 
@@ -329,7 +330,7 @@ fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut
             callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
         }
         let tail = &tail[first_non_space..];
-        if let Some(c) = tail.chars().next() {
+        if let Some(c) = tail.chars().nth(0) {
             // For error reporting, we would like the span to contain the character that was not
             // skipped.  The +1 is necessary to account for the leading \ that started the escape.
             let end = start + first_non_space + c.len_utf8() + 1;
index d147148ac71363f6b2feb1d23c0420e8cda4740b..d8883b0e66dba77be936bb086f2197af5d384880 100644 (file)
@@ -134,9 +134,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
                     Applicability::MachineApplicable,
                 );
                 if self.for_expr_span == expr.span {
-                    let expr_span = expr.span.ctxt().outer_expn_data().call_site;
                     diag.span_suggestion(
-                        receiver_arg.span.shrink_to_hi().to(expr_span.shrink_to_hi()),
+                        receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
                         "or remove `.into_iter()` to iterate by value",
                         String::new(),
                         Applicability::MaybeIncorrect,
index 57c1c8f3ecb5c28f033a29389fdf00edd74291f7..c228ecb03fdec25f1d475fd9d9a2ef63ce0c6f0e 100644 (file)
@@ -657,6 +657,24 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_
             return;
         }
 
+        // 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 impl_ty = cx.tcx.type_of(parent);
+            let outerdef = match impl_ty.kind() {
+                ty::Adt(def, _) => Some(def.did),
+                ty::Foreign(def_id) => Some(*def_id),
+                _ => None,
+            };
+            let is_hidden = match outerdef {
+                Some(id) => cx.tcx.is_doc_hidden(id),
+                None => false,
+            };
+            if is_hidden {
+                return;
+            }
+        }
+
         let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
         self.check_missing_docs_attrs(cx, impl_item.def_id, impl_item.span, article, desc);
     }
index d235b2209444eb8bd7dfb7e6896d416e95597499..6fd0a5b95f9f6e053f41ffa1cbefef1f9c5d9529 100644 (file)
@@ -16,6 +16,7 @@
 
 use self::TargetLint::*;
 
+use crate::hidden_unicode_codepoints::UNICODE_TEXT_FLOW_CHARS;
 use crate::levels::{is_known_lint_tool, LintLevelsBuilder};
 use crate::passes::{EarlyLintPassObject, LateLintPassObject};
 use rustc_ast as ast;
@@ -39,7 +40,7 @@
 use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
 use rustc_session::Session;
 use rustc_span::lev_distance::find_best_match_for_name;
-use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
+use rustc_span::{symbol::Symbol, BytePos, MultiSpan, Span, DUMMY_SP};
 use rustc_target::abi;
 use tracing::debug;
 
@@ -597,6 +598,42 @@ fn lookup_with_diagnostics(
             // Now, set up surrounding context.
             let sess = self.sess();
             match diagnostic {
+                BuiltinLintDiagnostics::UnicodeTextFlow(span, content) => {
+                    let spans: Vec<_> = content
+                        .char_indices()
+                        .filter_map(|(i, c)| {
+                            UNICODE_TEXT_FLOW_CHARS.contains(&c).then(|| {
+                                let lo = span.lo() + BytePos(2 + i as u32);
+                                (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
+                            })
+                        })
+                        .collect();
+                    let (an, s) = match spans.len() {
+                        1 => ("an ", ""),
+                        _ => ("", "s"),
+                    };
+                    db.span_label(span, &format!(
+                        "this comment contains {}invisible unicode text flow control codepoint{}",
+                        an,
+                        s,
+                    ));
+                    for (c, span) in &spans {
+                        db.span_label(*span, format!("{:?}", c));
+                    }
+                    db.note(
+                        "these kind of unicode codepoints change the way text flows on \
+                         applications that support them, but can cause confusion because they \
+                         change the order of characters on the screen",
+                    );
+                    if !spans.is_empty() {
+                        db.multipart_suggestion_with_style(
+                            "if their presence wasn't intentional, you can remove them",
+                            spans.into_iter().map(|(_, span)| (span, "".to_string())).collect(),
+                            Applicability::MachineApplicable,
+                            SuggestionStyle::HideCodeAlways,
+                        );
+                    }
+                },
                 BuiltinLintDiagnostics::Normal => (),
                 BuiltinLintDiagnostics::BareTraitObject(span, is_global) => {
                     let (sugg, app) = match sess.source_map().span_to_snippet(span) {
diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
new file mode 100644 (file)
index 0000000..1bcdcb8
--- /dev/null
@@ -0,0 +1,161 @@
+use crate::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_ast as ast;
+use rustc_errors::{Applicability, SuggestionStyle};
+use rustc_span::{BytePos, Span, Symbol};
+
+declare_lint! {
+    /// The `text_direction_codepoint_in_literal` lint detects Unicode codepoints that change the
+    /// visual representation of text on screen in a way that does not correspond to their on
+    /// memory representation.
+    ///
+    /// ### Explanation
+    ///
+    /// The unicode characters `\u{202A}`, `\u{202B}`, `\u{202D}`, `\u{202E}`, `\u{2066}`,
+    /// `\u{2067}`, `\u{2068}`, `\u{202C}` and `\u{2069}` make the flow of text on screen change
+    /// its direction on software that supports these codepoints. This makes the text "abc" display
+    /// as "cba" on screen. By leveraging software that supports these, people can write specially
+    /// crafted literals that make the surrounding code seem like it's performing one action, when
+    /// in reality it is performing another. Because of this, we proactively lint against their
+    /// presence to avoid surprises.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(text_direction_codepoint_in_literal)]
+    /// fn main() {
+    ///     println!("{:?}", '‮');
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    pub TEXT_DIRECTION_CODEPOINT_IN_LITERAL,
+    Deny,
+    "detect special Unicode codepoints that affect the visual representation of text on screen, \
+     changing the direction in which text flows",
+}
+
+declare_lint_pass!(HiddenUnicodeCodepoints => [TEXT_DIRECTION_CODEPOINT_IN_LITERAL]);
+
+crate const UNICODE_TEXT_FLOW_CHARS: &[char] = &[
+    '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}',
+    '\u{2069}',
+];
+
+impl HiddenUnicodeCodepoints {
+    fn lint_text_direction_codepoint(
+        &self,
+        cx: &EarlyContext<'_>,
+        text: Symbol,
+        span: Span,
+        padding: u32,
+        point_at_inner_spans: bool,
+        label: &str,
+    ) {
+        // Obtain the `Span`s for each of the forbidden chars.
+        let spans: Vec<_> = text
+            .as_str()
+            .char_indices()
+            .filter_map(|(i, c)| {
+                UNICODE_TEXT_FLOW_CHARS.contains(&c).then(|| {
+                    let lo = span.lo() + BytePos(i as u32 + padding);
+                    (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
+                })
+            })
+            .collect();
+
+        cx.struct_span_lint(TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, |lint| {
+            let mut err = lint.build(&format!(
+                "unicode codepoint changing visible direction of text present in {}",
+                label
+            ));
+            let (an, s) = match spans.len() {
+                1 => ("an ", ""),
+                _ => ("", "s"),
+            };
+            err.span_label(
+                span,
+                &format!(
+                    "this {} contains {}invisible unicode text flow control codepoint{}",
+                    label, an, s,
+                ),
+            );
+            if point_at_inner_spans {
+                for (c, span) in &spans {
+                    err.span_label(*span, format!("{:?}", c));
+                }
+            }
+            err.note(
+                "these kind of unicode codepoints change the way text flows on applications that \
+                 support them, but can cause confusion because they change the order of \
+                 characters on the screen",
+            );
+            if point_at_inner_spans && !spans.is_empty() {
+                err.multipart_suggestion_with_style(
+                    "if their presence wasn't intentional, you can remove them",
+                    spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
+                    Applicability::MachineApplicable,
+                    SuggestionStyle::HideCodeAlways,
+                );
+                err.multipart_suggestion(
+                    "if you want to keep them but make them visible in your source code, you can \
+                    escape them",
+                    spans
+                        .into_iter()
+                        .map(|(c, span)| {
+                            let c = format!("{:?}", c);
+                            (span, c[1..c.len() - 1].to_string())
+                        })
+                        .collect(),
+                    Applicability::MachineApplicable,
+                );
+            } else {
+                // FIXME: in other suggestions we've reversed the inner spans of doc comments. We
+                // should do the same here to provide the same good suggestions as we do for
+                // literals above.
+                err.note("if their presence wasn't intentional, you can remove them");
+                err.note(&format!(
+                    "if you want to keep them but make them visible in your source code, you can \
+                     escape them: {}",
+                    spans
+                        .into_iter()
+                        .map(|(c, _)| { format!("{:?}", c) })
+                        .collect::<Vec<String>>()
+                        .join(", "),
+                ));
+            }
+            err.emit();
+        });
+    }
+}
+impl EarlyLintPass for HiddenUnicodeCodepoints {
+    fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
+        if let ast::AttrKind::DocComment(_, comment) = attr.kind {
+            if comment.as_str().contains(UNICODE_TEXT_FLOW_CHARS) {
+                self.lint_text_direction_codepoint(cx, comment, attr.span, 0, false, "doc comment");
+            }
+        }
+    }
+
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
+        // byte strings are already handled well enough by `EscapeError::NonAsciiCharInByteString`
+        let (text, span, padding) = match &expr.kind {
+            ast::ExprKind::Lit(ast::Lit { token, kind, span }) => {
+                let text = token.symbol;
+                if !text.as_str().contains(UNICODE_TEXT_FLOW_CHARS) {
+                    return;
+                }
+                let padding = match kind {
+                    // account for `"` or `'`
+                    ast::LitKind::Str(_, ast::StrStyle::Cooked) | ast::LitKind::Char(_) => 1,
+                    // account for `r###"`
+                    ast::LitKind::Str(_, ast::StrStyle::Raw(val)) => *val as u32 + 2,
+                    _ => return,
+                };
+                (text, span, padding)
+            }
+            _ => return,
+        };
+        self.lint_text_direction_codepoint(cx, text, *span, padding, true, "literal");
+    }
+}
index 6f684a0fe5128658eaaa61dd955d505b5d80b24f..f6514ddca9f57c26bf54647f7e1485520c5c237c 100644 (file)
@@ -48,6 +48,7 @@
 mod context;
 mod early;
 mod enum_intrinsics_non_enums;
+pub mod hidden_unicode_codepoints;
 mod internal;
 mod late;
 mod levels;
@@ -78,6 +79,7 @@
 use array_into_iter::ArrayIntoIter;
 use builtin::*;
 use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
+use hidden_unicode_codepoints::*;
 use internal::*;
 use methods::*;
 use non_ascii_idents::*;
@@ -129,6 +131,7 @@ macro_rules! early_lint_passes {
                 DeprecatedAttr: DeprecatedAttr::new(),
                 WhileTrue: WhileTrue,
                 NonAsciiIdents: NonAsciiIdents,
+                HiddenUnicodeCodepoints: HiddenUnicodeCodepoints,
                 IncompleteFeatures: IncompleteFeatures,
                 RedundantSemicolons: RedundantSemicolons,
                 UnusedDocComment: UnusedDocComment,
@@ -300,7 +303,6 @@ macro_rules! register_passes {
         UNUSED_LABELS,
         UNUSED_PARENS,
         UNUSED_BRACES,
-        MUST_NOT_SUSPEND,
         REDUNDANT_SEMICOLONS
     );
 
index 48b955e41ac69506c05e5e46b071c979293dd6d3..da1edcf6fe3b47a590f2c81daea00f1ce1bf1571 100644 (file)
@@ -670,7 +670,7 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
     ///
     /// ### Explanation
     ///
-    /// The parenthesis are not needed, and should be removed. This is the
+    /// The parentheses are not needed, and should be removed. This is the
     /// preferred style for writing these expressions.
     pub(super) UNUSED_PARENS,
     Warn,
index a93d18950dba9256364c077fcd85d32afe2504b1..c1a53c34b7a244d27cfbcdb8bc8289108b5debf4 100644 (file)
     ///
     /// ```rust
     /// #![feature(must_not_suspend)]
+    /// #![warn(must_not_suspend)]
     ///
     /// #[must_not_suspend]
     /// struct SyncThing {}
     /// `MutexGuard`'s)
     ///
     pub MUST_NOT_SUSPEND,
-    Warn,
+    Allow,
     "use of a `#[must_not_suspend]` value across a yield point",
+    @feature_gate = rustc_span::symbol::sym::must_not_suspend;
 }
 
 declare_lint! {
     /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504
     /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
-    Warn,
+    Deny,
     "detects proc macro derives using inaccessible names from parent modules",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>",
         BREAK_WITH_LABEL_AND_LOOP,
         UNUSED_ATTRIBUTES,
         NON_EXHAUSTIVE_OMITTED_PATTERNS,
+        TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
         DEREF_INTO_DYN_SUPERTRAIT,
     ]
 }
     /// [issue #83125]: https://github.com/rust-lang/rust/issues/83125
     /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub PROC_MACRO_BACK_COMPAT,
-    Warn,
+    Deny,
     "detects usage of old versions of certain proc-macro crates",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #83125 <https://github.com/rust-lang/rust/issues/83125>",
     @feature_gate = sym::non_exhaustive_omitted_patterns_lint;
 }
 
+declare_lint! {
+    /// The `text_direction_codepoint_in_comment` lint detects Unicode codepoints in comments that
+    /// change the visual representation of text on screen in a way that does not correspond to
+    /// their on memory representation.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(text_direction_codepoint_in_comment)]
+    /// fn main() {
+    ///     println!("{:?}"); // '‮');
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unicode allows changing the visual flow of text on screen in order to support scripts that
+    /// are written right-to-left, but a specially crafted comment can make code that will be
+    /// compiled appear to be part of a comment, depending on the software used to read the code.
+    /// To avoid potential problems or confusion, such as in CVE-2021-42574, by default we deny
+    /// their use.
+    pub TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
+    Deny,
+    "invisible directionality-changing codepoints in comment"
+}
+
 declare_lint! {
     /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
     /// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
index f89d531b5ef5ceb8e403004c874d0c469d681cb8..feac2a7cfa48a77a8b0c88c296f5f584023478ab 100644 (file)
@@ -306,6 +306,7 @@ pub enum BuiltinLintDiagnostics {
     TrailingMacro(bool, Ident),
     BreakWithLabelAndLoop(Span),
     NamedAsmLabel(String),
+    UnicodeTextFlow(Span, String),
 }
 
 /// Lints that are buffered up early on in the `Session` before the
index 36a6d2cc33a99936b53df8c3566798683c9c71fb..943ce589c4f36ea41a19888cbe61af07159d0c40 100644 (file)
@@ -288,7 +288,7 @@ fn main() {
             let path = PathBuf::from(s);
             println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
             if target.contains("windows") {
-                println!("cargo:rustc-link-lib=static-nobundle={}", stdcppname);
+                println!("cargo:rustc-link-lib=static:-bundle={}", stdcppname);
             } else {
                 println!("cargo:rustc-link-lib=static={}", stdcppname);
             }
@@ -302,6 +302,6 @@ fn main() {
     // Libstdc++ depends on pthread which Rust doesn't link on MinGW
     // since nothing else requires it.
     if target.contains("windows-gnu") {
-        println!("cargo:rustc-link-lib=static-nobundle=pthread");
+        println!("cargo:rustc-link-lib=static:-bundle=pthread");
     }
 }
index 35cca04b20f758c737c11ecb1024703b365f7f27..8cd2bd12450e3d55a1c548cc4475d1f598754225 100644 (file)
@@ -98,10 +98,7 @@ extern "C" void LLVMRustCoverageWriteMapSectionNameToString(LLVMModuleRef M,
 
 extern "C" void LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M,
                                                              RustStringRef Str) {
-#if LLVM_VERSION_GE(11, 0)
   WriteSectionNameToString(M, IPSK_covfun, Str);
-// else do nothing; the `Version` check will abort codegen on the Rust side
-#endif
 }
 
 extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) {
@@ -111,9 +108,5 @@ extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) {
 }
 
 extern "C" uint32_t LLVMRustCoverageMappingVersion() {
-#if LLVM_VERSION_GE(11, 0)
   return coverage::CovMapVersion::Version4;
-#else
-  return coverage::CovMapVersion::Version3;
-#endif
 }
index 0b1b68d83b7b9254a8a9045d0ada18bd99523f27..ebe495872c4a6653a4f898ac72c7adcf0ad81008 100644 (file)
@@ -18,7 +18,6 @@
 #include "llvm/Support/Host.h"
 #include "llvm/Support/Memory.h"
 #include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Support/Timer.h"
 #include "llvm/Support/raw_ostream.h"
index 87f423fb2d56eb0b51771bc519d0a6386716b821..32b866e81b131eca15e114368170038fa9d8e0e1 100644 (file)
 #include "llvm/Support/CBindingWrapping.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Host.h"
+#if LLVM_VERSION_LT(14, 0)
+#include "llvm/Support/TargetRegistry.h"
+#else
+#include "llvm/MC/TargetRegistry.h"
+#endif
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
 #include "llvm/Transforms/IPO/AlwaysInliner.h"
@@ -49,10 +54,6 @@ typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
 
 DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
 DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
-#if LLVM_VERSION_LT(11, 0)
-DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder,
-                                   LLVMPassManagerBuilderRef)
-#endif
 
 extern "C" void LLVMInitializePasses() {
   PassRegistry &Registry = *PassRegistry::getPassRegistry();
@@ -461,6 +462,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat,
     bool FunctionSections,
     bool DataSections,
+    bool UniqueSectionNames,
     bool TrapUnreachable,
     bool Singlethread,
     bool AsmComments,
@@ -490,6 +492,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
   }
   Options.DataSections = DataSections;
   Options.FunctionSections = FunctionSections;
+  Options.UniqueSectionNames = UniqueSectionNames;
   Options.MCOptions.AsmVerbose = AsmComments;
   Options.MCOptions.PreserveAsmComments = AsmComments;
   Options.MCOptions.ABIName = ABIStr;
@@ -680,7 +683,6 @@ void LLVMSelfProfileInitializeCallbacks(
     PassInstrumentationCallbacks& PIC, void* LlvmSelfProfiler,
     LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
     LLVMRustSelfProfileAfterPassCallback AfterPassCallback) {
-#if LLVM_VERSION_GE(12, 0)
   PIC.registerBeforeNonSkippedPassCallback([LlvmSelfProfiler, BeforePassCallback](
                                            StringRef Pass, llvm::Any Ir) {
     std::string PassName = Pass.str();
@@ -698,25 +700,6 @@ void LLVMSelfProfileInitializeCallbacks(
       [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, const PreservedAnalyses &Preserved) {
         AfterPassCallback(LlvmSelfProfiler);
       });
-#else
-  PIC.registerBeforePassCallback([LlvmSelfProfiler, BeforePassCallback](
-                                     StringRef Pass, llvm::Any Ir) {
-    std::string PassName = Pass.str();
-    std::string IrName = LLVMRustwrappedIrGetName(Ir);
-    BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str());
-    return true;
-  });
-
-  PIC.registerAfterPassCallback(
-      [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any Ir) {
-        AfterPassCallback(LlvmSelfProfiler);
-      });
-
-  PIC.registerAfterPassInvalidatedCallback(
-      [LlvmSelfProfiler, AfterPassCallback](StringRef Pass) {
-        AfterPassCallback(LlvmSelfProfiler);
-      });
-#endif
 
   PIC.registerBeforeAnalysisCallback([LlvmSelfProfiler, BeforePassCallback](
                                          StringRef Pass, llvm::Any Ir) {
@@ -777,22 +760,13 @@ LLVMRustOptimizeWithNewPassManager(
   PTO.LoopInterleaving = UnrollLoops;
   PTO.LoopVectorization = LoopVectorize;
   PTO.SLPVectorization = SLPVectorize;
-#if LLVM_VERSION_GE(12, 0)
   PTO.MergeFunctions = MergeFunctions;
-#else
-  // MergeFunctions is not supported by NewPM in older LLVM versions.
-  (void) MergeFunctions;
-#endif
 
   // FIXME: We may want to expose this as an option.
   bool DebugPassManager = false;
 
   PassInstrumentationCallbacks PIC;
-#if LLVM_VERSION_GE(12, 0)
   StandardInstrumentations SI(DebugPassManager);
-#else
-  StandardInstrumentations SI;
-#endif
   SI.registerCallbacks(PIC);
 
   if (LlvmSelfProfiler){
@@ -816,18 +790,14 @@ LLVMRustOptimizeWithNewPassManager(
                         PGOOptions::NoCSAction, DebugInfoForProfiling);
   }
 
-#if LLVM_VERSION_GE(12, 0) && !LLVM_VERSION_GE(13,0)
-  PassBuilder PB(DebugPassManager, TM, PTO, PGOOpt, &PIC);
-#else
-  PassBuilder PB(TM, PTO, PGOOpt, &PIC);
-#endif
-
 #if LLVM_VERSION_GE(13, 0)
+  PassBuilder PB(TM, PTO, PGOOpt, &PIC);
   LoopAnalysisManager LAM;
   FunctionAnalysisManager FAM;
   CGSCCAnalysisManager CGAM;
   ModuleAnalysisManager MAM;
 #else
+  PassBuilder PB(DebugPassManager, TM, PTO, PGOOpt, &PIC);
   LoopAnalysisManager LAM(DebugPassManager);
   FunctionAnalysisManager FAM(DebugPassManager);
   CGSCCAnalysisManager CGAM(DebugPassManager);
@@ -852,13 +822,8 @@ LLVMRustOptimizeWithNewPassManager(
   // PassBuilder does not create a pipeline.
   std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
       PipelineStartEPCallbacks;
-#if LLVM_VERSION_GE(11, 0)
   std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
       OptimizerLastEPCallbacks;
-#else
-  std::vector<std::function<void(FunctionPassManager &, OptimizationLevel)>>
-      OptimizerLastEPCallbacks;
-#endif
 
   if (VerifyIR) {
     PipelineStartEPCallbacks.push_back(
@@ -891,7 +856,6 @@ LLVMRustOptimizeWithNewPassManager(
           SanitizerOptions->SanitizeMemoryTrackOrigins,
           SanitizerOptions->SanitizeMemoryRecover,
           /*CompileKernel=*/false);
-#if LLVM_VERSION_GE(11, 0)
       OptimizerLastEPCallbacks.push_back(
         [Options](ModulePassManager &MPM, OptimizationLevel Level) {
 #if LLVM_VERSION_GE(14, 0)
@@ -902,22 +866,9 @@ LLVMRustOptimizeWithNewPassManager(
           MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options)));
         }
       );
-#else
-      PipelineStartEPCallbacks.push_back(
-        [Options](ModulePassManager &MPM, OptimizationLevel Level) {
-          MPM.addPass(MemorySanitizerPass(Options));
-        }
-      );
-      OptimizerLastEPCallbacks.push_back(
-        [Options](FunctionPassManager &FPM, OptimizationLevel Level) {
-          FPM.addPass(MemorySanitizerPass(Options));
-        }
-      );
-#endif
     }
 
     if (SanitizerOptions->SanitizeThread) {
-#if LLVM_VERSION_GE(11, 0)
       OptimizerLastEPCallbacks.push_back(
         [](ModulePassManager &MPM, OptimizationLevel Level) {
 #if LLVM_VERSION_GE(14, 0)
@@ -928,22 +879,9 @@ LLVMRustOptimizeWithNewPassManager(
           MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
         }
       );
-#else
-      PipelineStartEPCallbacks.push_back(
-        [](ModulePassManager &MPM, OptimizationLevel Level) {
-          MPM.addPass(ThreadSanitizerPass());
-        }
-      );
-      OptimizerLastEPCallbacks.push_back(
-        [](FunctionPassManager &FPM, OptimizationLevel Level) {
-          FPM.addPass(ThreadSanitizerPass());
-        }
-      );
-#endif
     }
 
     if (SanitizerOptions->SanitizeAddress) {
-#if LLVM_VERSION_GE(11, 0)
       OptimizerLastEPCallbacks.push_back(
         [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
           MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
@@ -962,29 +900,8 @@ LLVMRustOptimizeWithNewPassManager(
 #endif
         }
       );
-#else
-      PipelineStartEPCallbacks.push_back(
-        [&](ModulePassManager &MPM, OptimizationLevel Level) {
-          MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
-        }
-      );
-      OptimizerLastEPCallbacks.push_back(
-        [SanitizerOptions](FunctionPassManager &FPM, OptimizationLevel Level) {
-          FPM.addPass(AddressSanitizerPass(
-              /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
-              /*UseAfterScope=*/true));
-        }
-      );
-      PipelineStartEPCallbacks.push_back(
-        [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
-          MPM.addPass(ModuleAddressSanitizerPass(
-              /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
-        }
-      );
-#endif
     }
     if (SanitizerOptions->SanitizeHWAddress) {
-#if LLVM_VERSION_GE(11, 0)
       OptimizerLastEPCallbacks.push_back(
         [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
 #if LLVM_VERSION_GE(14, 0)
@@ -998,14 +915,6 @@ LLVMRustOptimizeWithNewPassManager(
 #endif
         }
       );
-#else
-      PipelineStartEPCallbacks.push_back(
-        [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
-          MPM.addPass(HWAddressSanitizerPass(
-              /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
-        }
-      );
-#endif
     }
   }
 
@@ -1020,7 +929,6 @@ LLVMRustOptimizeWithNewPassManager(
     // At the same time, the LTO pipelines do support O0 and using them is required.
     bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO;
     if (OptLevel == OptimizationLevel::O0 && !IsLTO) {
-#if LLVM_VERSION_GE(12, 0)
       for (const auto &C : PipelineStartEPCallbacks)
         PB.registerPipelineStartEPCallback(C);
       for (const auto &C : OptimizerLastEPCallbacks)
@@ -1028,40 +936,9 @@ LLVMRustOptimizeWithNewPassManager(
 
       // Pass false as we manually schedule ThinLTOBufferPasses below.
       MPM = PB.buildO0DefaultPipeline(OptLevel, /* PreLinkLTO */ false);
-#else
-      for (const auto &C : PipelineStartEPCallbacks)
-        C(MPM, OptLevel);
-
-# if LLVM_VERSION_GE(11, 0)
-      for (const auto &C : OptimizerLastEPCallbacks)
-        C(MPM, OptLevel);
-# else
-      if (!OptimizerLastEPCallbacks.empty()) {
-        FunctionPassManager FPM(DebugPassManager);
-        for (const auto &C : OptimizerLastEPCallbacks)
-          C(FPM, OptLevel);
-        MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
-      }
-# endif
-
-      MPM.addPass(AlwaysInlinerPass(EmitLifetimeMarkers));
-
-      if (PGOOpt) {
-        PB.addPGOInstrPassesForO0(
-            MPM, DebugPassManager, PGOOpt->Action == PGOOptions::IRInstr,
-            /*IsCS=*/false, PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile);
-      }
-#endif
     } else {
-#if LLVM_VERSION_GE(12, 0)
       for (const auto &C : PipelineStartEPCallbacks)
         PB.registerPipelineStartEPCallback(C);
-#else
-      for (const auto &C : PipelineStartEPCallbacks)
-        PB.registerPipelineStartEPCallback([C, OptLevel](ModulePassManager &MPM) {
-          C(MPM, OptLevel);
-        });
-#endif
       if (OptStage != LLVMRustOptStage::PreLinkThinLTO) {
         for (const auto &C : OptimizerLastEPCallbacks)
           PB.registerOptimizerLastEPCallback(C);
@@ -1072,7 +949,6 @@ LLVMRustOptimizeWithNewPassManager(
         MPM = PB.buildPerModuleDefaultPipeline(OptLevel, DebugPassManager);
         break;
       case LLVMRustOptStage::PreLinkThinLTO:
-#if LLVM_VERSION_GE(12, 0)
         MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel);
         // The ThinLTOPreLink pipeline already includes ThinLTOBuffer passes. However, callback
         // passes may still run afterwards. This means we need to run the buffer passes again.
@@ -1080,44 +956,20 @@ LLVMRustOptimizeWithNewPassManager(
         // before the RequiredLTOPreLinkPasses, in which case we can remove these hacks.
         if (OptimizerLastEPCallbacks.empty())
           NeedThinLTOBufferPasses = false;
-#else
-        MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
-#endif
-#if LLVM_VERSION_GE(11, 0)
         for (const auto &C : OptimizerLastEPCallbacks)
           C(MPM, OptLevel);
-#else
-        if (!OptimizerLastEPCallbacks.empty()) {
-          FunctionPassManager FPM(DebugPassManager);
-          for (const auto &C : OptimizerLastEPCallbacks)
-            C(FPM, OptLevel);
-          MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
-        }
-#endif
         break;
       case LLVMRustOptStage::PreLinkFatLTO:
-#if LLVM_VERSION_GE(12, 0)
         MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel);
         NeedThinLTOBufferPasses = false;
-#else
-        MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
-#endif
         break;
       case LLVMRustOptStage::ThinLTO:
         // FIXME: Does it make sense to pass the ModuleSummaryIndex?
         // It only seems to be needed for C++ specific optimizations.
-#if LLVM_VERSION_GE(12, 0)
         MPM = PB.buildThinLTODefaultPipeline(OptLevel, nullptr);
-#else
-        MPM = PB.buildThinLTODefaultPipeline(OptLevel, DebugPassManager, nullptr);
-#endif
         break;
       case LLVMRustOptStage::FatLTO:
-#if LLVM_VERSION_GE(12, 0)
         MPM = PB.buildLTODefaultPipeline(OptLevel, nullptr);
-#else
-        MPM = PB.buildLTODefaultPipeline(OptLevel, DebugPassManager, nullptr);
-#endif
         break;
       }
     }
@@ -1547,7 +1399,6 @@ LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) {
 // `ProcessThinLTOModule` function. Here they're split up into separate steps
 // so rustc can save off the intermediate bytecode between each step.
 
-#if LLVM_VERSION_GE(11, 0)
 static bool
 clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) {
   // When linking an ELF shared object, dso_local should be dropped. We
@@ -1558,7 +1409,6 @@ clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) {
       Mod.getPIELevel() == PIELevel::Default;
   return ClearDSOLocalOnDeclarations;
 }
-#endif
 
 extern "C" bool
 LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
@@ -1566,12 +1416,8 @@ LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
   Module &Mod = *unwrap(M);
   TargetMachine &Target = *unwrap(TM);
 
-#if LLVM_VERSION_GE(11, 0)
   bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
   bool error = renameModuleForThinLTO(Mod, Data->Index, ClearDSOLocal);
-#else
-  bool error = renameModuleForThinLTO(Mod, Data->Index);
-#endif
 
   if (error) {
     LLVMRustSetLastError("renameModuleForThinLTO failed");
@@ -1640,12 +1486,8 @@ LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
 
     return MOrErr;
   };
-#if LLVM_VERSION_GE(11, 0)
   bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
   FunctionImporter Importer(Data->Index, Loader, ClearDSOLocal);
-#else
-  FunctionImporter Importer(Data->Index, Loader);
-#endif
   Expected<bool> Result = Importer.importFunctions(Mod, ImportList);
   if (!Result) {
     LLVMRustSetLastError(toString(Result.takeError()).c_str());
index b7b0524e2a38867091a878f27b093f220d7142ce..e77d29bed7122fd466e77cb5c226df615fe409b8 100644 (file)
@@ -263,11 +263,7 @@ extern "C" void LLVMRustAddByValCallSiteAttr(LLVMValueRef Instr, unsigned Index,
 extern "C" void LLVMRustAddStructRetCallSiteAttr(LLVMValueRef Instr, unsigned Index,
                                                  LLVMTypeRef Ty) {
   CallBase *Call = unwrap<CallBase>(Instr);
-#if LLVM_VERSION_GE(12, 0)
   Attribute Attr = Attribute::getWithStructRetType(Call->getContext(), unwrap(Ty));
-#else
-  Attribute Attr = Attribute::get(Call->getContext(), Attribute::StructRet);
-#endif
   AddAttribute(Call, Index, Attr);
 }
 
@@ -311,11 +307,7 @@ extern "C" void LLVMRustAddByValAttr(LLVMValueRef Fn, unsigned Index,
 extern "C" void LLVMRustAddStructRetAttr(LLVMValueRef Fn, unsigned Index,
                                          LLVMTypeRef Ty) {
   Function *F = unwrap<Function>(Fn);
-#if LLVM_VERSION_GE(12, 0)
   Attribute Attr = Attribute::getWithStructRetType(F->getContext(), unwrap(Ty));
-#else
-  Attribute Attr = Attribute::get(F->getContext(), Attribute::StructRet);
-#endif
   AddAttribute(F, Index, Attr);
 }
 
@@ -681,10 +673,8 @@ static Optional<DIFile::ChecksumKind> fromRust(LLVMRustChecksumKind Kind) {
     return DIFile::ChecksumKind::CSK_MD5;
   case LLVMRustChecksumKind::SHA1:
     return DIFile::ChecksumKind::CSK_SHA1;
-#if (LLVM_VERSION_MAJOR >= 11)
   case LLVMRustChecksumKind::SHA256:
     return DIFile::ChecksumKind::CSK_SHA256;
-#endif
   default:
     report_fatal_error("bad ChecksumKind.");
   }
@@ -999,14 +989,9 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType(
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter(
     LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
     const char *Name, size_t NameLen, LLVMMetadataRef Ty) {
-#if LLVM_VERSION_GE(11, 0)
   bool IsDefault = false; // FIXME: should we ever set this true?
   return wrap(Builder->createTemplateTypeParameter(
       unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty), IsDefault));
-#else
-  return wrap(Builder->createTemplateTypeParameter(
-      unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty)));
-#endif
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateNameSpace(
@@ -1031,17 +1016,11 @@ extern "C" LLVMMetadataRef
 LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column,
                                      LLVMMetadataRef ScopeRef,
                                      LLVMMetadataRef InlinedAt) {
-#if LLVM_VERSION_GE(12, 0)
   MDNode *Scope = unwrapDIPtr<MDNode>(ScopeRef);
   DILocation *Loc = DILocation::get(
       Scope->getContext(), Line, Column, Scope,
       unwrapDIPtr<MDNode>(InlinedAt));
   return wrap(Loc);
-#else
-  DebugLoc debug_loc = DebugLoc::get(Line, Column, unwrapDIPtr<MDNode>(ScopeRef),
-                                     unwrapDIPtr<MDNode>(InlinedAt));
-  return wrap(debug_loc.getAsMDNode());
-#endif
 }
 
 extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() {
@@ -1246,27 +1225,18 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
     return LLVMArrayTypeKind;
   case Type::PointerTyID:
     return LLVMPointerTypeKind;
-#if LLVM_VERSION_GE(11, 0)
   case Type::FixedVectorTyID:
     return LLVMVectorTypeKind;
-#else
-  case Type::VectorTyID:
-    return LLVMVectorTypeKind;
-#endif
   case Type::X86_MMXTyID:
     return LLVMX86_MMXTypeKind;
   case Type::TokenTyID:
     return LLVMTokenTypeKind;
-#if LLVM_VERSION_GE(11, 0)
   case Type::ScalableVectorTyID:
     return LLVMScalableVectorTypeKind;
   case Type::BFloatTyID:
     return LLVMBFloatTypeKind;
-#endif
-#if LLVM_VERSION_GE(12, 0)
   case Type::X86_AMXTyID:
     return LLVMX86_AMXTypeKind;
-#endif
   }
   report_fatal_error("Unhandled TypeID.");
 }
@@ -1724,23 +1694,15 @@ LLVMRustBuildVectorReduceMax(LLVMBuilderRef B, LLVMValueRef Src, bool IsSigned)
 }
 extern "C" LLVMValueRef
 LLVMRustBuildVectorReduceFMin(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) {
-#if LLVM_VERSION_GE(12, 0)
   Instruction *I = unwrap(B)->CreateFPMinReduce(unwrap(Src));
   I->setHasNoNaNs(NoNaN);
   return wrap(I);
-#else
-  return wrap(unwrap(B)->CreateFPMinReduce(unwrap(Src), NoNaN));
-#endif
 }
 extern "C" LLVMValueRef
 LLVMRustBuildVectorReduceFMax(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) {
-#if LLVM_VERSION_GE(12, 0)
   Instruction *I = unwrap(B)->CreateFPMaxReduce(unwrap(Src));
   I->setHasNoNaNs(NoNaN);
   return wrap(I);
-#else
-  return wrap(unwrap(B)->CreateFPMaxReduce(unwrap(Src), NoNaN));
-#endif
 }
 
 extern "C" LLVMValueRef
index 6493bd91ca27a836c54cb21bd80914b654474e6f..8476c2bfcc431ca7c8fe0a2e26323b4b6a9e918b 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(nll)]
-#![feature(static_nobundle)]
+#![feature(native_link_modifiers)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 
 // NOTE: This crate only exists to allow linking on mingw targets.
index 63bdcea87f8170a97df6b45df4f8bc8d8032e910..dba885a27fe229f3c73176568cb4891135acf097 100644 (file)
@@ -24,9 +24,11 @@ fn parse_attributes(field: &syn::Field) -> Attributes {
                         }
                         if meta.path().is_ident("project") {
                             if let Meta::List(list) = meta {
-                                if let Some(NestedMeta::Meta(meta)) = list.nested.iter().next() {
-                                    attrs.project = meta.path().get_ident().cloned();
-                                    any_attr = true;
+                                if let Some(nested) = list.nested.iter().next() {
+                                    if let NestedMeta::Meta(meta) = nested {
+                                        attrs.project = meta.path().get_ident().cloned();
+                                        any_attr = true;
+                                    }
                                 }
                             }
                         }
index 005017185c148458dd62271b689b4083209f35ba..6dbba274360231a05c18e716b4a3d128bd1a3e75 100644 (file)
@@ -36,7 +36,7 @@ enum QueryModifier {
     Storage(Type),
 
     /// Cache the query to disk if the `Expr` returns true.
-    Cache(Option<(IdentOrWild, IdentOrWild)>, Block),
+    Cache(Option<IdentOrWild>, Block),
 
     /// Custom code to load the query from disk.
     LoadCached(Ident, Ident, Block),
@@ -55,6 +55,9 @@ enum QueryModifier {
 
     /// Always evaluate the query, ignoring its dependencies
     EvalAlways(Ident),
+
+    /// Use a separate query provider for local and extern crates
+    SeparateProvideExtern(Ident),
 }
 
 impl Parse for QueryModifier {
@@ -87,9 +90,7 @@ fn parse(input: ParseStream<'_>) -> Result<Self> {
                 let args;
                 parenthesized!(args in input);
                 let tcx = args.parse()?;
-                args.parse::<Token![,]>()?;
-                let value = args.parse()?;
-                Some((tcx, value))
+                Some(tcx)
             } else {
                 None
             };
@@ -120,6 +121,8 @@ fn parse(input: ParseStream<'_>) -> Result<Self> {
             Ok(QueryModifier::Anon(modifier))
         } else if modifier == "eval_always" {
             Ok(QueryModifier::EvalAlways(modifier))
+        } else if modifier == "separate_provide_extern" {
+            Ok(QueryModifier::SeparateProvideExtern(modifier))
         } else {
             Err(Error::new(modifier.span(), "unknown query modifier"))
         }
@@ -197,7 +200,7 @@ struct QueryModifiers {
     storage: Option<Type>,
 
     /// Cache the query to disk if the `Block` returns true.
-    cache: Option<(Option<(IdentOrWild, IdentOrWild)>, Block)>,
+    cache: Option<(Option<IdentOrWild>, Block)>,
 
     /// Custom code to load the query from disk.
     load_cached: Option<(Ident, Ident, Block)>,
@@ -216,6 +219,9 @@ struct QueryModifiers {
 
     // Always evaluate the query, ignoring its dependencies
     eval_always: Option<Ident>,
+
+    /// Use a separate query provider for local and extern crates
+    separate_provide_extern: Option<Ident>,
 }
 
 /// Process query modifiers into a struct, erroring on duplicates
@@ -229,6 +235,7 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
     let mut no_hash = None;
     let mut anon = None;
     let mut eval_always = None;
+    let mut separate_provide_extern = None;
     for modifier in query.modifiers.0.drain(..) {
         match modifier {
             QueryModifier::LoadCached(tcx, id, block) => {
@@ -319,6 +326,15 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
                 }
                 eval_always = Some(ident);
             }
+            QueryModifier::SeparateProvideExtern(ident) => {
+                if separate_provide_extern.is_some() {
+                    panic!(
+                        "duplicate modifier `separate_provide_extern` for query `{}`",
+                        query.name
+                    );
+                }
+                separate_provide_extern = Some(ident);
+            }
         }
     }
     let desc = desc.unwrap_or_else(|| {
@@ -334,6 +350,7 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
         no_hash,
         anon,
         eval_always,
+        separate_provide_extern,
     }
 }
 
@@ -351,51 +368,30 @@ fn add_query_description_impl(
         let try_load_from_disk = if let Some((tcx, id, block)) = modifiers.load_cached.as_ref() {
             // Use custom code to load the query from disk
             quote! {
-                #[inline]
-                fn try_load_from_disk(
-                    #tcx: QueryCtxt<'tcx>,
-                    #id: SerializedDepNodeIndex
-                ) -> Option<Self::Value> {
-                    #block
-                }
+                const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>>
+                    = Some(|#tcx, #id| { #block });
             }
         } else {
             // Use the default code to load the query from disk
             quote! {
-                #[inline]
-                fn try_load_from_disk(
-                    tcx: QueryCtxt<'tcx>,
-                    id: SerializedDepNodeIndex
-                ) -> Option<Self::Value> {
-                    tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id)
-                }
+                const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>>
+                    = Some(|tcx, id| tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id));
             }
         };
 
         let tcx = args
             .as_ref()
             .map(|t| {
-                let t = &(t.0).0;
-                quote! { #t }
-            })
-            .unwrap_or_else(|| quote! { _ });
-        let value = args
-            .as_ref()
-            .map(|t| {
-                let t = &(t.1).0;
+                let t = &t.0;
                 quote! { #t }
             })
             .unwrap_or_else(|| quote! { _ });
         // expr is a `Block`, meaning that `{ #expr }` gets expanded
         // to `{ { stmts... } }`, which triggers the `unused_braces` lint.
         quote! {
-            #[inline]
             #[allow(unused_variables, unused_braces)]
-            fn cache_on_disk(
-                #tcx: QueryCtxt<'tcx>,
-                #key: &Self::Key,
-                #value: Option<&Self::Value>
-            ) -> bool {
+            #[inline]
+            fn cache_on_disk(#tcx: TyCtxt<'tcx>, #key: &Self::Key) -> bool {
                 #expr
             }
 
@@ -405,7 +401,14 @@ fn cache_on_disk(
         if modifiers.load_cached.is_some() {
             panic!("load_cached modifier on query `{}` without a cache modifier", name);
         }
-        quote! {}
+        quote! {
+            #[inline]
+            fn cache_on_disk(_: TyCtxt<'tcx>, _: &Self::Key) -> bool {
+                false
+            }
+
+            const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>> = None;
+        }
     };
 
     let (tcx, desc) = modifiers.desc;
@@ -413,17 +416,17 @@ fn cache_on_disk(
 
     let desc = quote! {
         #[allow(unused_variables)]
-        fn describe(tcx: QueryCtxt<'tcx>, key: Self::Key) -> String {
+        fn describe(tcx: QueryCtxt<$tcx>, key: Self::Key) -> String {
             let (#tcx, #key) = (*tcx, key);
             ::rustc_middle::ty::print::with_no_trimmed_paths(|| format!(#desc).into())
         }
     };
 
     impls.extend(quote! {
-        impl<'tcx> QueryDescription<QueryCtxt<'tcx>> for queries::#name<'tcx> {
+        (#name<$tcx:tt>) => {
             #desc
             #cache
-        }
+        };
     });
 }
 
@@ -478,6 +481,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
         if let Some(eval_always) = &modifiers.eval_always {
             attributes.push(quote! { (#eval_always) });
         };
+        // Pass on the separate_provide_extern modifier
+        if let Some(separate_provide_extern) = &modifiers.separate_provide_extern {
+            attributes.push(quote! { (#separate_provide_extern) });
+        }
 
         // This uses the span of the query definition for the commas,
         // which can be important if we later encounter any ambiguity
@@ -531,7 +538,7 @@ macro_rules! rustc_cached_queries {
         }
         #[macro_export]
         macro_rules! rustc_query_description {
-            () => { #query_description_stream }
+            #query_description_stream
         }
     })
 }
index c8959dc86ad2d87b3fd0c67a81389d211cf758de..80dcf99da6224b775936e1b1d746e89a640987c1 100644 (file)
@@ -349,14 +349,14 @@ fn generate_field_code(
     ) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> {
         let field_binding = &info.binding.binding;
 
-        let option_ty = option_inner_ty(info.ty);
+        let option_ty = option_inner_ty(&info.ty);
 
         let generated_code = self.generate_non_option_field_code(
             attr,
             FieldInfo {
                 vis: info.vis,
                 binding: info.binding,
-                ty: option_ty.unwrap_or(info.ty),
+                ty: option_ty.unwrap_or(&info.ty),
                 span: info.span,
             },
         )?;
@@ -388,7 +388,7 @@ fn generate_non_option_field_code(
                 let formatted_str = self.build_format(&s.value(), attr.span());
                 match name {
                     "message" => {
-                        if type_matches_path(info.ty, &["rustc_span", "Span"]) {
+                        if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
                             quote! {
                                 #diag.set_span(*#field_binding);
                                 #diag.set_primary_message(#formatted_str);
@@ -401,7 +401,7 @@ fn generate_non_option_field_code(
                         }
                     }
                     "label" => {
-                        if type_matches_path(info.ty, &["rustc_span", "Span"]) {
+                        if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
                             quote! {
                                 #diag.span_label(*#field_binding, #formatted_str);
                             }
index f71fefd17992083d4bd026199d7c3ca4e10e07fb..dec77d996f3f24cf040bf2694cc009a34f2578a4 100644 (file)
@@ -8,7 +8,7 @@ doctest = false
 
 [dependencies]
 libc = "0.2"
-odht = { version = "0.3.0", features = ["nightly"] }
+odht = { version = "0.3.1", features = ["nightly"] }
 snap = "1"
 tracing = "0.1"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
index 644b849a9f899e17bb81ccfec572c1591cc64489..6cf0dd8b1addbee40c76b377e7c05bb52c39455e 100644 (file)
@@ -2,6 +2,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(drain_filter)]
 #![feature(in_band_lifetimes)]
+#![feature(let_else)]
 #![feature(nll)]
 #![feature(once_cell)]
 #![feature(proc_macro_internals)]
index c54ea61060271979b26867832579f6288c80a284..8db2291dfcfaac8c6144128f3e03abd47452e52e 100644 (file)
 use std::io::{Read, Result as IoResult, Write};
 use std::path::{Path, PathBuf};
 use std::{cmp, fmt, fs};
-use tracing::{debug, info, warn};
+use tracing::{debug, info};
 
 #[derive(Clone)]
 crate struct CrateLocator<'a> {
@@ -529,6 +529,15 @@ fn extract_one(
         let mut err_data: Option<Vec<PathBuf>> = None;
         for (lib, kind) in m {
             info!("{} reading metadata from: {}", flavor, lib.display());
+            if flavor == CrateFlavor::Rmeta && lib.metadata().map_or(false, |m| m.len() == 0) {
+                // Empty files will cause get_metadata_section to fail. Rmeta
+                // files can be empty, for example with binaries (which can
+                // often appear with `cargo check` when checking a library as
+                // a unittest). We don't want to emit a user-visible warning
+                // in this case as it is not a real problem.
+                debug!("skipping empty file");
+                continue;
+            }
             let (hash, metadata) =
                 match get_metadata_section(self.target, flavor, &lib, self.metadata_loader) {
                     Ok(blob) => {
@@ -540,7 +549,7 @@ fn extract_one(
                         }
                     }
                     Err(err) => {
-                        warn!("no metadata found: {}", err);
+                        info!("no metadata found: {}", err);
                         continue;
                     }
                 };
index 89bb5797a828f3770d78f02ad1ba0c96dc10e62e..5e90aec003e9b1a20e381b1069059a87b1125bc6 100644 (file)
@@ -472,9 +472,7 @@ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Span, String> {
         let len = BytePos::decode(decoder)?;
         let hi = lo + len;
 
-        let sess = if let Some(sess) = decoder.sess {
-            sess
-        } else {
+        let Some(sess) = decoder.sess else {
             bug!("Cannot decode Span without Session.")
         };
 
@@ -1200,8 +1198,8 @@ fn each_child_of_item(&self, id: DefIndex, mut callback: impl FnMut(Export), ses
             }
         }
 
-        if let EntryKind::Mod(data) = kind {
-            for exp in data.decode((self, sess)).reexports.decode((self, sess)) {
+        if let EntryKind::Mod(exports) = kind {
+            for exp in exports.decode((self, sess)) {
                 match exp.res {
                     Res::Def(DefKind::Macro(..), _) => {}
                     _ if macros_only => continue,
@@ -1221,10 +1219,11 @@ fn is_item_mir_available(&self, id: DefIndex) -> bool {
     }
 
     fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
-        if let EntryKind::Mod(m) = self.kind(id) {
-            m.decode((self, sess)).expansion
-        } else {
-            panic!("Expected module, found {:?}", self.local_def_id(id))
+        match self.kind(id) {
+            EntryKind::Mod(_) | EntryKind::Enum(_) | EntryKind::Trait(_) => {
+                self.get_expn_that_defined(id, sess)
+            }
+            _ => panic!("Expected module, found {:?}", self.local_def_id(id)),
         }
     }
 
index 4e7f85d2c372772dce0c10fd47dfd855edad6268..7ea004b16f23bc3546f4db41827ca4ef927a22a0 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_middle::hir::exports::Export;
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
 use rustc_middle::middle::stability::DeprecationEntry;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::{self, TyCtxt, Visibility};
 use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule};
 use rustc_session::utils::NativeLibKind;
@@ -26,7 +26,7 @@
 macro_rules! provide {
     (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident,
       $($name:ident => $compute:block)*) => {
-        pub fn provide_extern(providers: &mut Providers) {
+        pub fn provide_extern(providers: &mut ExternProviders) {
             $(fn $name<$lt>(
                 $tcx: TyCtxt<$lt>,
                 def_id_arg: ty::query::query_keys::$name<$lt>,
@@ -51,7 +51,7 @@ pub fn provide_extern(providers: &mut Providers) {
                 $compute
             })*
 
-            *providers = Providers {
+            *providers = ExternProviders {
                 $($name,)*
                 ..*providers
             };
@@ -83,6 +83,12 @@ fn into_args(self) -> (DefId, DefId) {
     }
 }
 
+impl IntoArgs for ty::InstanceDef<'tcx> {
+    fn into_args(self) -> (DefId, DefId) {
+        (self.def_id(), self.def_id())
+    }
+}
+
 provide! { <'tcx> tcx, def_id, other, cdata,
     type_of => { cdata.get_type(def_id.index, tcx) }
     generics_of => { cdata.get_generics(def_id.index, tcx.sess) }
index dacb1e4029c20d302a850a4d1df9d86d90a9b495..0dbef66ac37d77ff78eeb6fa2fb10a5986f1e1f3 100644 (file)
@@ -1086,11 +1086,11 @@ fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) {
             Lazy::empty()
         };
 
-        let data = ModData { reexports, expansion: tcx.expn_that_defined(local_def_id) };
-
-        record!(self.tables.kind[def_id] <- EntryKind::Mod(self.lazy(data)));
+        record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports));
         if self.is_proc_macro {
             record!(self.tables.children[def_id] <- &[]);
+            // Encode this here because we don't do it in encode_def_ids.
+            record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
         } else {
             record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| {
                 item_id.def_id.local_def_index
@@ -1319,7 +1319,9 @@ fn encode_mir(&mut self) {
             }
             record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
 
-            let unused = self.tcx.unused_generic_params(def_id);
+            let instance =
+                ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id()));
+            let unused = self.tcx.unused_generic_params(instance);
             if !unused.is_empty() {
                 record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
             }
index 42855e9d9d12f2fc25fda08857d48f3b8b0b908c..4e09d23169aca3c771b86ad12d68c6ec713c32b2 100644 (file)
@@ -346,7 +346,7 @@ enum EntryKind {
     Union(Lazy<VariantData>, ReprOptions),
     Fn(Lazy<FnData>),
     ForeignFn(Lazy<FnData>),
-    Mod(Lazy<ModData>),
+    Mod(Lazy<[Export]>),
     MacroDef(Lazy<MacroDef>),
     ProcMacro(MacroKind),
     Closure,
@@ -364,12 +364,6 @@ enum EntryKind {
 #[derive(Encodable, Decodable)]
 struct RenderedConst(String);
 
-#[derive(MetadataEncodable, MetadataDecodable)]
-struct ModData {
-    reexports: Lazy<[Export]>,
-    expansion: ExpnId,
-}
-
 #[derive(MetadataEncodable, MetadataDecodable)]
 struct FnData {
     asyncness: hir::IsAsync,
index d06c593d39481e12e11a5adbb82778dc0bbfd669..daeccde6024e66340d8e741c5c419bc843d5daa8 100644 (file)
@@ -12,6 +12,7 @@ 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"
 polonius-engine = "0.13.0"
 rustc_apfloat = { path = "../rustc_apfloat" }
index 962aea448b82ca5ae2c79b9af400692e569d7151..420c500a7de22e427e34a3eb4f68795ba799c0ec 100644 (file)
@@ -92,12 +92,6 @@ macro_rules! arena_types {
             [] tys: rustc_middle::ty::TyS<$tcx>,
             [] predicates: rustc_middle::ty::PredicateInner<$tcx>,
 
-            // HIR query types
-            [few] indexed_hir: rustc_middle::hir::IndexedHir<$tcx>,
-            [few] hir_definitions: rustc_hir::definitions::Definitions,
-            [] hir_owner: rustc_middle::hir::Owner<$tcx>,
-            [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>,
-
             // Note that this deliberately duplicates items in the `rustc_hir::arena`,
             // since we need to allocate this type on both the `rustc_hir` arena
             // (during lowering) and the `librustc_middle` arena (for decoding MIR)
@@ -106,6 +100,8 @@ macro_rules! arena_types {
             // This is used to decode the &'tcx [Span] for InlineAsm's line_spans.
             [decode] span: rustc_span::Span,
             [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>,
+
+            [] dep_kind: rustc_middle::dep_graph::DepKindStruct,
         ], $tcx);
     )
 }
index 23d475a59538f8c6f191a4ae84a53cd0788e44a6..f3100010770307a08e1168547bd4c3d1082880d5 100644 (file)
 /// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
 /// jump table instead of large matches.
 pub struct DepKindStruct {
-    /// Whether the DepNode has parameters (query keys).
-    pub(super) has_params: bool,
-
     /// Anonymous queries cannot be replayed from one compiler invocation to the next.
     /// When their result is needed, it is recomputed. They are useful for fine-grained
     /// dependency tracking, and caching within one compiler invocation.
-    pub(super) is_anon: bool,
+    pub is_anon: bool,
 
     /// Eval-always queries do not track their dependencies, and are always recomputed, even if
     /// their inputs have not changed since the last compiler invocation. The result is still
     /// cached within one compiler invocation.
-    pub(super) is_eval_always: bool,
+    pub is_eval_always: bool,
 
     /// Whether the query key can be recovered from the hashed fingerprint.
     /// See [DepNodeParams] trait for the behaviour of each key type.
-    // FIXME: Make this a simple boolean once DepNodeParams::fingerprint_style
-    // can be made a specialized associated const.
-    fingerprint_style: fn() -> FingerprintStyle,
-}
-
-impl std::ops::Deref for DepKind {
-    type Target = DepKindStruct;
-    fn deref(&self) -> &DepKindStruct {
-        &DEP_KINDS[*self as usize]
-    }
+    pub fingerprint_style: FingerprintStyle,
+
+    /// The red/green evaluation system will try to mark a specific DepNode in the
+    /// dependency graph as green by recursively trying to mark the dependencies of
+    /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
+    /// where we don't know if it is red or green and we therefore actually have
+    /// to recompute its value in order to find out. Since the only piece of
+    /// information that we have at that point is the `DepNode` we are trying to
+    /// re-evaluate, we need some way to re-run a query from just that. This is what
+    /// `force_from_dep_node()` implements.
+    ///
+    /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
+    /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
+    /// is usually constructed by computing a stable hash of the query-key that the
+    /// `DepNode` corresponds to. Consequently, it is not in general possible to go
+    /// back from hash to query-key (since hash functions are not reversible). For
+    /// this reason `force_from_dep_node()` is expected to fail from time to time
+    /// because we just cannot find out, from the `DepNode` alone, what the
+    /// corresponding query-key is and therefore cannot re-run the query.
+    ///
+    /// The system deals with this case letting `try_mark_green` fail which forces
+    /// the root query to be re-evaluated.
+    ///
+    /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
+    /// Fortunately, we can use some contextual information that will allow us to
+    /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
+    /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
+    /// valid `DefPathHash`. Since we also always build a huge table that maps every
+    /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
+    /// everything we need to re-run the query.
+    ///
+    /// Take the `mir_promoted` query as an example. Like many other queries, it
+    /// just has a single parameter: the `DefId` of the item it will compute the
+    /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
+    /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
+    /// is actually a `DefPathHash`, and can therefore just look up the corresponding
+    /// `DefId` in `tcx.def_path_hash_to_def_id`.
+    pub force_from_dep_node: Option<fn(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool>,
+
+    /// Invoke a query to put the on-disk cached value in memory.
+    pub try_load_from_on_disk_cache: Option<fn(TyCtxt<'_>, DepNode)>,
 }
 
 impl DepKind {
     #[inline(always)]
-    pub fn fingerprint_style(&self) -> FingerprintStyle {
+    pub fn fingerprint_style(self, tcx: TyCtxt<'_>) -> FingerprintStyle {
         // Only fetch the DepKindStruct once.
-        let data: &DepKindStruct = &**self;
+        let data = tcx.query_kind(self);
         if data.is_anon {
             return FingerprintStyle::Opaque;
         }
-
-        (data.fingerprint_style)()
-    }
-}
-
-// erase!() just makes tokens go away. It's used to specify which macro argument
-// is repeated (i.e., which sub-expression of the macro we are in) but don't need
-// to actually use any of the arguments.
-macro_rules! erase {
-    ($x:tt) => {{}};
-}
-
-macro_rules! is_anon_attr {
-    (anon) => {
-        true
-    };
-    ($attr:ident) => {
-        false
-    };
-}
-
-macro_rules! is_eval_always_attr {
-    (eval_always) => {
-        true
-    };
-    ($attr:ident) => {
-        false
-    };
-}
-
-macro_rules! contains_anon_attr {
-    ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_anon_attr!($attr) | )* false});
-}
-
-macro_rules! contains_eval_always_attr {
-    ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_eval_always_attr!($attr) | )* false});
-}
-
-#[allow(non_upper_case_globals)]
-pub mod dep_kind {
-    use super::*;
-    use crate::ty::query::query_keys;
-    use rustc_query_system::dep_graph::FingerprintStyle;
-
-    // We use this for most things when incr. comp. is turned off.
-    pub const Null: DepKindStruct = DepKindStruct {
-        has_params: false,
-        is_anon: false,
-        is_eval_always: false,
-
-        fingerprint_style: || FingerprintStyle::Unit,
-    };
-
-    pub const TraitSelect: DepKindStruct = DepKindStruct {
-        has_params: false,
-        is_anon: true,
-        is_eval_always: false,
-
-        fingerprint_style: || FingerprintStyle::Unit,
-    };
-
-    pub const CompileCodegenUnit: DepKindStruct = DepKindStruct {
-        has_params: true,
-        is_anon: false,
-        is_eval_always: false,
-
-        fingerprint_style: || FingerprintStyle::Opaque,
-    };
-
-    pub const CompileMonoItem: DepKindStruct = DepKindStruct {
-        has_params: true,
-        is_anon: false,
-        is_eval_always: false,
-
-        fingerprint_style: || FingerprintStyle::Opaque,
-    };
-
-    macro_rules! define_query_dep_kinds {
-        ($(
-            [$($attrs:tt)*]
-            $variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
-        ,)*) => (
-            $(pub const $variant: DepKindStruct = {
-                const has_params: bool = $({ erase!($tuple_arg_ty); true } |)* false;
-                const is_anon: bool = contains_anon_attr!($($attrs)*);
-                const is_eval_always: bool = contains_eval_always_attr!($($attrs)*);
-
-                #[inline(always)]
-                fn fingerprint_style() -> rustc_query_system::dep_graph::FingerprintStyle {
-                    <query_keys::$variant<'_> as DepNodeParams<TyCtxt<'_>>>
-                        ::fingerprint_style()
-                }
-
-                DepKindStruct {
-                    has_params,
-                    is_anon,
-                    is_eval_always,
-                    fingerprint_style,
-                }
-            };)*
-        );
+        data.fingerprint_style
     }
-
-    rustc_dep_node_append!([define_query_dep_kinds!][]);
 }
 
 macro_rules! define_dep_nodes {
@@ -225,12 +151,10 @@ macro_rules! define_dep_nodes {
     ) => (
         #[macro_export]
         macro_rules! make_dep_kind_array {
-            ($mod:ident) => {[ $(($mod::$variant),)* ]};
+            ($mod:ident) => {[ $($mod::$variant()),* ]};
         }
 
-        static DEP_KINDS: &[DepKindStruct] = &make_dep_kind_array!(dep_kind);
-
-        /// This enum serves as an index into the `DEP_KINDS` array.
+        /// This enum serves as an index into arrays built by `make_dep_kind_array`.
         #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
         #[allow(non_camel_case_types)]
         pub enum DepKind {
@@ -296,7 +220,7 @@ pub trait DepNodeExt: Sized {
     /// Construct a DepNode from the given DepKind and DefPathHash. This
     /// method will assert that the given DepKind actually requires a
     /// single DefId/DefPathHash parameter.
-    fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self;
+    fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> Self;
 
     /// Extracts the DefId corresponding to this DepNode. This will work
     /// if two conditions are met:
@@ -311,7 +235,11 @@ pub trait DepNodeExt: Sized {
     fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>;
 
     /// Used in testing
-    fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<Self, ()>;
+    fn from_label_string(
+        tcx: TyCtxt<'_>,
+        label: &str,
+        def_path_hash: DefPathHash,
+    ) -> Result<Self, ()>;
 
     /// Used in testing
     fn has_label_string(label: &str) -> bool;
@@ -321,8 +249,8 @@ impl DepNodeExt for DepNode {
     /// Construct a DepNode from the given DepKind and DefPathHash. This
     /// method will assert that the given DepKind actually requires a
     /// single DefId/DefPathHash parameter.
-    fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
-        debug_assert!(kind.fingerprint_style() == FingerprintStyle::DefPathHash);
+    fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
+        debug_assert!(kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash);
         DepNode { kind, hash: def_path_hash.0.into() }
     }
 
@@ -337,31 +265,27 @@ fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
     /// refers to something from the previous compilation session that
     /// has been removed.
     fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
-        if self.kind.fingerprint_style() == FingerprintStyle::DefPathHash {
-            Some(
-                tcx.on_disk_cache
-                    .as_ref()?
-                    .def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into())),
-            )
+        if self.kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash {
+            Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into())))
         } else {
             None
         }
     }
 
     /// Used in testing
-    fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> {
+    fn from_label_string(
+        tcx: TyCtxt<'_>,
+        label: &str,
+        def_path_hash: DefPathHash,
+    ) -> Result<DepNode, ()> {
         let kind = dep_kind_from_label_string(label)?;
 
-        match kind.fingerprint_style() {
+        match kind.fingerprint_style(tcx) {
             FingerprintStyle::Opaque => Err(()),
-            FingerprintStyle::Unit => {
-                if !kind.has_params {
-                    Ok(DepNode::new_no_params(kind))
-                } else {
-                    Err(())
-                }
+            FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
+            FingerprintStyle::DefPathHash => {
+                Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind))
             }
-            FingerprintStyle::DefPathHash => Ok(DepNode::from_def_path_hash(def_path_hash, kind)),
         }
     }
 
@@ -377,10 +301,12 @@ fn fingerprint_style() -> FingerprintStyle {
         FingerprintStyle::Unit
     }
 
+    #[inline(always)]
     fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
         Fingerprint::ZERO
     }
 
+    #[inline(always)]
     fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
         Some(())
     }
@@ -392,14 +318,17 @@ fn fingerprint_style() -> FingerprintStyle {
         FingerprintStyle::DefPathHash
     }
 
+    #[inline(always)]
     fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
         tcx.def_path_hash(*self).0
     }
 
+    #[inline(always)]
     fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
         tcx.def_path_str(*self)
     }
 
+    #[inline(always)]
     fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
         dep_node.extract_def_id(tcx)
     }
@@ -411,14 +340,17 @@ fn fingerprint_style() -> FingerprintStyle {
         FingerprintStyle::DefPathHash
     }
 
+    #[inline(always)]
     fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
         self.to_def_id().to_fingerprint(tcx)
     }
 
+    #[inline(always)]
     fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
         self.to_def_id().to_debug_str(tcx)
     }
 
+    #[inline(always)]
     fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
         dep_node.extract_def_id(tcx).map(|id| id.expect_local())
     }
@@ -430,15 +362,18 @@ fn fingerprint_style() -> FingerprintStyle {
         FingerprintStyle::DefPathHash
     }
 
+    #[inline(always)]
     fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
         let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
         def_id.to_fingerprint(tcx)
     }
 
+    #[inline(always)]
     fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
         tcx.crate_name(*self).to_string()
     }
 
+    #[inline(always)]
     fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
         dep_node.extract_def_id(tcx).map(|id| id.krate)
     }
@@ -453,6 +388,7 @@ fn fingerprint_style() -> FingerprintStyle {
     // We actually would not need to specialize the implementation of this
     // method but it's faster to combine the hashes than to instantiate a full
     // hashing context and stable-hashing state.
+    #[inline(always)]
     fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
         let (def_id_0, def_id_1) = *self;
 
@@ -462,6 +398,7 @@ fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
         def_path_hash_0.0.combine(def_path_hash_1.0)
     }
 
+    #[inline(always)]
     fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
         let (def_id_0, def_id_1) = *self;
 
@@ -478,6 +415,7 @@ fn fingerprint_style() -> FingerprintStyle {
     // We actually would not need to specialize the implementation of this
     // method but it's faster to combine the hashes than to instantiate a full
     // hashing context and stable-hashing state.
+    #[inline(always)]
     fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
         let HirId { owner, local_id } = *self;
 
index cda9963907482f9a78ac3fa170df3b3745a619d5..79d7ca32f35553ba9e525404bd5b7f0cdda71e67 100644 (file)
@@ -12,7 +12,7 @@
     SerializedDepNodeIndex, WorkProduct, WorkProductId,
 };
 
-pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt};
+pub use dep_node::{label_strs, DepKind, DepKindStruct, DepNode, DepNodeExt};
 crate use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
 
 pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
 impl rustc_query_system::dep_graph::DepKind for DepKind {
     const NULL: Self = DepKind::Null;
 
-    #[inline(always)]
-    fn fingerprint_style(&self) -> rustc_query_system::dep_graph::FingerprintStyle {
-        DepKind::fingerprint_style(self)
-    }
-
-    #[inline(always)]
-    fn is_eval_always(&self) -> bool {
-        self.is_eval_always
-    }
-
-    #[inline(always)]
-    fn has_params(&self) -> bool {
-        self.has_params
-    }
-
     fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(f, "{:?}", node.kind)?;
-
-        if !node.kind.has_params && !node.kind.is_anon {
-            return Ok(());
-        }
-
-        write!(f, "(")?;
+        write!(f, "{:?}(", node.kind)?;
 
         ty::tls::with_opt(|opt_tcx| {
             if let Some(tcx) = opt_tcx {
@@ -110,4 +89,51 @@ fn profiler(&self) -> &SelfProfilerRef {
     fn sess(&self) -> &Session {
         self.sess
     }
+
+    #[inline(always)]
+    fn fingerprint_style(&self, kind: DepKind) -> rustc_query_system::dep_graph::FingerprintStyle {
+        kind.fingerprint_style(*self)
+    }
+
+    #[inline(always)]
+    fn is_eval_always(&self, kind: DepKind) -> bool {
+        self.query_kind(kind).is_eval_always
+    }
+
+    fn try_force_from_dep_node(&self, dep_node: DepNode) -> bool {
+        debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
+
+        // We must avoid ever having to call `force_from_dep_node()` for a
+        // `DepNode::codegen_unit`:
+        // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
+        // would always end up having to evaluate the first caller of the
+        // `codegen_unit` query that *is* reconstructible. This might very well be
+        // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
+        // to re-trigger calling the `codegen_unit` query with the right key. At
+        // that point we would already have re-done all the work we are trying to
+        // avoid doing in the first place.
+        // The solution is simple: Just explicitly call the `codegen_unit` query for
+        // each CGU, right after partitioning. This way `try_mark_green` will always
+        // hit the cache instead of having to go through `force_from_dep_node`.
+        // This assertion makes sure, we actually keep applying the solution above.
+        debug_assert!(
+            dep_node.kind != DepKind::codegen_unit,
+            "calling force_from_dep_node() on DepKind::codegen_unit"
+        );
+
+        let cb = self.query_kind(dep_node.kind);
+        if let Some(f) = cb.force_from_dep_node {
+            f(*self, dep_node);
+            true
+        } else {
+            false
+        }
+    }
+
+    fn try_load_from_on_disk_cache(&self, dep_node: DepNode) {
+        let cb = self.query_kind(dep_node.kind);
+        if let Some(f) = cb.try_load_from_on_disk_cache {
+            f(*self, dep_node)
+        }
+    }
 }
diff --git a/compiler/rustc_middle/src/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs
deleted file mode 100644 (file)
index 8efec8e..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-//! This module provides a simplified abstraction for working with
-//! code blocks identified by their integer `NodeId`. In particular,
-//! it captures a common set of attributes that all "function-like
-//! things" (represented by `FnLike` instances) share. For example,
-//! all `FnLike` instances have a type signature (be it explicit or
-//! inferred). And all `FnLike` instances have a body, i.e., the code
-//! that is run when the function-like thing it represents is invoked.
-//!
-//! With the above abstraction in place, one can treat the program
-//! text as a collection of blocks of code (and most such blocks are
-//! nested within a uniquely determined `FnLike`), and users can ask
-//! for the `Code` associated with a particular NodeId.
-
-use crate::hir::map::Map;
-use rustc_hir as hir;
-use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Expr, FnDecl, Node};
-use rustc_span::symbol::Ident;
-use rustc_span::Span;
-
-/// An FnLikeNode is a Node that is like a fn, in that it has a decl
-/// and a body (as well as a NodeId, a span, etc).
-///
-/// More specifically, it is one of either:
-///
-///   - A function item,
-///   - A closure expr (i.e., an ExprKind::Closure), or
-///   - The default implementation for a trait method.
-///
-/// To construct one, use the `Code::from_node` function.
-#[derive(Copy, Clone, Debug)]
-pub struct FnLikeNode<'a> {
-    node: Node<'a>,
-}
-
-/// MaybeFnLike wraps a method that indicates if an object
-/// corresponds to some FnLikeNode.
-trait MaybeFnLike {
-    fn is_fn_like(&self) -> bool;
-}
-
-impl MaybeFnLike for hir::Item<'_> {
-    fn is_fn_like(&self) -> bool {
-        matches!(self.kind, hir::ItemKind::Fn(..))
-    }
-}
-
-impl MaybeFnLike for hir::ImplItem<'_> {
-    fn is_fn_like(&self) -> bool {
-        matches!(self.kind, hir::ImplItemKind::Fn(..))
-    }
-}
-
-impl MaybeFnLike for hir::TraitItem<'_> {
-    fn is_fn_like(&self) -> bool {
-        matches!(self.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)))
-    }
-}
-
-impl MaybeFnLike for hir::Expr<'_> {
-    fn is_fn_like(&self) -> bool {
-        matches!(self.kind, hir::ExprKind::Closure(..))
-    }
-}
-
-/// Carries either an FnLikeNode or an Expr, as these are the two
-/// constructs that correspond to "code" (as in, something from which
-/// we can construct a control-flow graph).
-#[derive(Copy, Clone)]
-pub enum Code<'a> {
-    FnLike(FnLikeNode<'a>),
-    Expr(&'a Expr<'a>),
-}
-
-impl<'a> Code<'a> {
-    pub fn id(&self) -> hir::HirId {
-        match *self {
-            Code::FnLike(node) => node.id(),
-            Code::Expr(block) => block.hir_id,
-        }
-    }
-
-    /// Attempts to construct a Code from presumed FnLike or Expr node input.
-    pub fn from_node(map: &Map<'a>, id: hir::HirId) -> Option<Code<'a>> {
-        match map.get(id) {
-            Node::Block(_) => {
-                //  Use the parent, hopefully an expression node.
-                Code::from_node(map, map.get_parent_node(id))
-            }
-            Node::Expr(expr) => Some(Code::Expr(expr)),
-            node => FnLikeNode::from_node(node).map(Code::FnLike),
-        }
-    }
-}
-
-/// These are all the components one can extract from a fn item for
-/// use when implementing FnLikeNode operations.
-struct ItemFnParts<'a> {
-    ident: Ident,
-    decl: &'a hir::FnDecl<'a>,
-    header: hir::FnHeader,
-    vis: &'a hir::Visibility<'a>,
-    generics: &'a hir::Generics<'a>,
-    body: hir::BodyId,
-    id: hir::HirId,
-    span: Span,
-}
-
-/// These are all the components one can extract from a closure expr
-/// for use when implementing FnLikeNode operations.
-struct ClosureParts<'a> {
-    decl: &'a FnDecl<'a>,
-    body: hir::BodyId,
-    id: hir::HirId,
-    span: Span,
-}
-
-impl<'a> ClosureParts<'a> {
-    fn new(d: &'a FnDecl<'a>, b: hir::BodyId, id: hir::HirId, s: Span) -> Self {
-        ClosureParts { decl: d, body: b, id, span: s }
-    }
-}
-
-impl<'a> FnLikeNode<'a> {
-    /// Attempts to construct a FnLikeNode from presumed FnLike node input.
-    pub fn from_node(node: Node<'_>) -> Option<FnLikeNode<'_>> {
-        let fn_like = match node {
-            Node::Item(item) => item.is_fn_like(),
-            Node::TraitItem(tm) => tm.is_fn_like(),
-            Node::ImplItem(it) => it.is_fn_like(),
-            Node::Expr(e) => e.is_fn_like(),
-            _ => false,
-        };
-        fn_like.then_some(FnLikeNode { node })
-    }
-
-    pub fn body(self) -> hir::BodyId {
-        self.handle(
-            |i: ItemFnParts<'a>| i.body,
-            |_, _, _: &'a hir::FnSig<'a>, _, body: hir::BodyId, _| body,
-            |c: ClosureParts<'a>| c.body,
-        )
-    }
-
-    pub fn decl(self) -> &'a FnDecl<'a> {
-        self.handle(
-            |i: ItemFnParts<'a>| &*i.decl,
-            |_, _, sig: &'a hir::FnSig<'a>, _, _, _| &sig.decl,
-            |c: ClosureParts<'a>| c.decl,
-        )
-    }
-
-    pub fn span(self) -> Span {
-        self.handle(
-            |i: ItemFnParts<'_>| i.span,
-            |_, _, _: &'a hir::FnSig<'a>, _, _, span| span,
-            |c: ClosureParts<'_>| c.span,
-        )
-    }
-
-    pub fn id(self) -> hir::HirId {
-        self.handle(
-            |i: ItemFnParts<'_>| i.id,
-            |id, _, _: &'a hir::FnSig<'a>, _, _, _| id,
-            |c: ClosureParts<'_>| c.id,
-        )
-    }
-
-    pub fn constness(self) -> hir::Constness {
-        self.kind().header().map_or(hir::Constness::NotConst, |header| header.constness)
-    }
-
-    pub fn asyncness(self) -> hir::IsAsync {
-        self.kind().header().map_or(hir::IsAsync::NotAsync, |header| header.asyncness)
-    }
-
-    pub fn unsafety(self) -> hir::Unsafety {
-        self.kind().header().map_or(hir::Unsafety::Normal, |header| header.unsafety)
-    }
-
-    pub fn kind(self) -> FnKind<'a> {
-        let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
-            FnKind::ItemFn(p.ident, p.generics, p.header, p.vis)
-        };
-        let closure = |_: ClosureParts<'a>| FnKind::Closure;
-        let method =
-            |_, ident: Ident, sig: &'a hir::FnSig<'a>, vis, _, _| FnKind::Method(ident, sig, vis);
-        self.handle(item, method, closure)
-    }
-
-    fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A
-    where
-        I: FnOnce(ItemFnParts<'a>) -> A,
-        M: FnOnce(
-            hir::HirId,
-            Ident,
-            &'a hir::FnSig<'a>,
-            Option<&'a hir::Visibility<'a>>,
-            hir::BodyId,
-            Span,
-        ) -> A,
-        C: FnOnce(ClosureParts<'a>) -> A,
-    {
-        match self.node {
-            Node::Item(i) => match i.kind {
-                hir::ItemKind::Fn(ref sig, ref generics, block) => item_fn(ItemFnParts {
-                    id: i.hir_id(),
-                    ident: i.ident,
-                    decl: &sig.decl,
-                    body: block,
-                    vis: &i.vis,
-                    span: i.span,
-                    header: sig.header,
-                    generics,
-                }),
-                _ => bug!("item FnLikeNode that is not fn-like"),
-            },
-            Node::TraitItem(ti) => match ti.kind {
-                hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
-                    method(ti.hir_id(), ti.ident, sig, None, body, ti.span)
-                }
-                _ => bug!("trait method FnLikeNode that is not fn-like"),
-            },
-            Node::ImplItem(ii) => match ii.kind {
-                hir::ImplItemKind::Fn(ref sig, body) => {
-                    method(ii.hir_id(), ii.ident, sig, Some(&ii.vis), body, ii.span)
-                }
-                _ => bug!("impl method FnLikeNode that is not fn-like"),
-            },
-            Node::Expr(e) => match e.kind {
-                hir::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) => {
-                    closure(ClosureParts::new(&decl, block, e.hir_id, e.span))
-                }
-                _ => bug!("expr FnLikeNode that is not fn-like"),
-            },
-            _ => bug!("other FnLikeNode that is not fn-like"),
-        }
-    }
-}
diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs
deleted file mode 100644 (file)
index efebf73..0000000
+++ /dev/null
@@ -1,431 +0,0 @@
-use crate::arena::Arena;
-use crate::hir::map::Map;
-use crate::hir::{IndexedHir, OwnerNodes, ParentedNode};
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::def_id::CRATE_DEF_ID;
-use rustc_hir::definitions;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::*;
-use rustc_index::vec::{Idx, IndexVec};
-use rustc_query_system::ich::StableHashingContext;
-use rustc_session::Session;
-use rustc_span::source_map::SourceMap;
-use rustc_span::{Span, DUMMY_SP};
-
-use std::iter::repeat;
-
-/// A visitor that walks over the HIR and collects `Node`s into a HIR map.
-pub(super) struct NodeCollector<'a, 'hir> {
-    arena: &'hir Arena<'hir>,
-
-    /// The crate
-    krate: &'hir Crate<'hir>,
-
-    /// Source map
-    source_map: &'a SourceMap,
-
-    map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
-    parenting: FxHashMap<LocalDefId, HirId>,
-
-    /// The parent of this node
-    parent_node: hir::HirId,
-
-    current_dep_node_owner: LocalDefId,
-
-    definitions: &'a definitions::Definitions,
-
-    hcx: StableHashingContext<'a>,
-}
-
-fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V) {
-    let i = k.index();
-    let len = map.len();
-    if i >= len {
-        map.extend(repeat(None).take(i - len + 1));
-    }
-    debug_assert!(map[k].is_none());
-    map[k] = Some(v);
-}
-
-fn hash_body(
-    hcx: &mut StableHashingContext<'_>,
-    item_like: impl for<'a> HashStable<StableHashingContext<'a>>,
-) -> Fingerprint {
-    let mut stable_hasher = StableHasher::new();
-    hcx.while_hashing_hir_bodies(true, |hcx| {
-        item_like.hash_stable(hcx, &mut stable_hasher);
-    });
-    stable_hasher.finish()
-}
-
-impl<'a, 'hir> NodeCollector<'a, 'hir> {
-    pub(super) fn root(
-        sess: &'a Session,
-        arena: &'hir Arena<'hir>,
-        krate: &'hir Crate<'hir>,
-        definitions: &'a definitions::Definitions,
-        hcx: StableHashingContext<'a>,
-    ) -> NodeCollector<'a, 'hir> {
-        let mut collector = NodeCollector {
-            arena,
-            krate,
-            source_map: sess.source_map(),
-            parent_node: hir::CRATE_HIR_ID,
-            current_dep_node_owner: CRATE_DEF_ID,
-            definitions,
-            hcx,
-            map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()),
-            parenting: FxHashMap::default(),
-        };
-        collector.insert_owner(CRATE_DEF_ID, OwnerNode::Crate(krate.module()));
-
-        collector
-    }
-
-    pub(super) fn finalize_and_compute_crate_hash(mut self) -> IndexedHir<'hir> {
-        // Insert bodies into the map
-        for (id, body) in self.krate.bodies.iter() {
-            let bodies = &mut self.map[id.hir_id.owner].as_mut().unwrap().bodies;
-            assert!(bodies.insert(id.hir_id.local_id, body).is_none());
-        }
-        IndexedHir { map: self.map, parenting: self.parenting }
-    }
-
-    fn insert_owner(&mut self, owner: LocalDefId, node: OwnerNode<'hir>) {
-        let hash = hash_body(&mut self.hcx, node);
-
-        let mut nodes = IndexVec::new();
-        nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: node.into() }));
-
-        debug_assert!(self.map[owner].is_none());
-        self.map[owner] =
-            Some(self.arena.alloc(OwnerNodes { hash, nodes, bodies: FxHashMap::default() }));
-    }
-
-    fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
-        debug_assert_eq!(self.current_dep_node_owner, hir_id.owner);
-        debug_assert_ne!(hir_id.local_id.as_u32(), 0);
-
-        // Make sure that the DepNode of some node coincides with the HirId
-        // owner of that node.
-        if cfg!(debug_assertions) {
-            if hir_id.owner != self.current_dep_node_owner {
-                let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) {
-                    Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate_verbose(),
-                    None => format!("{:?}", node),
-                };
-
-                span_bug!(
-                    span,
-                    "inconsistent DepNode at `{:?}` for `{}`: \
-                     current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
-                    self.source_map.span_to_diagnostic_string(span),
-                    node_str,
-                    self.definitions
-                        .def_path(self.current_dep_node_owner)
-                        .to_string_no_crate_verbose(),
-                    self.current_dep_node_owner,
-                    self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(),
-                    hir_id.owner,
-                )
-            }
-        }
-
-        let nodes = self.map[hir_id.owner].as_mut().unwrap();
-
-        debug_assert_eq!(self.parent_node.owner, self.current_dep_node_owner);
-        insert_vec_map(
-            &mut nodes.nodes,
-            hir_id.local_id,
-            ParentedNode { parent: self.parent_node.local_id, node: node },
-        );
-    }
-
-    fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) {
-        let parent_node = self.parent_node;
-        self.parent_node = parent_node_id;
-        f(self);
-        self.parent_node = parent_node;
-    }
-
-    fn with_dep_node_owner(&mut self, dep_node_owner: LocalDefId, f: impl FnOnce(&mut Self)) {
-        let prev_owner = self.current_dep_node_owner;
-        let prev_parent = self.parent_node;
-
-        self.current_dep_node_owner = dep_node_owner;
-        self.parent_node = HirId::make_owner(dep_node_owner);
-        f(self);
-        self.current_dep_node_owner = prev_owner;
-        self.parent_node = prev_parent;
-    }
-
-    fn insert_nested(&mut self, item: LocalDefId) {
-        #[cfg(debug_assertions)]
-        {
-            let dk_parent = self.definitions.def_key(item).parent.unwrap();
-            let dk_parent = LocalDefId { local_def_index: dk_parent };
-            let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent);
-            debug_assert_eq!(
-                dk_parent.owner, self.parent_node.owner,
-                "Different parents for {:?}",
-                item
-            )
-        }
-
-        assert_eq!(self.parenting.insert(item, self.parent_node), None);
-    }
-}
-
-impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
-    type Map = Map<'hir>;
-
-    /// 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);
-        self.visit_item(self.krate.item(item));
-    }
-
-    fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
-        self.insert_nested(item_id.def_id);
-        self.visit_trait_item(self.krate.trait_item(item_id));
-    }
-
-    fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
-        self.insert_nested(item_id.def_id);
-        self.visit_impl_item(self.krate.impl_item(item_id));
-    }
-
-    fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
-        self.insert_nested(foreign_id.def_id);
-        self.visit_foreign_item(self.krate.foreign_item(foreign_id));
-    }
-
-    fn visit_nested_body(&mut self, id: BodyId) {
-        self.visit_body(self.krate.body(id));
-    }
-
-    fn visit_param(&mut self, param: &'hir Param<'hir>) {
-        let node = Node::Param(param);
-        self.insert(param.pat.span, param.hir_id, node);
-        self.with_parent(param.hir_id, |this| {
-            intravisit::walk_param(this, param);
-        });
-    }
-
-    fn visit_item(&mut self, i: &'hir Item<'hir>) {
-        debug!("visit_item: {:?}", i);
-        self.insert_owner(i.def_id, OwnerNode::Item(i));
-        self.with_dep_node_owner(i.def_id, |this| {
-            if let ItemKind::Struct(ref struct_def, _) = i.kind {
-                // If this is a tuple or unit-like struct, register the constructor.
-                if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
-                    this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
-                }
-            }
-            intravisit::walk_item(this, i);
-        });
-    }
-
-    fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
-        self.insert_owner(fi.def_id, OwnerNode::ForeignItem(fi));
-        self.with_dep_node_owner(fi.def_id, |this| {
-            intravisit::walk_foreign_item(this, fi);
-        });
-    }
-
-    fn visit_generic_param(&mut self, param: &'hir GenericParam<'hir>) {
-        self.insert(param.span, param.hir_id, Node::GenericParam(param));
-        intravisit::walk_generic_param(self, param);
-    }
-
-    fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) {
-        self.with_parent(param, |this| {
-            intravisit::walk_const_param_default(this, ct);
-        })
-    }
-
-    fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
-        self.insert_owner(ti.def_id, OwnerNode::TraitItem(ti));
-        self.with_dep_node_owner(ti.def_id, |this| {
-            intravisit::walk_trait_item(this, ti);
-        });
-    }
-
-    fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
-        self.insert_owner(ii.def_id, OwnerNode::ImplItem(ii));
-        self.with_dep_node_owner(ii.def_id, |this| {
-            intravisit::walk_impl_item(this, ii);
-        });
-    }
-
-    fn visit_pat(&mut self, pat: &'hir Pat<'hir>) {
-        let node =
-            if let PatKind::Binding(..) = pat.kind { Node::Binding(pat) } else { Node::Pat(pat) };
-        self.insert(pat.span, pat.hir_id, node);
-
-        self.with_parent(pat.hir_id, |this| {
-            intravisit::walk_pat(this, pat);
-        });
-    }
-
-    fn visit_arm(&mut self, arm: &'hir Arm<'hir>) {
-        let node = Node::Arm(arm);
-
-        self.insert(arm.span, arm.hir_id, node);
-
-        self.with_parent(arm.hir_id, |this| {
-            intravisit::walk_arm(this, arm);
-        });
-    }
-
-    fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
-        self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant));
-
-        self.with_parent(constant.hir_id, |this| {
-            intravisit::walk_anon_const(this, constant);
-        });
-    }
-
-    fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
-        self.insert(expr.span, expr.hir_id, Node::Expr(expr));
-
-        self.with_parent(expr.hir_id, |this| {
-            intravisit::walk_expr(this, expr);
-        });
-    }
-
-    fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) {
-        self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt));
-
-        self.with_parent(stmt.hir_id, |this| {
-            intravisit::walk_stmt(this, stmt);
-        });
-    }
-
-    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment<'hir>) {
-        if let Some(hir_id) = path_segment.hir_id {
-            self.insert(path_span, hir_id, Node::PathSegment(path_segment));
-        }
-        intravisit::walk_path_segment(self, path_span, path_segment);
-    }
-
-    fn visit_ty(&mut self, ty: &'hir Ty<'hir>) {
-        self.insert(ty.span, ty.hir_id, Node::Ty(ty));
-
-        self.with_parent(ty.hir_id, |this| {
-            intravisit::walk_ty(this, ty);
-        });
-    }
-
-    fn visit_infer(&mut self, inf: &'hir InferArg) {
-        self.insert(inf.span, inf.hir_id, Node::Infer(inf));
-
-        self.with_parent(inf.hir_id, |this| {
-            intravisit::walk_inf(this, inf);
-        });
-    }
-
-    fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) {
-        self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr));
-
-        self.with_parent(tr.hir_ref_id, |this| {
-            intravisit::walk_trait_ref(this, tr);
-        });
-    }
-
-    fn visit_fn(
-        &mut self,
-        fk: intravisit::FnKind<'hir>,
-        fd: &'hir FnDecl<'hir>,
-        b: BodyId,
-        s: Span,
-        id: HirId,
-    ) {
-        assert_eq!(self.parent_node, id);
-        intravisit::walk_fn(self, fk, fd, b, s, id);
-    }
-
-    fn visit_block(&mut self, block: &'hir Block<'hir>) {
-        self.insert(block.span, block.hir_id, Node::Block(block));
-        self.with_parent(block.hir_id, |this| {
-            intravisit::walk_block(this, block);
-        });
-    }
-
-    fn visit_local(&mut self, l: &'hir Local<'hir>) {
-        self.insert(l.span, l.hir_id, Node::Local(l));
-        self.with_parent(l.hir_id, |this| {
-            intravisit::walk_local(this, l);
-        })
-    }
-
-    fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) {
-        self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime));
-    }
-
-    fn visit_vis(&mut self, visibility: &'hir Visibility<'hir>) {
-        match visibility.node {
-            VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {}
-            VisibilityKind::Restricted { hir_id, .. } => {
-                self.insert(visibility.span, hir_id, Node::Visibility(visibility));
-                self.with_parent(hir_id, |this| {
-                    intravisit::walk_vis(this, visibility);
-                });
-            }
-        }
-    }
-
-    fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) {
-        self.insert(v.span, v.id, Node::Variant(v));
-        self.with_parent(v.id, |this| {
-            // Register the constructor of this variant.
-            if let Some(ctor_hir_id) = v.data.ctor_hir_id() {
-                this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data));
-            }
-            intravisit::walk_variant(this, v, g, item_id);
-        });
-    }
-
-    fn visit_field_def(&mut self, field: &'hir FieldDef<'hir>) {
-        self.insert(field.span, field.hir_id, Node::Field(field));
-        self.with_parent(field.hir_id, |this| {
-            intravisit::walk_field_def(this, field);
-        });
-    }
-
-    fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
-        // Do not visit the duplicate information in TraitItemRef. We want to
-        // map the actual nodes, not the duplicate ones in the *Ref.
-        let TraitItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
-
-        self.visit_nested_trait_item(id);
-    }
-
-    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;
-
-        self.visit_nested_impl_item(id);
-    }
-
-    fn visit_foreign_item_ref(&mut self, fi: &'hir ForeignItemRef) {
-        // Do not visit the duplicate information in ForeignItemRef. We want to
-        // map the actual nodes, not the duplicate ones in the *Ref.
-        let ForeignItemRef { id, ident: _, span: _ } = *fi;
-
-        self.visit_nested_foreign_item(id);
-    }
-}
index e6f56b0be93037a095b413f07e8699c0ddb16d49..8f52e16c2ebe41e7873d6893dc0917be4e1a37a4 100644 (file)
@@ -1,6 +1,4 @@
-use self::collector::NodeCollector;
-
-use crate::hir::{AttributeMap, IndexedHir, ModuleItems, Owner};
+use crate::hir::{ModuleItems, Owner};
 use crate::ty::TyCtxt;
 use rustc_ast as ast;
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -22,9 +20,6 @@
 use rustc_target::spec::abi::Abi;
 use std::collections::VecDeque;
 
-pub mod blocks;
-mod collector;
-
 fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> {
     match node {
         Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
@@ -166,8 +161,8 @@ pub fn root_module(&self) -> &'hir Mod<'hir> {
 
     pub fn items(&self) -> impl Iterator<Item = &'hir Item<'hir>> + 'hir {
         let krate = self.krate();
-        krate.owners.iter().filter_map(|owner| match owner.as_ref()? {
-            OwnerNode::Item(item) => Some(*item),
+        krate.owners.iter().filter_map(|owner| match owner.as_ref()?.node() {
+            OwnerNode::Item(item) => Some(item),
             _ => None,
         })
     }
@@ -318,7 +313,7 @@ pub fn find_parent_node(&self, id: HirId) -> Option<HirId> {
     }
 
     pub fn get_parent_node(&self, hir_id: HirId) -> HirId {
-        self.find_parent_node(hir_id).unwrap_or(CRATE_HIR_ID)
+        self.find_parent_node(hir_id).unwrap()
     }
 
     /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
@@ -381,7 +376,7 @@ pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
     }
 
     pub fn body(&self, id: BodyId) -> &'hir Body<'hir> {
-        self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies.get(&id.hir_id.local_id).unwrap()
+        self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[&id.hir_id.local_id]
     }
 
     pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
@@ -443,7 +438,7 @@ pub fn body_owned_by(&self, id: HirId) -> BodyId {
     pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
         self.body(id).params.iter().map(|arg| match arg.pat.kind {
             PatKind::Binding(_, _, ident, _) => ident,
-            _ => Ident::new(kw::Empty, rustc_span::DUMMY_SP),
+            _ => Ident::empty(),
         })
     }
 
@@ -495,11 +490,35 @@ pub fn body_const_context(&self, did: LocalDefId) -> Option<ConstContext> {
     /// crate. If you would prefer to iterate over the bodies
     /// themselves, you can do `self.hir().krate().body_ids.iter()`.
     pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir {
-        self.krate().bodies.keys().map(move |&body_id| self.body_owner_def_id(body_id))
+        self.krate()
+            .owners
+            .iter_enumerated()
+            .flat_map(move |(owner, owner_info)| {
+                let bodies = &owner_info.as_ref()?.nodes.bodies;
+                Some(bodies.iter().map(move |&(local_id, _)| {
+                    let hir_id = HirId { owner, local_id };
+                    let body_id = BodyId { hir_id };
+                    self.body_owner_def_id(body_id)
+                }))
+            })
+            .flatten()
     }
 
     pub fn par_body_owners<F: Fn(LocalDefId) + Sync + Send>(self, f: F) {
-        par_for_each_in(&self.krate().bodies, |(&body_id, _)| f(self.body_owner_def_id(body_id)));
+        use rustc_data_structures::sync::{par_iter, ParallelIterator};
+        #[cfg(parallel_compiler)]
+        use rustc_rayon::iter::IndexedParallelIterator;
+
+        par_iter(&self.krate().owners.raw).enumerate().for_each(|(owner, owner_info)| {
+            let owner = LocalDefId::new(owner);
+            if let Some(owner_info) = owner_info {
+                par_iter(owner_info.nodes.bodies.range(..)).for_each(|(local_id, _)| {
+                    let hir_id = HirId { owner, local_id: *local_id };
+                    let body_id = BodyId { hir_id };
+                    f(self.body_owner_def_id(body_id))
+                })
+            }
+        });
     }
 
     pub fn ty_param_owner(&self, id: HirId) -> HirId {
@@ -551,9 +570,14 @@ pub fn walk_toplevel_module(self, visitor: &mut impl Visitor<'hir>) {
     /// Walks the attributes in a crate.
     pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) {
         let krate = self.krate();
-        for (&id, attrs) in krate.attrs.iter() {
-            for a in *attrs {
-                visitor.visit_attribute(id, a)
+        for (owner, info) in krate.owners.iter_enumerated() {
+            if let Some(info) = info {
+                for (local_id, attrs) in info.attrs.map.iter() {
+                    let id = HirId { owner, local_id: *local_id };
+                    for a in *attrs {
+                        visitor.visit_attribute(id, a)
+                    }
+                }
             }
         }
     }
@@ -572,7 +596,7 @@ pub fn visit_all_item_likes<V>(&self, visitor: &mut V)
     {
         let krate = self.krate();
         for owner in krate.owners.iter().filter_map(Option::as_ref) {
-            match owner {
+            match owner.node() {
                 OwnerNode::Item(item) => visitor.visit_item(item),
                 OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
                 OwnerNode::ImplItem(item) => visitor.visit_impl_item(item),
@@ -588,7 +612,7 @@ pub fn par_visit_all_item_likes<V>(&self, visitor: &V)
         V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send,
     {
         let krate = self.krate();
-        par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref() {
+        par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref().map(OwnerInfo::node) {
             Some(OwnerNode::Item(item)) => visitor.visit_item(item),
             Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item),
             Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item),
@@ -839,21 +863,21 @@ pub fn get_foreign_abi(&self, hir_id: HirId) -> Abi {
 
     pub fn expect_item(&self, id: HirId) -> &'hir Item<'hir> {
         match self.tcx.hir_owner(id.expect_owner()) {
-            Some(Owner { node: OwnerNode::Item(item) }) => item,
+            Some(Owner { node: OwnerNode::Item(item), .. }) => item,
             _ => bug!("expected item, found {}", self.node_to_string(id)),
         }
     }
 
     pub fn expect_impl_item(&self, id: HirId) -> &'hir ImplItem<'hir> {
         match self.tcx.hir_owner(id.expect_owner()) {
-            Some(Owner { node: OwnerNode::ImplItem(item) }) => item,
+            Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item,
             _ => bug!("expected impl item, found {}", self.node_to_string(id)),
         }
     }
 
     pub fn expect_trait_item(&self, id: HirId) -> &'hir TraitItem<'hir> {
         match self.tcx.hir_owner(id.expect_owner()) {
-            Some(Owner { node: OwnerNode::TraitItem(item) }) => item,
+            Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item,
             _ => bug!("expected trait item, found {}", self.node_to_string(id)),
         }
     }
@@ -867,7 +891,7 @@ pub fn expect_variant(&self, id: HirId) -> &'hir Variant<'hir> {
 
     pub fn expect_foreign_item(&self, id: HirId) -> &'hir ForeignItem<'hir> {
         match self.tcx.hir_owner(id.expect_owner()) {
-            Some(Owner { node: OwnerNode::ForeignItem(item) }) => item,
+            Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item,
             _ => bug!("expected foreign item, found {}", self.node_to_string(id)),
         }
     }
@@ -1032,42 +1056,10 @@ fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
     }
 }
 
-pub(super) fn index_hir<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx IndexedHir<'tcx> {
-    let _prof_timer = tcx.sess.prof.generic_activity("build_hir_map");
-
-    // We can access untracked state since we are an eval_always query.
-    let hcx = tcx.create_stable_hashing_context();
-    let mut collector = NodeCollector::root(
-        tcx.sess,
-        &**tcx.arena,
-        tcx.untracked_crate,
-        &tcx.untracked_resolutions.definitions,
-        hcx,
-    );
-    let top_mod = tcx.untracked_crate.module();
-    collector.visit_mod(top_mod, top_mod.inner, CRATE_HIR_ID);
-
-    let map = collector.finalize_and_compute_crate_hash();
-    tcx.arena.alloc(map)
-}
-
 pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
-    assert_eq!(crate_num, LOCAL_CRATE);
-
-    // We can access untracked state since we are an eval_always query.
-    let mut hcx = tcx.create_stable_hashing_context();
-
-    let mut hir_body_nodes: Vec<_> = tcx
-        .index_hir(())
-        .map
-        .iter_enumerated()
-        .filter_map(|(def_id, hod)| {
-            let def_path_hash = tcx.untracked_resolutions.definitions.def_path_hash(def_id);
-            let hash = hod.as_ref()?.hash;
-            Some((def_path_hash, hash, def_id))
-        })
-        .collect();
-    hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
+    debug_assert_eq!(crate_num, LOCAL_CRATE);
+    let krate = tcx.hir_crate(());
+    let hir_body_hash = krate.hir_hash;
 
     let upstream_crates = upstream_crates(tcx);
 
@@ -1087,20 +1079,27 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
 
     source_file_names.sort_unstable();
 
+    let mut hcx = tcx.create_stable_hashing_context();
     let mut stable_hasher = StableHasher::new();
-    for (def_path_hash, fingerprint, def_id) in hir_body_nodes.iter() {
-        def_path_hash.0.hash_stable(&mut hcx, &mut stable_hasher);
-        fingerprint.hash_stable(&mut hcx, &mut stable_hasher);
-        AttributeMap { map: &tcx.untracked_crate.attrs, prefix: *def_id }
-            .hash_stable(&mut hcx, &mut stable_hasher);
-        if tcx.sess.opts.debugging_opts.incremental_relative_spans {
-            let span = tcx.untracked_resolutions.definitions.def_span(*def_id);
-            debug_assert_eq!(span.parent(), None);
-            span.hash_stable(&mut hcx, &mut stable_hasher);
-        }
-    }
+    hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
     upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
     source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
+    if tcx.sess.opts.debugging_opts.incremental_relative_spans {
+        let definitions = &tcx.untracked_resolutions.definitions;
+        let mut owner_spans: Vec<_> = krate
+            .owners
+            .iter_enumerated()
+            .filter_map(|(def_id, info)| {
+                let _ = info.as_ref()?;
+                let def_path_hash = definitions.def_path_hash(def_id);
+                let span = definitions.def_span(def_id);
+                debug_assert_eq!(span.parent(), None);
+                Some((def_path_hash, span))
+            })
+            .collect();
+        owner_spans.sort_unstable_by_key(|bn| bn.0);
+        owner_spans.hash_stable(&mut hcx, &mut stable_hasher);
+    }
     tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
     tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher);
 
index 5016c5ce95432b34cdf2db7a2c88554b4c985209..95d7273b17b446372976332c2a846aaf066e60f8 100644 (file)
@@ -8,28 +8,12 @@
 
 use crate::ty::query::Providers;
 use crate::ty::TyCtxt;
-use rustc_ast::Attribute;
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::*;
-use rustc_index::vec::{Idx, IndexVec};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_span::DUMMY_SP;
-use std::collections::BTreeMap;
-
-/// Result of HIR indexing.
-#[derive(Debug)]
-pub struct IndexedHir<'hir> {
-    /// Contents of the HIR owned by each definition. None for definitions that are not HIR owners.
-    // The `mut` comes from construction time, and is harmless since we only ever hand out
-    // immutable refs to IndexedHir.
-    map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
-    /// Map from each owner to its parent's HirId inside another owner.
-    // This map is separate from `map` to eventually allow for per-owner indexing.
-    parenting: FxHashMap<LocalDefId, HirId>,
-}
 
 /// Top-level HIR node for current owner. This only contains the node for which
 /// `HirId::local_id == 0`, and excludes bodies.
@@ -39,85 +23,14 @@ pub struct IndexedHir<'hir> {
 #[derive(Copy, Clone, Debug)]
 pub struct Owner<'tcx> {
     node: OwnerNode<'tcx>,
+    hash_without_bodies: Fingerprint,
 }
 
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
+    #[inline]
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let Owner { node } = self;
-        hcx.while_hashing_hir_bodies(false, |hcx| node.hash_stable(hcx, hasher));
-    }
-}
-
-/// HIR node coupled with its parent's id in the same HIR owner.
-///
-/// The parent is trash when the node is a HIR owner.
-#[derive(Clone, Debug)]
-pub struct ParentedNode<'tcx> {
-    parent: ItemLocalId,
-    node: Node<'tcx>,
-}
-
-#[derive(Debug)]
-pub struct OwnerNodes<'tcx> {
-    /// Pre-computed hash of the full HIR.
-    hash: Fingerprint,
-    /// Full HIR for the current owner.
-    // The zeroth node's parent is trash, but is never accessed.
-    nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
-    /// Content of local bodies.
-    bodies: FxHashMap<ItemLocalId, &'tcx Body<'tcx>>,
-}
-
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OwnerNodes<'tcx> {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        // We ignore the `nodes` and `bodies` fields since these refer to information included in
-        // `hash` which is hashed in the collector and used for the crate hash.
-        let OwnerNodes { hash, nodes: _, bodies: _ } = *self;
-        hash.hash_stable(hcx, hasher);
-    }
-}
-
-/// Attributes owner by a HIR owner. It is build as a slice inside the attributes map, restricted
-/// to the nodes whose `HirId::owner` is `prefix`.
-#[derive(Copy, Clone)]
-pub struct AttributeMap<'tcx> {
-    map: &'tcx BTreeMap<HirId, &'tcx [Attribute]>,
-    prefix: LocalDefId,
-}
-
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for AttributeMap<'tcx> {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let range = self.range();
-
-        range.clone().count().hash_stable(hcx, hasher);
-        for (key, value) in range {
-            key.hash_stable(hcx, hasher);
-            value.hash_stable(hcx, hasher);
-        }
-    }
-}
-
-impl<'tcx> std::fmt::Debug for AttributeMap<'tcx> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("AttributeMap")
-            .field("prefix", &self.prefix)
-            .field("range", &&self.range().collect::<Vec<_>>()[..])
-            .finish()
-    }
-}
-
-impl<'tcx> AttributeMap<'tcx> {
-    fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] {
-        self.map.get(&HirId { owner: self.prefix, local_id: id }).copied().unwrap_or(&[])
-    }
-
-    fn range(&self) -> std::collections::btree_map::Range<'_, rustc_hir::HirId, &[Attribute]> {
-        let local_zero = ItemLocalId::from_u32(0);
-        let range = HirId { owner: self.prefix, local_id: local_zero }..HirId {
-            owner: LocalDefId { local_def_index: self.prefix.local_def_index + 1 },
-            local_id: local_zero,
-        };
-        self.map.range(range)
+        let Owner { node: _, hash_without_bodies } = self;
+        hash_without_bodies.hash_stable(hcx, hasher)
     }
 }
 
@@ -149,21 +62,32 @@ pub fn provide(providers: &mut Providers) {
         hir.local_def_id(hir.get_module_parent_node(hir.local_def_id_to_hir_id(id)))
     };
     providers.hir_crate = |tcx, ()| tcx.untracked_crate;
-    providers.index_hir = map::index_hir;
     providers.crate_hash = map::crate_hash;
     providers.hir_module_items = map::hir_module_items;
     providers.hir_owner = |tcx, id| {
-        let owner = tcx.index_hir(()).map[id].as_ref()?;
-        let node = owner.nodes[ItemLocalId::new(0)].as_ref().unwrap().node;
-        let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode.
-        Some(Owner { node })
+        let owner = tcx.hir_crate(()).owners[id].as_ref()?;
+        let node = owner.node();
+        Some(Owner { node, hash_without_bodies: owner.nodes.hash_without_bodies })
     };
-    providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].as_deref();
+    providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|i| &i.nodes);
     providers.hir_owner_parent = |tcx, id| {
-        let index = tcx.index_hir(());
-        index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID)
+        // Accessing the def_key is ok since its value is hashed as part of `id`'s DefPathHash.
+        let parent = tcx.untracked_resolutions.definitions.def_key(id).parent;
+        let parent = parent.map_or(CRATE_HIR_ID, |local_def_index| {
+            let def_id = LocalDefId { local_def_index };
+            let mut parent_hir_id =
+                tcx.untracked_resolutions.definitions.local_def_id_to_hir_id(def_id);
+            if let Some(local_id) =
+                tcx.hir_crate(()).owners[parent_hir_id.owner].as_ref().unwrap().parenting.get(&id)
+            {
+                parent_hir_id.local_id = *local_id;
+            }
+            parent_hir_id
+        });
+        parent
     };
-    providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id };
+    providers.hir_attrs =
+        |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map_or(AttributeMap::EMPTY, |o| &o.attrs);
     providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id);
     providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
     providers.fn_arg_names = |tcx, id| {
index e41f5add457fb2782fa9536781d1c2b7e853fb69..0894b80507581458cb006426ed59e7b33158347e 100644 (file)
@@ -39,6 +39,7 @@
 #![feature(new_uninit)]
 #![feature(nll)]
 #![feature(once_cell)]
+#![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(trusted_len)]
 #![feature(in_band_lifetimes)]
index b6358f9929448cc22b1baa98ec7123d2da0f6617..a36c9b6ed7304ba6fae8b627e84aa04c1561422b 100644 (file)
@@ -1004,13 +1004,13 @@ fn is_init(&self, range: AllocRange) -> Result<(), Range<Size>> {
     /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes`
     /// error which will report the first range of bytes which is uninitialized.
     fn check_init(&self, range: AllocRange) -> AllocResult {
-        self.is_init(range).or_else(|idx_range| {
-            Err(AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
+        self.is_init(range).map_err(|idx_range| {
+            AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
                 access_offset: range.start,
                 access_size: range.size,
                 uninit_offset: idx_range.start,
                 uninit_size: idx_range.end - idx_range.start, // `Size` subtraction
-            })))
+            }))
         })
     }
 
index 67a20d72905f927aab6c4551b40ee1937e895c3d..06b42320049f015267c1cd030242d60407eec94f 100644 (file)
@@ -47,6 +47,14 @@ pub enum MonoItem<'tcx> {
 }
 
 impl<'tcx> MonoItem<'tcx> {
+    /// Returns `true` if the mono item is user-defined (i.e. not compiler-generated, like shims).
+    pub fn is_user_defined(&self) -> bool {
+        match *self {
+            MonoItem::Fn(instance) => matches!(instance.def, InstanceDef::Item(..)),
+            MonoItem::Static(..) | MonoItem::GlobalAsm(..) => true,
+        }
+    }
+
     pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize {
         match *self {
             MonoItem::Fn(instance) => {
index db98cb763430f4dc62a0e9f4246192a1ffc2dc88..8e363cfbff562d594d9850dfa52c0a6ed2ed553e 100644 (file)
@@ -71,6 +71,7 @@ pub enum PassWhere {
 ///   or `typeck` appears in the name.
 /// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name
 ///   or `typeck` and `bar` both appear in the name.
+#[inline]
 pub fn dump_mir<'tcx, F>(
     tcx: TyCtxt<'tcx>,
     pass_num: Option<&dyn Display>,
index d5541d7890c77de20e6906d5ee913dc8c02aa804..cb3f3850958ec90d85d9e4d1e0db2667fca32a93 100644 (file)
@@ -225,6 +225,7 @@ pub struct BorrowCheckResult<'tcx> {
 pub struct ConstQualifs {
     pub has_mut_interior: bool,
     pub needs_drop: bool,
+    pub needs_non_const_drop: bool,
     pub custom_eq: bool,
     pub error_occured: Option<ErrorReported>,
 }
index 42683dac426e3b1fdd5271658149c50ca42bd014..1260c691e7844cfb1fc1447c51d938114233f280 100644 (file)
@@ -632,11 +632,11 @@ fn tooltip<'tcx>(
     for statement in statements {
         let source_range = source_range_no_file(tcx, &statement.source_info.span);
         text.push(format!(
-            "\n{}{}: {}: {}",
+            "\n{}{}: {}: {:?}",
             TOOLTIP_INDENT,
             source_range,
             statement_kind_name(&statement),
-            format!("{:?}", statement)
+            statement
         ));
     }
     if let Some(term) = terminator {
index e3eda8483b692368784bffacf496addfa61ac172..06041bbb02d355537240c012aefb6835520036d4 100644 (file)
     /// prefer wrappers like `tcx.visit_all_items_in_krate()`.
     query hir_crate(key: ()) -> &'tcx Crate<'tcx> {
         eval_always
-        no_hash
         desc { "get the crate HIR" }
     }
 
-    /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`.
-    /// Avoid calling this query directly.
-    query index_hir(_: ()) -> &'tcx crate::hir::IndexedHir<'tcx> {
-        eval_always
-        no_hash
-        desc { "index HIR" }
-    }
-
     /// The items in a module.
     ///
     /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`.
@@ -62,7 +53,6 @@
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
     query hir_owner(key: LocalDefId) -> Option<crate::hir::Owner<'tcx>> {
-        eval_always
         desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
@@ -71,7 +61,6 @@
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
     query hir_owner_parent(key: LocalDefId) -> hir::HirId {
-        eval_always
         desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
@@ -79,8 +68,7 @@
     ///
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
-    query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> {
-        eval_always
+    query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> {
         desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
@@ -88,8 +76,7 @@
     ///
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
-    query hir_attrs(key: LocalDefId) -> rustc_middle::hir::AttributeMap<'tcx> {
-        eval_always
+    query hir_attrs(key: LocalDefId) -> &'tcx hir::AttributeMap<'tcx> {
         desc { |tcx| "HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
     /// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
     query const_param_default(param: DefId) -> &'tcx ty::Const<'tcx> {
         desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param)  }
+        separate_provide_extern
     }
 
     query default_anon_const_substs(key: DefId) -> SubstsRef<'tcx> {
             path = tcx.def_path_str(key),
         }
         cache_on_disk_if { key.is_local() }
+        separate_provide_extern
     }
 
     query analysis(key: ()) -> Result<(), ErrorReported> {
         desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) }
         storage(ArenaCacheSelector<'tcx>)
         cache_on_disk_if { key.is_local() }
+        separate_provide_extern
     }
 
     /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
     /// Bounds from the parent (e.g. with nested impl trait) are not included.
     query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
         desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
     }
 
     /// Elaborated version of the predicates from `explicit_item_bounds`.
 
     query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
         desc { "looking up the native libraries of a linked crate" }
+        separate_provide_extern
     }
 
     query lint_levels(_: ()) -> LintLevelMap {
         // This query reads from untracked data in definitions.
         eval_always
         desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
     }
 
     query is_panic_runtime(_: CrateNum) -> bool {
         fatal_cycle
         desc { "checking if the crate is_panic_runtime" }
+        separate_provide_extern
     }
 
     /// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
     query mir_const_qualif(key: DefId) -> mir::ConstQualifs {
         desc { |tcx| "const checking `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
+        separate_provide_extern
     }
     query mir_const_qualif_const_arg(
         key: (LocalDefId, DefId)
         desc {
             |tcx| "building an abstract representation for {}", tcx.def_path_str(key),
         }
+        separate_provide_extern
     }
     /// Try to build an abstract representation of the given constant.
     query thir_abstract_const_of_const_arg(
     ) -> &'tcx mir::Body<'tcx> {
         desc { |tcx| "caching mir of `{}` for CTFE", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
+        separate_provide_extern
     }
 
     query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
     query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> {
         desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
+        separate_provide_extern
     }
 
     /// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
     query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
         desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
+        separate_provide_extern
     }
     query promoted_mir_of_const_arg(
         key: (LocalDefId, DefId)
     /// Returns the predicates written explicitly by the user.
     query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
         desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
     }
 
     /// Returns the inferred outlives predicates (e.g., for `struct
     /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
     query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
         desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
     }
 
     /// Maps from the `DefId` of a trait to the list of
     /// additional acyclicity requirements).
     query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
         desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
     }
 
     /// The `Option<Ident>` is the name of an associated type. If it is `None`, then this query
     query trait_def(key: DefId) -> ty::TraitDef {
         desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) }
         storage(ArenaCacheSelector<'tcx>)
+        separate_provide_extern
     }
     query adt_def(key: DefId) -> &'tcx ty::AdtDef {
         desc { |tcx| "computing ADT definition for `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
     }
     query adt_destructor(key: DefId) -> Option<ty::Destructor> {
         desc { |tcx| "computing `Drop` impl for `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
     }
 
     // The cycle error here should be reported as an error by `check_representable`.
     /// `is_const_fn` function.
     query is_const_fn_raw(key: DefId) -> bool {
         desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
     }
 
     query asyncness(key: DefId) -> hir::IsAsync {
         desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
     }
 
     /// Returns `true` if calls to the function may be promoted.
     /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
     query is_foreign_item(key: DefId) -> bool {
         desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) }
+        separate_provide_extern
     }
 
     /// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item.
     query static_mutability(def_id: DefId) -> Option<hir::Mutability> {
         desc { |tcx| "looking up static mutability of `{}`", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
 
     /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator.
     query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> {
         desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
 
     /// Gets a map with the variance of every item; use `item_variance` instead.
     /// Maps from the `DefId` of a type or region parameter to its (inferred) variance.
     query variances_of(def_id: DefId) -> &'tcx [ty::Variance] {
         desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
 
     /// Maps from thee `DefId` of a type to its (inferred) outlives.
     /// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items.
     query associated_item_def_ids(key: DefId) -> &'tcx [DefId] {
         desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
     }
 
     /// Maps from a trait item to the trait item "descriptor".
     query associated_item(key: DefId) -> ty::AssocItem {
         desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) }
         storage(ArenaCacheSelector<'tcx>)
+        separate_provide_extern
     }
 
     /// Collects the associated items defined on a trait or impl.
     /// Return `None` if this is an inherent impl.
     query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
         desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
+        separate_provide_extern
     }
     query impl_polarity(impl_id: DefId) -> ty::ImplPolarity {
         desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) }
+        separate_provide_extern
     }
 
     query issue33140_self_ty(key: DefId) -> Option<ty::Ty<'tcx>> {
     query inherent_impls(key: DefId) -> &'tcx [DefId] {
         desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) }
         eval_always
+        separate_provide_extern
     }
 
     /// The result of unsafety-checking this `LocalDefId`.
         desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
-    /// The signature of functions.
+    /// Computes the signature of the function.
     query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> {
         desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
     }
 
+    /// Performs lint checking for the module.
     query lint_mod(key: LocalDefId) -> () {
         desc { |tcx| "linting {}", describe_as_module(key, tcx) }
     }
         desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) }
     }
 
+    /// Checks for uses of unstable APIs in the module.
     query check_mod_unstable_api_usage(key: LocalDefId) -> () {
         desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) }
     }
     }
 
     /// Caches `CoerceUnsized` kinds for impls on custom types.
-    query coerce_unsized_info(key: DefId)
-        -> ty::adjustment::CoerceUnsizedInfo {
-            desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
-        }
+    query coerce_unsized_info(key: DefId) -> ty::adjustment::CoerceUnsizedInfo {
+        desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
+    }
 
     query typeck_item_bodies(_: ()) -> () {
         desc { "type-checking all item bodies" }
     /// additional requirements that the closure's creator must verify.
     query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
         desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
-        cache_on_disk_if(tcx, opt_result) {
-            tcx.is_closure(key.to_def_id())
-                || opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty())
-        }
+        cache_on_disk_if(tcx) { tcx.is_closure(key.to_def_id()) }
     }
     query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
         desc {
         desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) }
     }
 
+    /// Generates a MIR body for the shim.
     query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> {
         storage(ArenaCacheSelector<'tcx>)
         desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
 
     query opt_def_kind(def_id: DefId) -> Option<DefKind> {
         desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
 
+    /// Gets the span for the definition.
     query def_span(def_id: DefId) -> Span {
         desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) }
-        // FIXME(mw): DefSpans are not really inputs since they are derived from
-        // HIR. But at the moment HIR hashing still contains some hacks that allow
-        // to make type debuginfo to be source location independent. Declaring
-        // DefSpan an input makes sure that changes to these are always detected
-        // regardless of HIR hashing.
-        eval_always
+        separate_provide_extern
     }
 
+    /// Gets the span for the identifier of the definition.
     query def_ident_span(def_id: DefId) -> Option<Span> {
         desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
 
     query lookup_stability(def_id: DefId) -> Option<&'tcx attr::Stability> {
         desc { |tcx| "looking up stability of `{}`", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
 
     query lookup_const_stability(def_id: DefId) -> Option<&'tcx attr::ConstStability> {
         desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
 
     query should_inherit_track_caller(def_id: DefId) -> bool {
 
     query lookup_deprecation_entry(def_id: DefId) -> Option<DeprecationEntry> {
         desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
 
     query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] {
         desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
 
     query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs {
 
     query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
         desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
     /// Gets the rendered value of the specified constant or associated constant.
     /// Used by rustdoc.
     query rendered_const(def_id: DefId) -> String {
         desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
     query impl_parent(def_id: DefId) -> Option<DefId> {
         desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
 
     /// Given an `associated_item`, find the trait it belongs to.
     /// Return `None` if the `DefId` is not an associated item.
     query trait_of_item(associated_item: DefId) -> Option<DefId> {
         desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) }
+        separate_provide_extern
     }
 
     query is_ctfe_mir_available(key: DefId) -> bool {
         desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
     }
     query is_mir_available(key: DefId) -> bool {
         desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
     }
 
     query own_existential_vtable_entries(
     query dylib_dependency_formats(_: CrateNum)
                                     -> &'tcx [(CrateNum, LinkagePreference)] {
         desc { "dylib dependency formats of crate" }
+        separate_provide_extern
     }
 
     query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> {
     query is_compiler_builtins(_: CrateNum) -> bool {
         fatal_cycle
         desc { "checking if the crate is_compiler_builtins" }
+        separate_provide_extern
     }
     query has_global_allocator(_: CrateNum) -> bool {
         // This query depends on untracked global state in CStore
         eval_always
         fatal_cycle
         desc { "checking if the crate has_global_allocator" }
+        separate_provide_extern
     }
     query has_panic_handler(_: CrateNum) -> bool {
         fatal_cycle
         desc { "checking if the crate has_panic_handler" }
+        separate_provide_extern
     }
     query is_profiler_runtime(_: CrateNum) -> bool {
         fatal_cycle
         desc { "query a crate is `#![profiler_runtime]`" }
+        separate_provide_extern
     }
     query panic_strategy(_: CrateNum) -> PanicStrategy {
         fatal_cycle
         desc { "query a crate's configured panic strategy" }
+        separate_provide_extern
     }
     query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy {
         fatal_cycle
         desc { "query a crate's configured panic-in-drop strategy" }
+        separate_provide_extern
     }
     query is_no_builtins(_: CrateNum) -> bool {
         fatal_cycle
         desc { "test whether a crate has `#![no_builtins]`" }
+        separate_provide_extern
     }
     query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion {
         fatal_cycle
         desc { "query a crate's symbol mangling version" }
+        separate_provide_extern
     }
 
     query extern_crate(def_id: DefId) -> Option<&'tcx ExternCrate> {
         eval_always
         desc { "getting crate's ExternCrateData" }
+        separate_provide_extern
     }
 
     query specializes(_: (DefId, DefId)) -> bool {
 
     query impl_defaultness(def_id: DefId) -> hir::Defaultness {
         desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
 
     query impl_constness(def_id: DefId) -> hir::Constness {
         desc { |tcx| "looking up whether `{}` is a const impl", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
 
     query check_item_well_formed(key: LocalDefId) -> () {
         -> DefIdMap<SymbolExportLevel> {
         storage(ArenaCacheSelector<'tcx>)
         desc { "looking up the exported symbols of a crate" }
+        separate_provide_extern
     }
     query is_reachable_non_generic(def_id: DefId) -> bool {
         desc { |tcx| "checking whether `{}` is an exported symbol", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
     query is_unreachable_local_definition(def_id: LocalDefId) -> bool {
         desc { |tcx|
                 "collecting available upstream monomorphizations for `{}`",
                 tcx.def_path_str(def_id),
             }
+            separate_provide_extern
         }
 
     /// Returns the upstream crate that exports drop-glue for the given
 
     query foreign_modules(_: CrateNum) -> Lrc<FxHashMap<DefId, ForeignModule>> {
         desc { "looking up the foreign modules of a linked crate" }
+        separate_provide_extern
     }
 
     /// Identifies the entry-point (e.g., the `main` function) for a given
     query crate_hash(_: CrateNum) -> Svh {
         eval_always
         desc { "looking up the hash a crate" }
+        separate_provide_extern
     }
     query crate_host_hash(_: CrateNum) -> Option<Svh> {
         eval_always
         desc { "looking up the hash of a host version of a crate" }
+        separate_provide_extern
     }
     query extra_filename(_: CrateNum) -> String {
         eval_always
         desc { "looking up the extra filename for a crate" }
+        separate_provide_extern
     }
     query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> {
         eval_always
         desc { "looking up the paths for extern crates" }
+        separate_provide_extern
     }
 
     /// Given a crate and a trait, look up all impls of that trait in the crate.
     query implementations_of_trait(_: (CrateNum, DefId))
         -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
         desc { "looking up implementations of a trait in a crate" }
+        separate_provide_extern
     }
 
     /// Given a crate, look up all trait impls in that crate.
     query all_trait_implementations(_: CrateNum)
         -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
         desc { "looking up all (?) trait implementations" }
+        separate_provide_extern
     }
 
     query is_dllimport_foreign_item(def_id: DefId) -> bool {
 
     query visibility(def_id: DefId) -> ty::Visibility {
         desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
 
     /// Computes the set of modules from which this type is visibly uninhabited.
     query dep_kind(_: CrateNum) -> CrateDepKind {
         eval_always
         desc { "fetching what a dependency looks like" }
+        separate_provide_extern
     }
+
+    /// Gets the name of the crate.
     query crate_name(_: CrateNum) -> Symbol {
         eval_always
         desc { "fetching what a crate is named" }
+        separate_provide_extern
     }
     query item_children(def_id: DefId) -> &'tcx [Export] {
         desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) }
+        separate_provide_extern
     }
     query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
         desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
     query defined_lib_features(_: CrateNum)
         -> &'tcx [(Symbol, Option<Symbol>)] {
         desc { "calculating the lib features defined in a crate" }
+        separate_provide_extern
     }
     /// Returns the lang items defined in another crate by loading it from metadata.
     query get_lang_items(_: ()) -> LanguageItems {
     /// Returns the lang items defined in another crate by loading it from metadata.
     query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] {
         desc { "calculating the lang items defined in a crate" }
+        separate_provide_extern
     }
 
     /// Returns the diagnostic items defined in a crate.
     query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems {
         storage(ArenaCacheSelector<'tcx>)
         desc { "calculating the diagnostic items map in a crate" }
+        separate_provide_extern
     }
 
     query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] {
         desc { "calculating the missing lang items in a crate" }
+        separate_provide_extern
     }
     query visible_parent_map(_: ()) -> DefIdMap<DefId> {
         storage(ArenaCacheSelector<'tcx>)
     query missing_extern_crate_item(_: CrateNum) -> bool {
         eval_always
         desc { "seeing if we're missing an `extern crate` item for this crate" }
+        separate_provide_extern
     }
     query used_crate_source(_: CrateNum) -> Lrc<CrateSource> {
         eval_always
         desc { "looking at the source for a crate" }
+        separate_provide_extern
     }
     query postorder_cnums(_: ()) -> &'tcx [CrateNum] {
         eval_always
     query is_private_dep(c: CrateNum) -> bool {
         eval_always
         desc { "check whether crate {} is a private dependency", c }
+        separate_provide_extern
     }
     query allocator_kind(_: ()) -> Option<AllocatorKind> {
         eval_always
     query exported_symbols(_: CrateNum)
         -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
         desc { "exported_symbols" }
+        separate_provide_extern
     }
 
     query collect_and_partition_mono_items(_: ()) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) {
     query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
         desc { "codegen_unit" }
     }
-    query unused_generic_params(key: DefId) -> FiniteBitSet<u32> {
-        cache_on_disk_if { key.is_local() }
+    query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet<u32> {
+        cache_on_disk_if { key.def_id().is_local() }
         desc {
             |tcx| "determining which generic parameters are unused by `{}`",
-                tcx.def_path_str(key)
+                tcx.def_path_str(key.def_id())
         }
+        separate_provide_extern
     }
     query backend_optimization_level(_: ()) -> OptLevel {
         desc { "optimization level used by backend" }
index b089ae22d6d9855de6004fa256e91bc86410b3c3..6570d8e15679da6143c74ec0324fe8095f885e6e 100644 (file)
@@ -440,16 +440,28 @@ pub struct DerivedObligationCause<'tcx> {
 
 #[derive(Clone, Debug, TypeFoldable, Lift)]
 pub enum SelectionError<'tcx> {
+    /// The trait is not implemented.
     Unimplemented,
+    /// After a closure impl has selected, its "outputs" were evaluated
+    /// (which for closures includes the "input" type params) and they
+    /// didn't resolve. See `confirm_poly_trait_refs` for more.
     OutputTypeParameterMismatch(
         ty::PolyTraitRef<'tcx>,
         ty::PolyTraitRef<'tcx>,
         ty::error::TypeError<'tcx>,
     ),
+    /// The trait pointed by `DefId` is not object safe.
     TraitNotObjectSafe(DefId),
+    /// A given constant couldn't be evaluated.
     NotConstEvaluatable(NotConstEvaluatable),
+    /// Exceeded the recursion depth during type projection.
     Overflow,
+    /// Signaling that an error has already been emitted, to avoid
+    /// multiple errors being shown.
     ErrorReporting,
+    /// Multiple applicable `impl`s where found. The `DefId`s correspond to
+    /// all the `impl`s' Items.
+    Ambiguous(Vec<DefId>),
 }
 
 /// When performing resolution, it is typically the case that there
index 6720493cd3cb19ba77400f82970fc08df7449cca..560660517f34b27ab7134b515951762b6e9c8133 100644 (file)
 use rustc_query_system::cache::Cache;
 
 pub type SelectionCache<'tcx> = Cache<
-    ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>,
+    (ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, ty::ImplPolarity),
     SelectionResult<'tcx, SelectionCandidate<'tcx>>,
 >;
 
-pub type EvaluationCache<'tcx> =
-    Cache<ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, EvaluationResult>;
+pub type EvaluationCache<'tcx> = Cache<
+    (ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, ty::ImplPolarity),
+    EvaluationResult,
+>;
 
 /// The selection process begins by considering all impls, where
 /// clauses, and so forth that might resolve an obligation. Sometimes
@@ -101,7 +103,7 @@ pub enum SelectionCandidate<'tcx> {
         /// `false` if there are no *further* obligations.
         has_nested: bool,
     },
-    ParamCandidate(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>),
+    ParamCandidate((ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ty::ImplPolarity)),
     ImplCandidate(DefId),
     AutoImplCandidate(DefId),
 
index 83d7c307bdfe9c7f0e29fdc439fe417634fc2cca..8240273acad4cd89eb1bcabfff4defc8dbf00cf7 100644 (file)
@@ -1,7 +1,7 @@
 //! Type context book-keeping.
 
 use crate::arena::Arena;
-use crate::dep_graph::DepGraph;
+use crate::dep_graph::{DepGraph, DepKind, DepKindStruct};
 use crate::hir::place::Place as HirPlace;
 use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
 use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
@@ -79,11 +79,6 @@ fn new_empty(source_map: &'tcx SourceMap) -> Self
     where
         Self: Sized;
 
-    /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
-    /// session, if it still exists. This is used during incremental compilation to
-    /// turn a deserialized `DefPathHash` into its current `DefId`.
-    fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, def_path_hash: DefPathHash) -> DefId;
-
     fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>);
 
     fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult;
@@ -1016,6 +1011,7 @@ pub struct GlobalCtxt<'tcx> {
 
     pub queries: &'tcx dyn query::QueryEngine<'tcx>,
     pub query_caches: query::QueryCaches<'tcx>,
+    query_kinds: &'tcx [DepKindStruct],
 
     // Internal caches for metadata decoding. No need to track deps on this.
     pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
@@ -1149,6 +1145,7 @@ pub fn create_global_ctxt(
         dep_graph: DepGraph,
         on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
         queries: &'tcx dyn query::QueryEngine<'tcx>,
+        query_kinds: &'tcx [DepKindStruct],
         crate_name: &str,
         output_filenames: OutputFilenames,
     ) -> GlobalCtxt<'tcx> {
@@ -1175,6 +1172,7 @@ pub fn create_global_ctxt(
             on_disk_cache,
             queries,
             query_caches: query::QueryCaches::default(),
+            query_kinds,
             ty_rcache: Default::default(),
             pred_rcache: Default::default(),
             selection_cache: Default::default(),
@@ -1188,6 +1186,10 @@ pub fn create_global_ctxt(
         }
     }
 
+    crate fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct {
+        &self.query_kinds[k as usize]
+    }
+
     /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
     #[track_caller]
     pub fn ty_error(self) -> Ty<'tcx> {
@@ -1301,6 +1303,27 @@ pub fn stable_crate_id_to_crate_num(self, stable_crate_id: StableCrateId) -> Cra
         }
     }
 
+    /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
+    /// session, if it still exists. This is used during incremental compilation to
+    /// turn a deserialized `DefPathHash` into its current `DefId`.
+    pub fn def_path_hash_to_def_id(self, hash: DefPathHash) -> DefId {
+        debug!("def_path_hash_to_def_id({:?})", hash);
+
+        let stable_crate_id = hash.stable_crate_id();
+
+        // If this is a DefPathHash from the local crate, we can look up the
+        // DefId in the tcx's `Definitions`.
+        if stable_crate_id == self.sess.local_stable_crate_id() {
+            self.untracked_resolutions.definitions.local_def_path_hash_to_def_id(hash).to_def_id()
+        } else {
+            // If this is a DefPathHash from an upstream crate, let the CrateStore map
+            // it to a DefId.
+            let cstore = &self.untracked_resolutions.cstore;
+            let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id);
+            cstore.def_path_hash_to_def_id(cnum, hash)
+        }
+    }
+
     pub fn def_path_debug_str(self, def_id: DefId) -> String {
         // We are explicitly not going through queries here in order to get
         // crate name and stable crate id since this code is called from debug!()
@@ -1337,20 +1360,15 @@ pub fn definitions_untracked(self) -> &'tcx hir::definitions::Definitions {
 
     #[inline(always)]
     pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> {
-        let krate = self.gcx.untracked_crate;
         let resolutions = &self.gcx.untracked_resolutions;
-
-        StableHashingContext::new(self.sess, krate, &resolutions.definitions, &*resolutions.cstore)
+        StableHashingContext::new(self.sess, &resolutions.definitions, &*resolutions.cstore)
     }
 
     #[inline(always)]
     pub fn create_no_span_stable_hashing_context(self) -> StableHashingContext<'tcx> {
-        let krate = self.gcx.untracked_crate;
         let resolutions = &self.gcx.untracked_resolutions;
-
         StableHashingContext::ignore_spans(
             self.sess,
-            krate,
             &resolutions.definitions,
             &*resolutions.cstore,
         )
@@ -2823,7 +2841,8 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
-    providers.in_scope_traits_map = |tcx, id| tcx.hir_crate(()).trait_map.get(&id);
+    providers.in_scope_traits_map =
+        |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|owner_info| &owner_info.trait_map);
     providers.resolutions = |tcx, ()| &tcx.untracked_resolutions;
     providers.module_exports = |tcx, id| tcx.resolutions(()).export_map.get(&id).map(|v| &v[..]);
     providers.crate_name = |tcx, id| {
index 092eae0fc5c236bbd3bb91ed99b767a7f2994a72..1b32c8a66989f7b8ded38db6a847e1170b292616 100644 (file)
@@ -221,9 +221,7 @@ pub fn suggest_constraining_type_param(
 ) -> bool {
     let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
 
-    let param = if let Some(param) = param {
-        param
-    } else {
+    let Some(param) = param else {
         return false;
     };
 
index 08b4d3aecda0ae358abcd76529f8497010ce8069..2bd9415171d7d5d2ac0af852205e531aa736a01c 100644 (file)
@@ -34,6 +34,7 @@ pub fn new(a_is_expected: bool, a: T, b: T) -> Self {
 pub enum TypeError<'tcx> {
     Mismatch,
     ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
+    PolarityMismatch(ExpectedFound<ty::ImplPolarity>),
     UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
     AbiMismatch(ExpectedFound<abi::Abi>),
     Mutability,
@@ -104,6 +105,9 @@ fn report_maybe_different(
             ConstnessMismatch(values) => {
                 write!(f, "expected {} bound, found {} bound", values.expected, values.found)
             }
+            PolarityMismatch(values) => {
+                write!(f, "expected {} polarity, found {} polarity", values.expected, values.found)
+            }
             UnsafetyMismatch(values) => {
                 write!(f, "expected {} fn, found {} fn", values.expected, values.found)
             }
@@ -212,10 +216,9 @@ pub fn must_include_note(&self) -> bool {
         use self::TypeError::*;
         match self {
             CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_)
-            | Mismatch | AbiMismatch(_) | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_)
-            | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_) | TargetFeatureCast(_) => {
-                false
-            }
+            | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
+            | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
+            | VariadicMismatch(_) | TargetFeatureCast(_) => false,
 
             Mutability
             | ArgumentMutability(_)
@@ -769,11 +772,16 @@ fn suggest_constraining_opaque_associated_type(
     ) -> bool {
         let assoc = self.associated_item(proj_ty.item_def_id);
         if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
-            let opaque_local_def_id = def_id.expect_local();
-            let opaque_hir_id = self.hir().local_def_id_to_hir_id(opaque_local_def_id);
-            let opaque_hir_ty = match &self.hir().expect_item(opaque_hir_id).kind {
-                hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
-                _ => bug!("The HirId comes from a `ty::Opaque`"),
+            let opaque_local_def_id = def_id.as_local();
+            let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
+                let hir = self.hir();
+                let opaque_hir_id = hir.local_def_id_to_hir_id(opaque_local_def_id);
+                match &hir.expect_item(opaque_hir_id).kind {
+                    hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
+                    _ => bug!("The HirId comes from a `ty::Opaque`"),
+                }
+            } else {
+                return false;
             };
 
             let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
index 9b8247fd0283e3d62c554e39bf918152357779b4..4b38105e44717e52300e5b6f9e789e58f8093d12 100644 (file)
@@ -152,6 +152,22 @@ pub fn def_id(self) -> DefId {
         }
     }
 
+    /// Returns the `DefId` of instances which might not require codegen locally.
+    pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> {
+        match self {
+            ty::InstanceDef::Item(def) => Some(def.did),
+            ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id),
+            InstanceDef::VtableShim(..)
+            | InstanceDef::ReifyShim(..)
+            | InstanceDef::FnPtrShim(..)
+            | InstanceDef::Virtual(..)
+            | InstanceDef::Intrinsic(..)
+            | InstanceDef::ClosureOnceShim { .. }
+            | InstanceDef::DropGlue(..)
+            | InstanceDef::CloneShim(..) => None,
+        }
+    }
+
     #[inline]
     pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> {
         match self {
@@ -567,29 +583,26 @@ pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self {
             return self;
         }
 
-        if let InstanceDef::Item(def) = self.def {
-            let polymorphized_substs = polymorphize(tcx, def.did, self.substs);
-            debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs);
-            Self { def: self.def, substs: polymorphized_substs }
-        } else {
-            self
-        }
+        let polymorphized_substs = polymorphize(tcx, self.def, self.substs);
+        debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs);
+        Self { def: self.def, substs: polymorphized_substs }
     }
 }
 
 fn polymorphize<'tcx>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
+    instance: ty::InstanceDef<'tcx>,
     substs: SubstsRef<'tcx>,
 ) -> SubstsRef<'tcx> {
-    debug!("polymorphize({:?}, {:?})", def_id, substs);
-    let unused = tcx.unused_generic_params(def_id);
+    debug!("polymorphize({:?}, {:?})", instance, substs);
+    let unused = tcx.unused_generic_params(instance);
     debug!("polymorphize: unused={:?}", unused);
 
     // If this is a closure or generator then we need to handle the case where another closure
     // from the function is captured as an upvar and hasn't been polymorphized. In this case,
     // the unpolymorphized upvar closure would result in a polymorphized closure producing
     // multiple mono items (and eventually symbol clashes).
+    let def_id = instance.def_id();
     let upvars_ty = if tcx.is_closure(def_id) {
         Some(substs.as_closure().tupled_upvars_ty())
     } else if tcx.type_of(def_id).is_generator() {
@@ -613,7 +626,11 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
             debug!("fold_ty: ty={:?}", ty);
             match ty.kind {
                 ty::Closure(def_id, substs) => {
-                    let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
+                    let polymorphized_substs = polymorphize(
+                        self.tcx,
+                        ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
+                        substs,
+                    );
                     if substs == polymorphized_substs {
                         ty
                     } else {
@@ -621,7 +638,11 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                     }
                 }
                 ty::Generator(def_id, substs, movability) => {
-                    let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
+                    let polymorphized_substs = polymorphize(
+                        self.tcx,
+                        ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
+                        substs,
+                    );
                     if substs == polymorphized_substs {
                         ty
                     } else {
index d0c7379c2d94d5aab856d8fb9ffbda0c6f795008..b87e23af72b702076ea2ea84f8d5b48bf87b6f43 100644 (file)
@@ -755,17 +755,14 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
                     }
 
                     // Extract the number of elements from the layout of the array field:
-                    let len = if let Ok(TyAndLayout {
+                    let Ok(TyAndLayout {
                         layout: Layout { fields: FieldsShape::Array { count, .. }, .. },
                         ..
-                    }) = self.layout_of(f0_ty)
-                    {
-                        count
-                    } else {
+                    }) = self.layout_of(f0_ty) else {
                         return Err(LayoutError::Unknown(ty));
                     };
 
-                    (*e_ty, *len, true)
+                    (*e_ty, *count, true)
                 } else {
                     // First ADT field is not an array:
                     (f0_ty, def.non_enum_variant().fields.len() as _, false)
@@ -787,9 +784,7 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
 
                 // Compute the ABI of the element type:
                 let e_ly = self.layout_of(e_ty)?;
-                let e_abi = if let Abi::Scalar(scalar) = e_ly.abi {
-                    scalar
-                } else {
+                let Abi::Scalar(e_abi) = e_ly.abi else {
                     // This error isn't caught in typeck, e.g., if
                     // the element type of the vector is generic.
                     tcx.sess.fatal(&format!(
@@ -3065,9 +3060,10 @@ fn fn_abi_new_uncached(
                     // LLVM's definition of `noalias` is based solely on memory
                     // dependencies rather than pointer equality
                     //
-                    // Due to miscompiles in LLVM < 12, we apply a separate NoAliasMutRef attribute
-                    // for UniqueBorrowed arguments, so that the codegen backend can decide
-                    // whether or not to actually emit the attribute.
+                    // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute
+                    // for UniqueBorrowed arguments, so that the codegen backend can decide whether
+                    // or not to actually emit the attribute. It can also be controlled with the
+                    // `-Zmutable-noalias` debugging option.
                     let no_alias = match kind {
                         PointerKind::Shared | PointerKind::UniqueBorrowed => false,
                         PointerKind::UniqueOwned => true,
index 20d07bdc48a622d171947fbfe2ed7f1b3e813748..cf47da157d19f7c969eb8e0e9724d06056f052f0 100644 (file)
@@ -164,7 +164,18 @@ pub struct ImplHeader<'tcx> {
     pub predicates: Vec<Predicate<'tcx>>,
 }
 
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(
+    Copy,
+    Clone,
+    PartialEq,
+    Eq,
+    Hash,
+    TyEncodable,
+    TyDecodable,
+    HashStable,
+    Debug,
+    TypeFoldable
+)]
 pub enum ImplPolarity {
     /// `impl Trait for Type`
     Positive,
@@ -177,6 +188,27 @@ pub enum ImplPolarity {
     Reservation,
 }
 
+impl ImplPolarity {
+    /// Flips polarity by turning `Positive` into `Negative` and `Negative` into `Positive`.
+    pub fn flip(&self) -> Option<ImplPolarity> {
+        match self {
+            ImplPolarity::Positive => Some(ImplPolarity::Negative),
+            ImplPolarity::Negative => Some(ImplPolarity::Positive),
+            ImplPolarity::Reservation => None,
+        }
+    }
+}
+
+impl fmt::Display for ImplPolarity {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Positive => f.write_str("positive"),
+            Self::Negative => f.write_str("negative"),
+            Self::Reservation => f.write_str("reservation"),
+        }
+    }
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)]
 pub enum Visibility {
     /// Visible everywhere (including in other crates).
@@ -459,6 +491,29 @@ impl<'tcx> Predicate<'tcx> {
     pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> {
         self.inner.kind
     }
+
+    /// Flips the polarity of a Predicate.
+    ///
+    /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
+    pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<Predicate<'tcx>> {
+        let kind = self
+            .inner
+            .kind
+            .map_bound(|kind| match kind {
+                PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) => {
+                    Some(PredicateKind::Trait(TraitPredicate {
+                        trait_ref,
+                        constness,
+                        polarity: polarity.flip()?,
+                    }))
+                }
+
+                _ => None,
+            })
+            .transpose()?;
+
+        Some(tcx.mk_predicate(kind))
+    }
 }
 
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
@@ -654,6 +709,8 @@ pub struct TraitPredicate<'tcx> {
     pub trait_ref: TraitRef<'tcx>,
 
     pub constness: BoundConstness,
+
+    pub polarity: ImplPolarity,
 }
 
 pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
@@ -788,7 +845,11 @@ impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         self.value
             .map_bound(|trait_ref| {
-                PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: self.constness })
+                PredicateKind::Trait(ty::TraitPredicate {
+                    trait_ref,
+                    constness: self.constness,
+                    polarity: ty::ImplPolarity::Positive,
+                })
             })
             .to_predicate(tcx)
     }
index 2610a76b2810bf9fca2cc3f395e0ac277cd81331..742005e245f9d160ed91387e209975e1f1ddf0da 100644 (file)
@@ -350,18 +350,26 @@ fn try_print_visible_def_path_recur(
             match self.tcx().extern_crate(def_id) {
                 Some(&ExternCrate { src, dependency_of, span, .. }) => match (src, dependency_of) {
                     (ExternCrateSource::Extern(def_id), LOCAL_CRATE) => {
-                        debug!("try_print_visible_def_path: def_id={:?}", def_id);
-                        return Ok((
-                            if !span.is_dummy() {
-                                self.print_def_path(def_id, &[])?
-                            } else {
-                                self.path_crate(cnum)?
-                            },
-                            true,
-                        ));
+                        // NOTE(eddyb) the only reason `span` might be dummy,
+                        // that we're aware of, is that it's the `std`/`core`
+                        // `extern crate` injected by default.
+                        // FIXME(eddyb) find something better to key this on,
+                        // or avoid ending up with `ExternCrateSource::Extern`,
+                        // for the injected `std`/`core`.
+                        if span.is_dummy() {
+                            return Ok((self.path_crate(cnum)?, true));
+                        }
+
+                        // Disable `try_print_trimmed_def_path` behavior within
+                        // the `print_def_path` call, to avoid infinite recursion
+                        // in cases where the `extern crate foo` has non-trivial
+                        // parents, e.g. it's nested in `impl foo::Trait for Bar`
+                        // (see also issues #55779 and #87932).
+                        self = with_no_visible_paths(|| self.print_def_path(def_id, &[]))?;
+
+                        return Ok((self, true));
                     }
                     (ExternCrateSource::Path, LOCAL_CRATE) => {
-                        debug!("try_print_visible_def_path: def_id={:?}", def_id);
                         return Ok((self.path_crate(cnum)?, true));
                     }
                     _ => {}
@@ -736,6 +744,7 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                     p!(print_def_path(did, substs));
                     if !substs.as_closure().is_valid() {
                         p!(" closure_substs=(unavailable)");
+                        p!(write(" substs={:?}", substs));
                     } else {
                         p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
                         p!(
index b1bc073ca99e4c84cd0607f8cd133ba686914ccd..34f806271979af7ec3bef7af3d4e99438fc6862b 100644 (file)
@@ -102,6 +102,10 @@ pub fn try_mark_green(self, dep_node: &dep_graph::DepNode) -> bool {
     }
 }
 
+/// Helper for `TyCtxtEnsure` to avoid a closure.
+#[inline(always)]
+fn noop<T>(_: &T) {}
+
 macro_rules! query_helper_param_ty {
     (DefId) => { impl IntoQueryParam<DefId> };
     ($K:ty) => { $K };
@@ -119,6 +123,39 @@ macro_rules! query_storage {
     };
 }
 
+macro_rules! separate_provide_extern_decl {
+    ([][$name:ident]) => {
+        ()
+    };
+    ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
+        for<'tcx> fn(
+            TyCtxt<'tcx>,
+            query_keys::$name<'tcx>,
+        ) -> query_values::$name<'tcx>
+    };
+    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+        separate_provide_extern_decl!([$($modifiers)*][$($args)*])
+    };
+}
+
+macro_rules! separate_provide_extern_default {
+    ([][$name:ident]) => {
+        ()
+    };
+    ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
+        |_, key| bug!(
+            "`tcx.{}({:?})` unsupported by its crate; \
+             perhaps the `{}` query was never assigned a provider function",
+            stringify!($name),
+            key,
+            stringify!($name),
+        )
+    };
+    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+        separate_provide_extern_default!([$($modifiers)*][$($args)*])
+    };
+}
+
 macro_rules! define_callbacks {
     (<$tcx:tt>
      $($(#[$attr:meta])*
@@ -165,7 +202,7 @@ impl TyCtxtEnsure<$tcx> {
             #[inline(always)]
             pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
                 let key = key.into_query_param();
-                let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, |_| {});
+                let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, noop);
 
                 let lookup = match cached {
                     Ok(()) => return,
@@ -192,9 +229,7 @@ impl TyCtxtAt<$tcx> {
             pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx>
             {
                 let key = key.into_query_param();
-                let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, |value| {
-                    value.clone()
-                });
+                let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, Clone::clone);
 
                 let lookup = match cached {
                     Ok(value) => return value,
@@ -212,6 +247,10 @@ pub struct Providers {
             ) -> query_values::$name<'tcx>,)*
         }
 
+        pub struct ExternProviders {
+            $(pub $name: separate_provide_extern_decl!([$($modifiers)*][$name]),)*
+        }
+
         impl Default for Providers {
             fn default() -> Self {
                 Providers {
@@ -226,11 +265,24 @@ fn default() -> Self {
             }
         }
 
+        impl Default for ExternProviders {
+            fn default() -> Self {
+                ExternProviders {
+                    $($name: separate_provide_extern_default!([$($modifiers)*][$name]),)*
+                }
+            }
+        }
+
         impl Copy for Providers {}
         impl Clone for Providers {
             fn clone(&self) -> Self { *self }
         }
 
+        impl Copy for ExternProviders {}
+        impl Clone for ExternProviders {
+            fn clone(&self) -> Self { *self }
+        }
+
         pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync {
             fn as_any(&'tcx self) -> &'tcx dyn std::any::Any;
 
index 2c786538014ff20421324e5927de8a613caaf4e0..8b20e1eec9a86e03ba2d3992530b195e385f4a59 100644 (file)
@@ -797,6 +797,20 @@ fn relate<R: TypeRelation<'tcx>>(
     }
 }
 
+impl<'tcx> Relate<'tcx> for ty::ImplPolarity {
+    fn relate<R: TypeRelation<'tcx>>(
+        relation: &mut R,
+        a: ty::ImplPolarity,
+        b: ty::ImplPolarity,
+    ) -> RelateResult<'tcx, ty::ImplPolarity> {
+        if a != b {
+            Err(TypeError::PolarityMismatch(expected_found(relation, a, b)))
+        } else {
+            Ok(a)
+        }
+    }
+}
+
 impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
@@ -806,6 +820,7 @@ fn relate<R: TypeRelation<'tcx>>(
         Ok(ty::TraitPredicate {
             trait_ref: relation.relate(a.trait_ref, b.trait_ref)?,
             constness: relation.relate(a.constness, b.constness)?,
+            polarity: relation.relate(a.polarity, b.polarity)?,
         })
     }
 }
index 8f343ba9fec22064b964c13198292c795f310a77..d6069395474ab21ddd877c02e804944deafc7d44 100644 (file)
@@ -157,7 +157,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         if let ty::BoundConstness::ConstIfConst = self.constness {
             write!(f, "~const ")?;
         }
-        write!(f, "TraitPredicate({:?})", self.trait_ref)
+        write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity)
     }
 }
 
@@ -365,8 +365,11 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
 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>> {
-        tcx.lift(self.trait_ref)
-            .map(|trait_ref| ty::TraitPredicate { trait_ref, constness: self.constness })
+        tcx.lift(self.trait_ref).map(|trait_ref| ty::TraitPredicate {
+            trait_ref,
+            constness: self.constness,
+            polarity: self.polarity,
+        })
     }
 }
 
@@ -591,6 +594,7 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         Some(match self {
             Mismatch => Mismatch,
             ConstnessMismatch(x) => ConstnessMismatch(x),
+            PolarityMismatch(x) => PolarityMismatch(x),
             UnsafetyMismatch(x) => UnsafetyMismatch(x),
             AbiMismatch(x) => AbiMismatch(x),
             Mutability => Mutability,
index d3094b3e6ff4d74ccb3ea809de72d01ebcd1bcf2..874de3366d79213ee7499075d518f5a41f3eb58d 100644 (file)
@@ -882,6 +882,7 @@ pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> {
         self.map_bound(|trait_ref| ty::TraitPredicate {
             trait_ref,
             constness: ty::BoundConstness::NotConst,
+            polarity: ty::ImplPolarity::Positive,
         })
     }
 }
index 05995ddcc00513398e1036cb0b7aa9ed0d8518e4..c6a34ece24576e51aa85e42b2d179aa26943dcd1 100644 (file)
@@ -221,15 +221,13 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
             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 (capture_index, capture) = if let Some(capture_details) =
+            let Some((capture_index, capture)) =
                 find_capture_matching_projections(
                     typeck_results,
                     var_hir_id,
                     closure_def_id,
                     &from_builder.projection,
-                ) {
-                capture_details
-            } else {
+                ) else {
                 if !enable_precise_capture(tcx, closure_span) {
                     bug!(
                         "No associated capture found for {:?}[{:#?}] even though \
index b74208edafea6172643d9c02f41a5a8cfb7679d2..8dadbf5f02bd1bd2a6a5a339cb56730867d30f08 100644 (file)
@@ -362,11 +362,7 @@ fn link_blocks<'tcx>(
         blocks: &IndexVec<DropIdx, Option<BasicBlock>>,
     ) {
         for (drop_idx, drop_data) in self.drops.iter_enumerated().rev() {
-            let block = if let Some(block) = blocks[drop_idx] {
-                block
-            } else {
-                continue;
-            };
+            let Some(block) = blocks[drop_idx] else { continue };
             match drop_data.0.kind {
                 DropKind::Value => {
                     let terminator = TerminatorKind::Drop {
index 02023c48a6c98d0371666340c32fff6bb2d1c21a..b0f1e08562c1609b4d91ef91d0b9333478f2d59c 100644 (file)
@@ -6,6 +6,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(bool_to_option)]
 #![feature(iter_zip)]
+#![feature(let_else)]
 #![feature(once_cell)]
 #![feature(min_specialization)]
 #![recursion_limit = "256"]
index ef8bd20d51098c3e94821c1ded39573525b9d0da..e4c2d2dce67c7d3883b5614c3e23599a74626e59 100644 (file)
@@ -2,7 +2,6 @@
     NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
 };
 use rustc_hir::intravisit::FnKind;
-use rustc_middle::hir::map::blocks::FnLikeNode;
 use rustc_middle::mir::{BasicBlock, Body, Operand, TerminatorKind};
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
 use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
@@ -14,8 +13,8 @@
     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_like_node) = FnLikeNode::from_node(tcx.hir().get(hir_id)) {
-        if let FnKind::Closure = fn_like_node.kind() {
+    if let Some(fn_kind) = tcx.hir().get(hir_id).fn_kind() {
+        if let FnKind::Closure = fn_kind {
             // closures can't recur, so they don't matter.
             return;
         }
index 847b89f0464f6fa474ea962ed70448b24711a903..dd16e3cde75aeff584ab37c15de47aeb22a94d62 100644 (file)
@@ -130,6 +130,9 @@ fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<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()
                     }
index c000e49c14bc1b72483803e310601e420be49193..ba6b566a304a5d75804d24a1150e634c67eb09ae 100644 (file)
@@ -64,6 +64,13 @@ pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
         }
     }
 
+    /// Allows inspection of unreachable basic blocks even with `debug_assertions` enabled.
+    #[cfg(test)]
+    pub(crate) fn allow_unreachable(&mut self) {
+        #[cfg(debug_assertions)]
+        self.reachable_blocks.insert_all()
+    }
+
     /// Returns the underlying `Results`.
     pub fn results(&self) -> &Results<'tcx, A> {
         &self.results.borrow()
index a5989121679c4fa8fb2014cd9910581e30520a48..6efa8daec489a9e1da66a566e11bc7bb7ff8eb74 100644 (file)
@@ -268,6 +268,8 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'tcx, D>) {
     let mut cursor =
         Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body);
 
+    cursor.allow_unreachable();
+
     let every_target = || {
         body.basic_blocks()
             .iter_enumerated()
index 158ba1b942528072c7416f70fe9cb434590e83a6..d38b567a95849be35d1995a6e2e8c3707dd2e1e4 100644 (file)
@@ -3,25 +3,14 @@
 use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{ParamEnv, TyCtxt};
-use rustc_span::DUMMY_SP;
-
-pub type MaybeMutBorrowedLocals<'mir, 'tcx> = MaybeBorrowedLocals<MutBorrow<'mir, 'tcx>>;
 
 /// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points
 /// to a given local.
 ///
-/// The `K` parameter determines what kind of borrows are tracked. By default,
-/// `MaybeBorrowedLocals` looks for *any* borrow of a local. If you are only interested in borrows
-/// that might allow mutation, use the `MaybeMutBorrowedLocals` type alias instead.
-///
 /// At present, this is used as a very limited form of alias analysis. For example,
 /// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
-/// immovable generators. `MaybeMutBorrowedLocals` is used during const checking to prove that a
-/// local has not been mutated via indirect assignment (e.g., `*p = 42`), the side-effects of a
-/// function call or inline assembly.
-pub struct MaybeBorrowedLocals<K = AnyBorrow> {
-    kind: K,
+/// immovable generators.
+pub struct MaybeBorrowedLocals {
     ignore_borrow_on_drop: bool,
 }
 
@@ -29,29 +18,11 @@ impl MaybeBorrowedLocals {
     /// A dataflow analysis that records whether a pointer or reference exists that may alias the
     /// given local.
     pub fn all_borrows() -> Self {
-        MaybeBorrowedLocals { kind: AnyBorrow, ignore_borrow_on_drop: false }
-    }
-}
-
-impl MaybeMutBorrowedLocals<'mir, 'tcx> {
-    /// A dataflow analysis that records whether a pointer or reference exists that may *mutably*
-    /// alias the given local.
-    ///
-    /// This includes `&mut` and pointers derived from an `&mut`, as well as shared borrows of
-    /// types with interior mutability.
-    pub fn mut_borrows_only(
-        tcx: TyCtxt<'tcx>,
-        body: &'mir mir::Body<'tcx>,
-        param_env: ParamEnv<'tcx>,
-    ) -> Self {
-        MaybeBorrowedLocals {
-            kind: MutBorrow { body, tcx, param_env },
-            ignore_borrow_on_drop: false,
-        }
+        MaybeBorrowedLocals { ignore_borrow_on_drop: false }
     }
 }
 
-impl<K> MaybeBorrowedLocals<K> {
+impl MaybeBorrowedLocals {
     /// During dataflow analysis, ignore the borrow that may occur when a place is dropped.
     ///
     /// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a
@@ -69,21 +40,14 @@ pub fn unsound_ignore_borrow_on_drop(self) -> Self {
         MaybeBorrowedLocals { ignore_borrow_on_drop: true, ..self }
     }
 
-    fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T, K> {
-        TransferFunction {
-            kind: &self.kind,
-            trans,
-            ignore_borrow_on_drop: self.ignore_borrow_on_drop,
-        }
+    fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> {
+        TransferFunction { trans, ignore_borrow_on_drop: self.ignore_borrow_on_drop }
     }
 }
 
-impl<K> AnalysisDomain<'tcx> for MaybeBorrowedLocals<K>
-where
-    K: BorrowAnalysisKind<'tcx>,
-{
+impl AnalysisDomain<'tcx> for MaybeBorrowedLocals {
     type Domain = BitSet<Local>;
-    const NAME: &'static str = K::ANALYSIS_NAME;
+    const NAME: &'static str = "maybe_borrowed_locals";
 
     fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
         // bottom = unborrowed
@@ -95,10 +59,7 @@ fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
     }
 }
 
-impl<K> GenKillAnalysis<'tcx> for MaybeBorrowedLocals<K>
-where
-    K: BorrowAnalysisKind<'tcx>,
-{
+impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
     type Idx = Local;
 
     fn statement_effect(
@@ -131,16 +92,14 @@ fn call_return_effect(
 }
 
 /// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
-struct TransferFunction<'a, T, K> {
+struct TransferFunction<'a, T> {
     trans: &'a mut T,
-    kind: &'a K,
     ignore_borrow_on_drop: bool,
 }
 
-impl<T, K> Visitor<'tcx> for TransferFunction<'a, T, K>
+impl<T> Visitor<'tcx> for TransferFunction<'a, T>
 where
     T: GenKill<Local>,
-    K: BorrowAnalysisKind<'tcx>,
 {
     fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) {
         self.super_statement(stmt, location);
@@ -156,14 +115,14 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
         self.super_rvalue(rvalue, location);
 
         match rvalue {
-            mir::Rvalue::AddressOf(mt, borrowed_place) => {
-                if !borrowed_place.is_indirect() && self.kind.in_address_of(*mt, *borrowed_place) {
+            mir::Rvalue::AddressOf(_mt, borrowed_place) => {
+                if !borrowed_place.is_indirect() {
                     self.trans.gen(borrowed_place.local);
                 }
             }
 
-            mir::Rvalue::Ref(_, kind, borrowed_place) => {
-                if !borrowed_place.is_indirect() && self.kind.in_ref(*kind, *borrowed_place) {
+            mir::Rvalue::Ref(_, _kind, borrowed_place) => {
+                if !borrowed_place.is_indirect() {
                     self.trans.gen(borrowed_place.local);
                 }
             }
@@ -211,64 +170,3 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Loc
         }
     }
 }
-
-pub struct AnyBorrow;
-
-pub struct MutBorrow<'mir, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    body: &'mir Body<'tcx>,
-    param_env: ParamEnv<'tcx>,
-}
-
-impl MutBorrow<'mir, 'tcx> {
-    /// `&` and `&raw` only allow mutation if the borrowed place is `!Freeze`.
-    ///
-    /// This assumes that it is UB to take the address of a struct field whose type is
-    /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
-    /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
-    /// have to check the type of the borrowed **local** instead of the borrowed **place**
-    /// below. See [rust-lang/unsafe-code-guidelines#134].
-    ///
-    /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
-    fn shared_borrow_allows_mutation(&self, place: Place<'tcx>) -> bool {
-        !place.ty(self.body, self.tcx).ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env)
-    }
-}
-
-pub trait BorrowAnalysisKind<'tcx> {
-    const ANALYSIS_NAME: &'static str;
-
-    fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool;
-    fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool;
-}
-
-impl BorrowAnalysisKind<'tcx> for AnyBorrow {
-    const ANALYSIS_NAME: &'static str = "maybe_borrowed_locals";
-
-    fn in_ref(&self, _: mir::BorrowKind, _: Place<'_>) -> bool {
-        true
-    }
-    fn in_address_of(&self, _: Mutability, _: Place<'_>) -> bool {
-        true
-    }
-}
-
-impl BorrowAnalysisKind<'tcx> for MutBorrow<'mir, 'tcx> {
-    const ANALYSIS_NAME: &'static str = "maybe_mut_borrowed_locals";
-
-    fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool {
-        match kind {
-            mir::BorrowKind::Mut { .. } => true,
-            mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
-                self.shared_borrow_allows_mutation(place)
-            }
-        }
-    }
-
-    fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool {
-        match mt {
-            Mutability::Mut => true,
-            Mutability::Not => self.shared_borrow_allows_mutation(place),
-        }
-    }
-}
index 474f4f2a79b2a7475a25344d49f0f9193b48d04c..91dddc6cd55c5d415b76548051dd488b0774bb4a 100644 (file)
@@ -22,7 +22,7 @@
 mod liveness;
 mod storage_liveness;
 
-pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals};
+pub use self::borrowed_locals::MaybeBorrowedLocals;
 pub use self::init_locals::MaybeInitializedLocals;
 pub use self::liveness::MaybeLiveLocals;
 pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive};
index 402391b87eaa93e177dee350192a0beacc64e7ea..77a72ce63ce5ee53ccc2ed8e74ce159fcafc1d27 100644 (file)
@@ -2,10 +2,10 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![cfg_attr(bootstrap, feature(const_panic))]
 #![feature(exact_size_is_empty)]
 #![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
+#![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(once_cell)]
 #![feature(stmt_expr_attributes)]
index c0bf4b659aa9674c12fa61201d51571afe3decaf..28e5d76783aa4015cb8af5bc2cce5b2a618cf584 100644 (file)
@@ -11,8 +11,7 @@
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
 use crate::impls::{
-    DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeMutBorrowedLocals,
-    MaybeUninitializedPlaces,
+    DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces,
 };
 use crate::move_paths::{HasMoveData, MoveData};
 use crate::move_paths::{LookupResult, MovePathIndex};
@@ -62,14 +61,6 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_def_inits);
         }
 
-        if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_indirectly_mutable).is_some() {
-            let flow_mut_borrowed = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env)
-                .into_engine(tcx, body)
-                .iterate_to_fixpoint();
-
-            sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_mut_borrowed);
-        }
-
         if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_liveness).is_some() {
             let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
 
@@ -281,28 +272,6 @@ fn peek_at(
     }
 }
 
-impl<'tcx> RustcPeekAt<'tcx> for MaybeMutBorrowedLocals<'_, 'tcx> {
-    fn peek_at(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        place: mir::Place<'tcx>,
-        flow_state: &BitSet<Local>,
-        call: PeekCall,
-    ) {
-        info!(?place, "peek_at");
-        let local = if let Some(l) = place.as_local() {
-            l
-        } else {
-            tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
-            return;
-        };
-
-        if !flow_state.contains(local) {
-            tcx.sess.span_err(call.span, "rustc_peek: bit not set");
-        }
-    }
-}
-
 impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals {
     fn peek_at(
         &self,
@@ -312,9 +281,7 @@ fn peek_at(
         call: PeekCall,
     ) {
         info!(?place, "peek_at");
-        let local = if let Some(l) = place.as_local() {
-            l
-        } else {
+        let Some(local) = place.as_local() else {
             tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
             return;
         };
index 17790ec91c8a3fd17d19132ad21aba33e9255712..63c637af5c21a39ae94067abde5c52efc531b007 100644 (file)
@@ -68,11 +68,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             return;
         }
 
-        use rustc_middle::hir::map::blocks::FnLikeNode;
         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 = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
+        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;
 
         // Only run const prop on functions, methods, closures and associated constants
index 1c946bd2d8af282e73abc0bf5597ddb0129ede9e..4ac93f716192308709d3c18b73b58d8cb63041f6 100644 (file)
 
 use crate::MirPass;
 
-use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::graph::WithNumNodes;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
 use rustc_index::vec::IndexVec;
 use rustc_middle::hir;
-use rustc_middle::hir::map::blocks::FnLikeNode;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::dump_enabled;
@@ -29,7 +27,6 @@
     TerminatorKind,
 };
 use rustc_middle::ty::TyCtxt;
-use rustc_query_system::ich::StableHashingContext;
 use rustc_span::def_id::DefId;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol};
@@ -66,7 +63,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
         }
 
         let hir_id = tcx.hir().local_def_id_to_hir_id(mir_source.def_id().expect_local());
-        let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
+        let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some();
 
         // Only instrument functions, methods, and closures (not constants since they are evaluated
         // at compile time by Miri).
@@ -76,7 +73,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
         // be tricky if const expressions have no corresponding statements in the enclosing MIR.
         // Closures are carved out by their initial `Assign` statement.)
         if !is_fn_like {
-            trace!("InstrumentCoverage skipped for {:?} (not an FnLikeNode)", mir_source.def_id());
+            trace!("InstrumentCoverage skipped for {:?} (not an fn-like)", mir_source.def_id());
             return;
         }
 
@@ -574,15 +571,13 @@ fn get_body_span<'tcx>(
 }
 
 fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {
+    // FIXME(cjgillot) Stop hashing HIR manually here.
     let mut hcx = tcx.create_no_span_stable_hashing_context();
-    hash(&mut hcx, &hir_body.value).to_smaller_hash()
-}
-
-fn hash(
-    hcx: &mut StableHashingContext<'tcx>,
-    node: &impl HashStable<StableHashingContext<'tcx>>,
-) -> Fingerprint {
     let mut stable_hasher = StableHasher::new();
-    node.hash_stable(hcx, &mut stable_hasher);
+    let owner = hir_body.id().hir_id.owner;
+    let bodies = &tcx.hir_owner_nodes(owner).as_ref().unwrap().bodies;
+    hcx.with_hir_bodies(false, owner, bodies, |hcx| {
+        hir_body.value.hash_stable(hcx, &mut stable_hasher)
+    });
     stable_hasher.finish()
 }
index 2a24e1ea8d7edf968cbb898f958289ccad3eb257..6b995141a2bef7602ea8cfb6b7c9038bdad1cd21 100644 (file)
@@ -1,13 +1,12 @@
 //! This pass just dumps MIR at a specified point.
 
 use std::borrow::Cow;
-use std::fmt;
 use std::fs::File;
 use std::io;
 
 use crate::MirPass;
+use rustc_middle::mir::write_mir_pretty;
 use rustc_middle::mir::Body;
-use rustc_middle::mir::{dump_enabled, dump_mir, write_mir_pretty};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{OutputFilenames, OutputType};
 
@@ -21,29 +20,6 @@ fn name(&self) -> Cow<'_, str> {
     fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
 }
 
-pub struct Disambiguator {
-    is_after: bool,
-}
-
-impl fmt::Display for Disambiguator {
-    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let title = if self.is_after { "after" } else { "before" };
-        write!(formatter, "{}", title)
-    }
-}
-
-pub fn on_mir_pass<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    pass_num: &dyn fmt::Display,
-    pass_name: &str,
-    body: &Body<'tcx>,
-    is_after: bool,
-) {
-    if dump_enabled(tcx, pass_name, body.source.def_id()) {
-        dump_mir(tcx, Some(pass_num), pass_name, &Disambiguator { is_after }, body, |_, _| Ok(()));
-    }
-}
-
 pub fn emit_mir(tcx: TyCtxt<'_>, outputs: &OutputFilenames) -> io::Result<()> {
     let path = outputs.path(OutputType::Mir);
     let mut f = io::BufWriter::new(File::create(&path)?);
index ee4e91ecb62b036451e7a48c3e2c3635f6f30f7a..84a1e3fb600fdb42d9d4283be8cab5642577e4e1 100644 (file)
@@ -673,9 +673,7 @@ fn make_call_args(
             assert!(args.next().is_none());
 
             let tuple = Place::from(tuple);
-            let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.kind() {
-                s
-            } else {
+            let ty::Tuple(tuple_tys) = tuple.ty(caller_body, tcx).ty.kind() else {
                 bug!("Closure arguments are not passed as a tuple");
             };
 
index 9b11c8f0b24c0836fb96b3d31f82236d26e10b85..f9ef31462780731a9375aa0ec7f4f379c17da875 100644 (file)
@@ -1,9 +1,9 @@
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(const_panic))]
 #![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
+#![feature(let_else)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
 #![feature(option_get_or_insert_default)]
@@ -27,7 +27,7 @@
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::visit::Visitor as _;
-use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted};
+use rustc_middle::mir::{dump_mir, traversal, Body, ConstQualifs, MirPhase, Promoted};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 use rustc_span::{Span, Symbol};
@@ -65,6 +65,7 @@
 mod remove_unneeded_drops;
 mod remove_zsts;
 mod required_consts;
+mod reveal_all;
 mod separate_const_switch;
 mod shim;
 mod simplify;
@@ -187,12 +188,14 @@ fn run_passes(
     let mut index = 0;
     let mut run_pass = |pass: &dyn MirPass<'tcx>| {
         let run_hooks = |body: &_, index, is_after| {
-            dump_mir::on_mir_pass(
+            let disambiguator = if is_after { "after" } else { "before" };
+            dump_mir(
                 tcx,
-                &format_args!("{:03}-{:03}", phase_index, index),
+                Some(&format_args!("{:03}-{:03}", phase_index, index)),
                 &pass.name(),
+                &disambiguator,
                 body,
-                is_after,
+                |_, _| Ok(()),
             );
         };
         run_hooks(body, index, false);
@@ -428,8 +431,7 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
     }
 
     let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
-    use rustc_middle::hir::map::blocks::FnLikeNode;
-    let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
+    let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some();
     if is_fn_like {
         let did = def.did.to_def_id();
         let def = ty::WithOptConstParam::unknown(did);
@@ -488,6 +490,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     // to them. We run some optimizations before that, because they may be harder to do on the state
     // machine than on MIR with async primitives.
     let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[
+        &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode.
         &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
         &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
         &unreachable_prop::UnreachablePropagation,
index a2cce9f1eda076e12fc6f2f43b0465a5c4e62507..822a372d8ce90fa1a11d043fe96da70e1072f750 100644 (file)
@@ -17,9 +17,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 
 pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let language_items = tcx.lang_items();
-    let slice_len_fn_item_def_id = if let Some(slice_len_fn_item) = language_items.slice_len_fn() {
-        slice_len_fn_item
-    } else {
+    let Some(slice_len_fn_item_def_id) = language_items.slice_len_fn() else {
         // there is no language item to compare to :)
         return;
     };
index 76f0e83c8c3d5c8a63c6f65c9d01d8323ac48117..a04a0b51531509bf5ad7d3e16a9437b90cccb4e8 100644 (file)
@@ -208,7 +208,7 @@ fn normalize_array_len_call<'tcx>(
                         operand,
                         cast_ty,
                     ) => {
-                        let local = if let Some(local) = place.as_local() { local } else { return };
+                        let Some(local) = place.as_local() else { return };
                         match operand {
                             Operand::Copy(place) | Operand::Move(place) => {
                                 let operand_local =
@@ -255,9 +255,7 @@ fn normalize_array_len_call<'tcx>(
                         }
                     }
                     Rvalue::Len(place) => {
-                        let local = if let Some(local) = place.local_or_deref_local() {
-                            local
-                        } else {
+                        let Some(local) = place.local_or_deref_local() else {
                             return;
                         };
                         if let Some(cast_statement_idx) = state.get(&local).copied() {
index 5c9d04a08bfec775e45efd7df67f67359536f84e..c71bc512c31b5e8403eb59e59d5702ecec8d4813 100644 (file)
@@ -13,7 +13,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("Running RemoveUnneededDrops on {:?}", body.source);
 
         let did = body.source.def_id();
-        let param_env = tcx.param_env(did);
+        let param_env = tcx.param_env_reveal_all_normalized(did);
         let mut should_simplify = false;
 
         let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs
new file mode 100644 (file)
index 0000000..7b4eb49
--- /dev/null
@@ -0,0 +1,58 @@
+//! Normalizes MIR in RevealAll mode.
+
+use crate::MirPass;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+
+pub struct RevealAll;
+
+impl<'tcx> MirPass<'tcx> for RevealAll {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        // This pass must run before inlining, since we insert callee bodies in RevealAll mode.
+        // Do not apply this transformation to generators.
+        if (tcx.sess.mir_opt_level() >= 3 || !super::inline::is_enabled(tcx))
+            && body.generator.is_none()
+        {
+            let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+            RevealAllVisitor { tcx, param_env }.visit_body(body);
+        }
+    }
+}
+
+struct RevealAllVisitor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> {
+    #[inline]
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    #[inline]
+    fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
+        *ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
+    }
+
+    #[inline]
+    fn process_projection_elem(
+        &mut self,
+        elem: PlaceElem<'tcx>,
+        _: Location,
+    ) -> Option<PlaceElem<'tcx>> {
+        match elem {
+            PlaceElem::Field(field, ty) => {
+                let new_ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
+                if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
+            }
+            // None of those contain a Ty.
+            PlaceElem::Index(..)
+            | PlaceElem::Deref
+            | PlaceElem::ConstantIndex { .. }
+            | PlaceElem::Subslice { .. }
+            | PlaceElem::Downcast(..) => None,
+        }
+    }
+}
index 5cef64d7786b3b965e9b9bd0471cddb562be8fe8..2aa506112909d6241cdc6840d94cad79c3509031 100644 (file)
@@ -83,12 +83,9 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             let bb = BasicBlock::from_usize(bb);
             trace!("processing block {:?}", bb);
 
-            let discriminant_ty =
-                if let Some(ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) {
-                    ty
-                } else {
-                    continue;
-                };
+            let Some(discriminant_ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) else {
+                continue;
+            };
 
             let layout = tcx.layout_of(tcx.param_env(body.source.def_id()).and(discriminant_ty));
 
index f06426308a2287d58e263066f3f046a6452b732b..59988e69b5d3a0d3af3dc8c516c459fd19391af0 100644 (file)
@@ -450,7 +450,9 @@ fn collect_items_rec<'tcx>(
     // involving a dependency, and the lack of context is confusing) in this MVP, we focus on
     // diagnostics on edges crossing a crate boundary: the collected mono items which are not
     // defined in the local crate.
-    if tcx.sess.diagnostic().err_count() > error_count && starting_point.node.krate() != LOCAL_CRATE
+    if tcx.sess.diagnostic().err_count() > error_count
+        && starting_point.node.krate() != LOCAL_CRATE
+        && starting_point.node.is_user_defined()
     {
         let formatted_item = with_no_trimmed_paths(|| starting_point.node.to_string());
         tcx.sess.span_note_without_error(
@@ -804,13 +806,22 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Loc
                     }
                 }
             }
+            mir::TerminatorKind::Assert { ref msg, .. } => {
+                let lang_item = match msg {
+                    mir::AssertKind::BoundsCheck { .. } => LangItem::PanicBoundsCheck,
+                    _ => LangItem::Panic,
+                };
+                let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source)));
+                if should_codegen_locally(tcx, &instance) {
+                    self.output.push(create_fn_mono_item(tcx, instance, source));
+                }
+            }
             mir::TerminatorKind::Goto { .. }
             | mir::TerminatorKind::SwitchInt { .. }
             | mir::TerminatorKind::Resume
             | mir::TerminatorKind::Abort
             | mir::TerminatorKind::Return
-            | mir::TerminatorKind::Unreachable
-            | mir::TerminatorKind::Assert { .. } => {}
+            | mir::TerminatorKind::Unreachable => {}
             mir::TerminatorKind::GeneratorDrop
             | mir::TerminatorKind::Yield { .. }
             | mir::TerminatorKind::FalseEdge { .. }
@@ -934,21 +945,13 @@ fn visit_instance_use<'tcx>(
     }
 }
 
-// Returns `true` if we should codegen an instance in the local crate.
-// Returns `false` if we can just link to the upstream crate and therefore don't
-// need a mono item.
+/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
+/// can just link to the upstream crate and therefore don't need a mono item.
 fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
-    let def_id = match instance.def {
-        ty::InstanceDef::Item(def) => def.did,
-        ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id,
-        ty::InstanceDef::VtableShim(..)
-        | ty::InstanceDef::ReifyShim(..)
-        | ty::InstanceDef::ClosureOnceShim { .. }
-        | ty::InstanceDef::Virtual(..)
-        | ty::InstanceDef::FnPtrShim(..)
-        | ty::InstanceDef::DropGlue(..)
-        | ty::InstanceDef::Intrinsic(_)
-        | ty::InstanceDef::CloneShim(..) => return true,
+    let def_id = if let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() {
+        def_id
+    } else {
+        return true;
     };
 
     if tcx.is_foreign_item(def_id) {
index 08b1d7b7fabd7314f2487935b555bf2fe1c7001c..f4082153b684048d1310b9a1990ee6b721dd128b 100644 (file)
@@ -2,6 +2,7 @@
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
 #![feature(control_flow_enum)]
+#![feature(let_else)]
 #![feature(in_band_lifetimes)]
 #![recursion_limit = "256"]
 
index 429ed53d37977ec67288c929eb67d8888ce48b64..b41906111b938598ba89cc32804dc462e5c75226 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility};
 use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
 use rustc_middle::ty::print::characteristic_def_id_of_type;
-use rustc_middle::ty::{self, DefIdTree, InstanceDef, TyCtxt};
+use rustc_middle::ty::{self, fold::TypeFoldable, DefIdTree, InstanceDef, TyCtxt};
 use rustc_span::symbol::Symbol;
 
 use super::PartitioningCx;
@@ -300,14 +300,21 @@ fn characteristic_def_id_of_mono_item<'tcx>(
                     // call it.
                     return None;
                 }
-                // 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,
-                    ty::ParamEnv::reveal_all(),
-                    tcx.type_of(impl_def_id),
-                );
-                if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
-                    return Some(def_id);
+
+                // 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)
+                {
+                    // 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,
+                        ty::ParamEnv::reveal_all(),
+                        tcx.type_of(impl_def_id),
+                    );
+                    if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
+                        return Some(def_id);
+                    }
                 }
             }
 
@@ -451,9 +458,7 @@ fn mono_item_visibility(
     let is_generic = instance.substs.non_erasable_generics().next().is_some();
 
     // Upstream `DefId` instances get different handling than local ones.
-    let def_id = if let Some(def_id) = def_id.as_local() {
-        def_id
-    } else {
+    let Some(def_id) = def_id.as_local() else {
         return if export_generics && is_generic {
             // If it is an upstream monomorphization and we export generics, we must make
             // it available to downstream crates.
index 0f768b7819b5b67e35e6938626b5347e27588be3..e6e4438b6d41afa63bb448bbc1db8b81cfd51e17 100644 (file)
@@ -27,20 +27,23 @@ pub fn provide(providers: &mut Providers) {
     providers.unused_generic_params = unused_generic_params;
 }
 
-/// Determine which generic parameters are used by the function/method/closure represented by
-/// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty`
-/// indicates all parameters are used).
+/// Determine which generic parameters are used by the instance.
+///
+/// Returns a bitset where bits representing unused parameters are set (`is_empty` indicates all
+/// parameters are used).
 #[instrument(level = "debug", skip(tcx))]
-fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
+fn unused_generic_params<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    instance: ty::InstanceDef<'tcx>,
+) -> FiniteBitSet<u32> {
     if !tcx.sess.opts.debugging_opts.polymorphize {
         // If polymorphization disabled, then all parameters are used.
         return FiniteBitSet::new_empty();
     }
 
-    // Polymorphization results are stored in cross-crate metadata only when there are unused
-    // parameters, so assume that non-local items must have only used parameters (else this query
-    // would not be invoked, and the cross-crate metadata used instead).
-    if !def_id.is_local() {
+    let def_id = instance.def_id();
+    // Exit early if this instance should not be polymorphized.
+    if !should_polymorphize(tcx, def_id, instance) {
         return FiniteBitSet::new_empty();
     }
 
@@ -52,41 +55,25 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
         return FiniteBitSet::new_empty();
     }
 
-    // Exit early when there is no MIR available.
-    let context = tcx.hir().body_const_context(def_id.expect_local());
-    match context {
-        Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => {
-            debug!("no mir available");
-            return FiniteBitSet::new_empty();
-        }
-        Some(_) if !tcx.is_ctfe_mir_available(def_id) => {
-            debug!("no ctfe mir available");
-            return FiniteBitSet::new_empty();
-        }
-        _ => {}
-    }
-
     // Create a bitset with N rightmost ones for each parameter.
     let generics_count: u32 =
         generics.count().try_into().expect("more generic parameters than can fit into a `u32`");
     let mut unused_parameters = FiniteBitSet::<u32>::new_empty();
     unused_parameters.set_range(0..generics_count);
     debug!(?unused_parameters, "(start)");
+
     mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters);
     debug!(?unused_parameters, "(after default)");
 
     // Visit MIR and accumululate used generic parameters.
-    let body = match context {
+    let body = match tcx.hir().body_const_context(def_id.expect_local()) {
         // Const functions are actually called and should thus be considered for polymorphization
-        // via their runtime MIR
+        // via their runtime MIR.
         Some(ConstContext::ConstFn) | None => tcx.optimized_mir(def_id),
         Some(_) => tcx.mir_for_ctfe(def_id),
     };
     let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters };
     vis.visit_body(body);
-    debug!(?unused_parameters, "(after visitor)");
-
-    mark_used_by_predicates(tcx, def_id, &mut unused_parameters);
     debug!(?unused_parameters, "(end)");
 
     // Emit errors for debugging and testing if enabled.
@@ -97,6 +84,49 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
     unused_parameters
 }
 
+/// Returns `true` if the instance should be polymorphized.
+fn should_polymorphize<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    instance: ty::InstanceDef<'tcx>,
+) -> bool {
+    // If an instance's MIR body is not polymorphic then the modified substitutions that are
+    // derived from polymorphization's result won't make any difference.
+    if !instance.has_polymorphic_mir_body() {
+        return false;
+    }
+
+    // Don't polymorphize intrinsics or virtual calls - calling `instance_mir` will panic.
+    if matches!(instance, ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::Virtual(..)) {
+        return false;
+    }
+
+    // Polymorphization results are stored in cross-crate metadata only when there are unused
+    // parameters, so assume that non-local items must have only used parameters (else this query
+    // would not be invoked, and the cross-crate metadata used instead).
+    if !def_id.is_local() {
+        return false;
+    }
+
+    // Foreign items have no bodies to analyze.
+    if tcx.is_foreign_item(def_id) {
+        return false;
+    }
+
+    // Make sure there is MIR available.
+    match tcx.hir().body_const_context(def_id.expect_local()) {
+        Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => {
+            debug!("no mir available");
+            return false;
+        }
+        Some(_) if !tcx.is_ctfe_mir_available(def_id) => {
+            debug!("no ctfe mir available");
+            return false;
+        }
+        _ => true,
+    }
+}
+
 /// Some parameters are considered used-by-default, such as non-generic parameters and the dummy
 /// generic parameters from closures, this function marks them as used. `leaf_is_closure` should
 /// be `true` if the item that `unused_generic_params` was invoked on is a closure.
@@ -156,44 +186,6 @@ fn mark_used_by_default_parameters<'tcx>(
     }
 }
 
-/// Search the predicates on used generic parameters for any unused generic parameters, and mark
-/// those as used.
-#[instrument(level = "debug", skip(tcx, def_id))]
-fn mark_used_by_predicates<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: DefId,
-    unused_parameters: &mut FiniteBitSet<u32>,
-) {
-    let def_id = tcx.closure_base_def_id(def_id);
-    let predicates = tcx.explicit_predicates_of(def_id);
-
-    let mut current_unused_parameters = FiniteBitSet::new_empty();
-    // Run to a fixed point to support `where T: Trait<U>, U: Trait<V>`, starting with an empty
-    // bit set so that this is skipped if all parameters are already used.
-    while current_unused_parameters != *unused_parameters {
-        debug!(?current_unused_parameters, ?unused_parameters);
-        current_unused_parameters = *unused_parameters;
-
-        for (predicate, _) in predicates.predicates {
-            // Consider all generic params in a predicate as used if any other parameter in the
-            // predicate is used.
-            let any_param_used = {
-                let mut vis = HasUsedGenericParams { tcx, unused_parameters };
-                predicate.visit_with(&mut vis).is_break()
-            };
-
-            if any_param_used {
-                let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters };
-                predicate.visit_with(&mut vis);
-            }
-        }
-    }
-
-    if let Some(parent) = predicates.parent {
-        mark_used_by_predicates(tcx, parent, unused_parameters);
-    }
-}
-
 /// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic
 /// parameter which was unused.
 #[instrument(level = "debug", skip(tcx, generics))]
@@ -243,7 +235,8 @@ impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
     /// a closure, generator or constant).
     #[instrument(level = "debug", skip(self, def_id, substs))]
     fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) {
-        let unused = self.tcx.unused_generic_params(def_id);
+        let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id));
+        let unused = self.tcx.unused_generic_params(instance);
         debug!(?self.unused_parameters, ?unused);
         for (i, arg) in substs.iter().enumerate() {
             let i = i.try_into().unwrap();
index 799b4e18c240f24afedae9073453384356f2c5ad..4392c02f874d4da47001ca3f167f7baf37a85dda 100644 (file)
@@ -67,7 +67,7 @@
             src_file.prefer_local(),
             line_nos
         ) {
-            eprintln!("Error writting to file {}", e.to_string())
+            eprintln!("Error writing to file {}", e)
         }
     }
 }
index 1decaaa955f023075367e523b4e801eec49a2cb1..a823607ab0ec2191c86a3630fd2488d0c9198fb2 100644 (file)
@@ -18,3 +18,4 @@ rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_ast = { path = "../rustc_ast" }
 unicode-normalization = "0.1.11"
+unicode-width = "0.1.4"
index 1e65cc27154a818bd19889f40810dbef788acecc..09a3d1b902831f648a0df2e4ef14685e7e50a6fa 100644 (file)
@@ -4,7 +4,9 @@
 use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError, PResult};
 use rustc_lexer::unescape::{self, Mode};
 use rustc_lexer::{Base, DocStyle, RawStrError};
-use rustc_session::lint::builtin::RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX;
+use rustc_session::lint::builtin::{
+    RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
+};
 use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::{sym, Symbol};
@@ -129,6 +131,28 @@ fn struct_fatal_span_char(
             .struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c)))
     }
 
+    /// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly
+    /// complain about it.
+    fn lint_unicode_text_flow(&self, start: BytePos) {
+        // Opening delimiter of the length 2 is not included into the comment text.
+        let content_start = start + BytePos(2);
+        let content = self.str_from(content_start);
+        let span = self.mk_sp(start, self.pos);
+        const UNICODE_TEXT_FLOW_CHARS: &[char] = &[
+            '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}',
+            '\u{202C}', '\u{2069}',
+        ];
+        if content.contains(UNICODE_TEXT_FLOW_CHARS) {
+            self.sess.buffer_lint_with_diagnostic(
+                &TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
+                span,
+                ast::CRATE_NODE_ID,
+                "unicode codepoint changing visible direction of text present in comment",
+                BuiltinLintDiagnostics::UnicodeTextFlow(span, content.to_string()),
+            );
+        }
+    }
+
     /// Turns simple `rustc_lexer::TokenKind` enum into a rich
     /// `rustc_ast::TokenKind`. This turns strings into interned
     /// symbols and runs additional validation.
@@ -136,7 +160,12 @@ fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Opt
         Some(match token {
             rustc_lexer::TokenKind::LineComment { doc_style } => {
                 // Skip non-doc comments
-                let doc_style = doc_style?;
+                let doc_style = if let Some(doc_style) = doc_style {
+                    doc_style
+                } else {
+                    self.lint_unicode_text_flow(start);
+                    return None;
+                };
 
                 // Opening delimiter of the length 3 is not included into the symbol.
                 let content_start = start + BytePos(3);
@@ -158,7 +187,12 @@ fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Opt
                 }
 
                 // Skip non-doc comments
-                let doc_style = doc_style?;
+                let doc_style = if let Some(doc_style) = doc_style {
+                    doc_style
+                } else {
+                    self.lint_unicode_text_flow(start);
+                    return None;
+                };
 
                 // Opening delimiter of the length 3 and closing delimiter of the length 2
                 // are not included into the symbol.
index cef5b3a226bff81a65f1fa69da5bdfc227e06a77..569f186a72766f45aed97f560400a3cc91c5f6e7 100644 (file)
@@ -187,12 +187,17 @@ pub(crate) fn emit_unescape_error(
             assert!(mode.is_bytes());
             let (c, span) = last_char();
             let mut err = handler.struct_span_err(span, "non-ASCII character in byte constant");
-            err.span_label(span, "byte constant must be ASCII");
+            let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
+                format!(" but is {:?}", c)
+            } else {
+                String::new()
+            };
+            err.span_label(span, &format!("byte constant must be ASCII{}", postfix));
             if (c as u32) <= 0xFF {
                 err.span_suggestion(
                     span,
                     &format!(
-                        "if you meant to use the unicode code point for '{}', use a \\xHH escape",
+                        "if you meant to use the unicode code point for {:?}, use a \\xHH escape",
                         c
                     ),
                     format!("\\x{:X}", c as u32),
@@ -206,7 +211,7 @@ pub(crate) fn emit_unescape_error(
                 err.span_suggestion(
                     span,
                     &format!(
-                        "if you meant to use the UTF-8 encoding of '{}', use \\xHH escapes",
+                        "if you meant to use the UTF-8 encoding of {:?}, use \\xHH escapes",
                         c
                     ),
                     utf8.as_bytes()
@@ -220,10 +225,15 @@ pub(crate) fn emit_unescape_error(
         }
         EscapeError::NonAsciiCharInByteString => {
             assert!(mode.is_bytes());
-            let (_c, span) = last_char();
+            let (c, span) = last_char();
+            let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
+                format!(" but is {:?}", c)
+            } else {
+                String::new()
+            };
             handler
                 .struct_span_err(span, "raw byte string must be ASCII")
-                .span_label(span, "must be ASCII")
+                .span_label(span, &format!("must be ASCII{}", postfix))
                 .emit();
         }
         EscapeError::OutOfRangeHexEscape => {
index 8095f386fa3615144125bca5a0ebd9897a81789b..81328e09156a18c4399c9f85300c0e86ebf47e9f 100644 (file)
@@ -1342,10 +1342,10 @@ pub(super) fn recover_parens_around_for_head(
 
                 self.struct_span_err(
                     MultiSpan::from_spans(vec![begin_par_sp, self.prev_token.span]),
-                    "unexpected parenthesis surrounding `for` loop head",
+                    "unexpected parentheses surrounding `for` loop head",
                 )
                 .multipart_suggestion(
-                    "remove parenthesis in `for` loop",
+                    "remove parentheses in `for` loop",
                     vec![(begin_par_sp, String::new()), (self.prev_token.span, String::new())],
                     // With e.g. `for (x) in y)` this would replace `(x) in y)`
                     // with `x) in y)` which is syntactically invalid.
index 624390a406ff2bbcfbbbf3b298f6d1e124dec01c..d2167c7a5db0c8f642f61c047f5b3b54b39372eb 100644 (file)
@@ -216,7 +216,7 @@ fn parse_item_kind(
                 return Err(e);
             }
 
-            (Ident::invalid(), ItemKind::Use(tree))
+            (Ident::empty(), ItemKind::Use(tree))
         } else if self.check_fn_front_matter(def_final) {
             // FUNCTION ITEM
             let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?;
@@ -279,15 +279,15 @@ fn parse_item_kind(
         } else if self.eat_keyword(kw::Macro) {
             // MACROS 2.0 ITEM
             self.parse_item_decl_macro(lo)?
-        } else if self.is_macro_rules_item() {
+        } else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {
             // MACRO_RULES ITEM
-            self.parse_item_macro_rules(vis)?
+            self.parse_item_macro_rules(vis, has_bang)?
         } else if vis.kind.is_pub() && self.isnt_macro_invocation() {
             self.recover_missing_kw_before_item()?;
             return Ok(None);
         } else if macros_allowed && self.check_path() {
             // MACRO INVOCATION ITEM
-            (Ident::invalid(), ItemKind::MacCall(self.parse_item_macro(vis)?))
+            (Ident::empty(), ItemKind::MacCall(self.parse_item_macro(vis)?))
         } else {
             return Ok(None);
         };
@@ -300,7 +300,7 @@ pub(super) fn is_path_start_item(&mut self) -> bool {
         || self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
         || self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }`
         || self.is_async_fn() // no(2015): `async::b`, yes: `async fn`
-        || self.is_macro_rules_item() // no: `macro_rules::b`, yes: `macro_rules! mac`
+        || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac`
     }
 
     /// Are we sure this could not possibly be a macro invocation?
@@ -586,7 +586,7 @@ fn parse_item_impl(
             }
         };
 
-        Ok((Ident::invalid(), item_kind))
+        Ok((Ident::empty(), item_kind))
     }
 
     fn parse_item_list<T>(
@@ -933,7 +933,7 @@ fn parse_item_foreign_mod(
         let abi = self.parse_abi(); // ABI?
         let items = self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?;
         let module = ast::ForeignMod { unsafety, abi, items };
-        Ok((Ident::invalid(), ItemKind::ForeignMod(module)))
+        Ok((Ident::empty(), ItemKind::ForeignMod(module)))
     }
 
     /// Parses a foreign item (one in an `extern { ... }` block).
@@ -1534,18 +1534,43 @@ fn parse_item_decl_macro(&mut self, lo: Span) -> PResult<'a, ItemInfo> {
         Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, macro_rules: false })))
     }
 
-    /// Is this unambiguously the start of a `macro_rules! foo` item definition?
-    fn is_macro_rules_item(&mut self) -> bool {
-        self.check_keyword(kw::MacroRules)
-            && self.look_ahead(1, |t| *t == token::Not)
-            && self.look_ahead(2, |t| t.is_ident())
+    /// Is this a possibly malformed start of a `macro_rules! foo` item definition?
+
+    fn is_macro_rules_item(&mut self) -> IsMacroRulesItem {
+        if self.check_keyword(kw::MacroRules) {
+            let macro_rules_span = self.token.span;
+
+            if self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) {
+                return IsMacroRulesItem::Yes { has_bang: true };
+            } else if self.look_ahead(1, |t| (t.is_ident())) {
+                // macro_rules foo
+                self.struct_span_err(macro_rules_span, "expected `!` after `macro_rules`")
+                    .span_suggestion(
+                        macro_rules_span,
+                        "add a `!`",
+                        "macro_rules!".to_owned(),
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+
+                return IsMacroRulesItem::Yes { has_bang: false };
+            }
+        }
+
+        IsMacroRulesItem::No
     }
 
     /// Parses a `macro_rules! foo { ... }` declarative macro.
-    fn parse_item_macro_rules(&mut self, vis: &Visibility) -> PResult<'a, ItemInfo> {
+    fn parse_item_macro_rules(
+        &mut self,
+        vis: &Visibility,
+        has_bang: bool,
+    ) -> PResult<'a, ItemInfo> {
         self.expect_keyword(kw::MacroRules)?; // `macro_rules`
-        self.expect(&token::Not)?; // `!`
 
+        if has_bang {
+            self.expect(&token::Not)?; // `!`
+        }
         let ident = self.parse_ident()?;
 
         if self.eat(&token::Not) {
@@ -2121,3 +2146,8 @@ fn recover_first_param(&mut self) -> &'static str {
         }
     }
 }
+
+enum IsMacroRulesItem {
+    Yes { has_bang: bool },
+    No,
+}
index 5c701fefd17de95b0d95dfaeaa64f625f61f27e2..e50b983ec621680f962c302772932cd74ff0a06a 100644 (file)
@@ -1258,7 +1258,7 @@ fn is_crate_vis(&self) -> bool {
     /// Parses `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `crate` for `pub(crate)`,
     /// `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`.
     /// If the following element can't be a tuple (i.e., it's a function definition), then
-    /// it's not a tuple struct field), and the contents within the parentheses isn't valid,
+    /// it's not a tuple struct field), and the contents within the parentheses aren't valid,
     /// so emit a proper diagnostic.
     // Public for rustfmt usage.
     pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> {
index 9ec6effeb4e03a9e2ed2368204ed75511a38eb3d..01e751ea8b5bff53bff164fd6a936c49e61f371e 100644 (file)
@@ -16,7 +16,7 @@
 };
 use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt};
 use rustc_ast::{StmtKind, DUMMY_NODE_ID};
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
 use rustc_span::source_map::{BytePos, Span};
 use rustc_span::symbol::{kw, sym};
 
@@ -300,6 +300,12 @@ fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
             None => LocalKind::Decl,
             Some(init) => {
                 if self.eat_keyword(kw::Else) {
+                    if self.token.is_keyword(kw::If) {
+                        // `let...else if`. Emit the same error that `parse_block()` would,
+                        // but explicitly point out that this pattern is not allowed.
+                        let msg = "conditional `else if` is not supported for `let...else`";
+                        return Err(self.error_block_no_opening_brace_msg(msg));
+                    }
                     let els = self.parse_block()?;
                     self.check_let_else_init_bool_expr(&init);
                     self.check_let_else_init_trailing_brace(&init);
@@ -328,7 +334,7 @@ fn check_let_else_init_bool_expr(&self, init: &ast::Expr) {
                     ),
                 )
                 .multipart_suggestion(
-                    "wrap the expression in parenthesis",
+                    "wrap the expression in parentheses",
                     suggs,
                     Applicability::MachineApplicable,
                 )
@@ -349,7 +355,7 @@ fn check_let_else_init_trailing_brace(&self, init: &ast::Expr) {
                 "right curly brace `}` before `else` in a `let...else` statement not allowed",
             )
             .multipart_suggestion(
-                "try wrapping the expression in parenthesis",
+                "try wrapping the expression in parentheses",
                 suggs,
                 Applicability::MachineApplicable,
             )
@@ -392,10 +398,9 @@ pub(super) fn parse_block(&mut self) -> PResult<'a, P<Block>> {
         Ok(block)
     }
 
-    fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
+    fn error_block_no_opening_brace_msg(&mut self, msg: &str) -> DiagnosticBuilder<'a> {
         let sp = self.token.span;
-        let tok = super::token_descr(&self.token);
-        let mut e = self.struct_span_err(sp, &format!("expected `{{`, found {}", tok));
+        let mut e = self.struct_span_err(sp, msg);
         let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
 
         // Check to see if the user has written something like
@@ -435,7 +440,13 @@ fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
             _ => {}
         }
         e.span_label(sp, "expected `{`");
-        Err(e)
+        e
+    }
+
+    fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
+        let tok = super::token_descr(&self.token);
+        let msg = format!("expected `{{`, found {}", tok);
+        Err(self.error_block_no_opening_brace_msg(&msg))
     }
 
     /// Parses a block. Inner attributes are allowed.
index 98400372c36a6576e9c90b8350f2d430d52a6a20..c4c0c17addf107959d8ed95dd909fb3c1f656330 100644 (file)
@@ -430,7 +430,7 @@ fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
     }
 
     // Parses the `typeof(EXPR)`.
-    // To avoid ambiguity, the type is surrounded by parenthesis.
+    // To avoid ambiguity, the type is surrounded by parentheses.
     fn parse_typeof_ty(&mut self) -> PResult<'a, TyKind> {
         self.expect(&token::OpenDelim(token::Paren))?;
         let expr = self.parse_anon_const_expr()?;
index e5fbddda74427a8e0d60b8d0c4a5681854e01bb0..596d13d2d9acbb7aa8c79b2f79820e88f76db106 100644 (file)
@@ -765,7 +765,7 @@ fn check_doc_inline(
                             "not a `use` item",
                         );
                     }
-                    err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information")
+                    err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information")
                         .emit();
                 },
             );
index ae3a9c71c59686fc23e0120cff1abade2dfe610f..fa34b9abc1e6c9314288ae045f6d1e71dde8ec03 100644 (file)
@@ -23,7 +23,7 @@
 use rustc_middle::thir::abstract_const::Node as ACNode;
 use rustc_middle::ty::fold::TypeVisitor;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
@@ -124,9 +124,11 @@ fn visit_projection_ty(
 
     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
         match predicate.kind().skip_binder() {
-            ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: _ }) => {
-                self.visit_trait(trait_ref)
-            }
+            ty::PredicateKind::Trait(ty::TraitPredicate {
+                trait_ref,
+                constness: _,
+                polarity: _,
+            }) => self.visit_trait(trait_ref),
             ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
                 ty.visit_with(self)?;
                 self.visit_projection_ty(projection_ty)
@@ -153,11 +155,8 @@ fn visit_abstract_const_expr(
         tcx: TyCtxt<'tcx>,
         ct: AbstractConst<'tcx>,
     ) -> ControlFlow<V::BreakTy> {
-        const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root() {
-            ACNode::Leaf(leaf) => {
-                let leaf = leaf.subst(tcx, ct.substs);
-                self.visit_const(leaf)
-            }
+        const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root(tcx) {
+            ACNode::Leaf(leaf) => self.visit_const(leaf),
             ACNode::Cast(_, _, ty) => self.visit_ty(ty),
             ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
                 ControlFlow::CONTINUE
index 89df3d4674b6b363cc471fe89329292966f3329d..f984bb1872b2842ea21538bd86a57566c4ceed6a 100644 (file)
@@ -7,9 +7,8 @@ edition = "2021"
 doctest = false
 
 [dependencies]
-measureme = "9.0.0"
+measureme = "10.0.0"
 rustc-rayon-core = "0.3.1"
-tracing = "0.1"
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
index e50a8c191ad4001d48f36a56038c199472a6e624..440b6f1983e6eee7d8e7cbfcf3784268412de789 100644 (file)
 extern crate rustc_macros;
 #[macro_use]
 extern crate rustc_middle;
-#[macro_use]
-extern crate tracing;
 
-use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_errors::DiagnosticBuilder;
-use rustc_middle::dep_graph;
+use rustc_middle::arena::Arena;
+use rustc_middle::dep_graph::{self, DepKindStruct, SerializedDepNodeIndex};
 use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values};
-use rustc_middle::ty::query::{Providers, QueryEngine};
+use rustc_middle::ty::query::{ExternProviders, Providers, QueryEngine};
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_query_system::ich::StableHashingContext;
+use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
 
 #[macro_use]
 mod plumbing;
 pub use plumbing::QueryCtxt;
-use plumbing::QueryStruct;
 use rustc_query_system::query::*;
 
 mod stats;
@@ -41,9 +37,8 @@
 mod values;
 use self::values::Value;
 
-use rustc_query_system::query::QueryAccessors;
 pub use rustc_query_system::query::QueryConfig;
-pub(crate) use rustc_query_system::query::QueryDescription;
+pub(crate) use rustc_query_system::query::{QueryDescription, QueryVtable};
 
 mod on_disk_cache;
 pub use on_disk_cache::OnDiskCache;
 
 mod util;
 
+fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
+    if def_id.is_top_level_module() {
+        "top-level module".to_string()
+    } else {
+        format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
+    }
+}
+
 rustc_query_append! { [define_queries!][<'tcx>] }
 
 impl<'tcx> Queries<'tcx> {
index 48eb488792d8973b05fe582fa329c0c4679e854a..552906aac31a7f5ac79b3abd45e612dd981f8de4 100644 (file)
@@ -219,7 +219,7 @@ fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>) {
         // Do this *before* we clone 'latest_foreign_def_path_hashes', since
         // loading existing queries may cause us to create new DepNodes, which
         // may in turn end up invoking `store_foreign_def_id_hash`
-        tcx.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx));
+        tcx.dep_graph.exec_cache_promotions(tcx);
 
         *self.serialized_data.write() = None;
     }
@@ -358,23 +358,6 @@ fn serialize<'tcx>(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileE
             Ok(())
         })
     }
-
-    fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) -> DefId {
-        debug!("def_path_hash_to_def_id({:?})", hash);
-
-        let stable_crate_id = hash.stable_crate_id();
-
-        // If this is a DefPathHash from the local crate, we can look up the
-        // DefId in the tcx's `Definitions`.
-        if stable_crate_id == tcx.sess.local_stable_crate_id() {
-            tcx.definitions_untracked().local_def_path_hash_to_def_id(hash).to_def_id()
-        } else {
-            // If this is a DefPathHash from an upstream crate, let the CrateStore map
-            // it to a DefId.
-            let cnum = tcx.cstore_untracked().stable_crate_id_to_crate_num(stable_crate_id);
-            tcx.cstore_untracked().def_path_hash_to_def_id(cnum, hash)
-        }
-    }
 }
 
 impl<'sess> OnDiskCache<'sess> {
@@ -764,7 +747,7 @@ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
         // If we get to this point, then all of the query inputs were green,
         // which means that the definition with this hash is guaranteed to
         // still exist in the current compilation session.
-        Ok(d.tcx().on_disk_cache.as_ref().unwrap().def_path_hash_to_def_id(d.tcx(), def_path_hash))
+        Ok(d.tcx().def_path_hash_to_def_id(def_path_hash))
     }
 }
 
@@ -1035,7 +1018,7 @@ pub fn encode_query_results<'a, 'tcx, CTX, Q>(
 ) -> FileEncodeResult
 where
     CTX: QueryContext + 'tcx,
-    Q: super::QueryDescription<CTX> + super::QueryAccessors<CTX>,
+    Q: super::QueryDescription<CTX>,
     Q::Value: Encodable<CacheEncoder<'a, 'tcx, FileEncoder>>,
 {
     let _timer = tcx
@@ -1050,7 +1033,7 @@ pub fn encode_query_results<'a, 'tcx, CTX, Q>(
         if res.is_err() {
             return;
         }
-        if Q::cache_on_disk(tcx, &key, Some(value)) {
+        if Q::cache_on_disk(*tcx.dep_context(), &key) {
             let dep_node = SerializedDepNodeIndex::new(dep_node.index());
 
             // Record position of the cache entry.
index 4d1e39db0ed48f3ce82702305512e93bb8296dac..81a36e0d59eff601769bb373d03bf3b047e62df1 100644 (file)
@@ -2,20 +2,17 @@
 //! generate the actual methods on tcx which find and execute the provider,
 //! manage the caches, and so forth.
 
-use crate::{on_disk_cache, queries, Queries};
-use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex};
+use crate::{on_disk_cache, Queries};
+use rustc_middle::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex};
 use rustc_middle::ty::tls::{self, ImplicitCtxt};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 use rustc_query_system::dep_graph::HasDepContext;
-use rustc_query_system::query::{
-    QueryContext, QueryDescription, QueryJobId, QueryMap, QuerySideEffects,
-};
+use rustc_query_system::query::{QueryContext, QueryJobId, QueryMap, QuerySideEffects};
 
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::{Diagnostic, Handler};
 use rustc_serialize::opaque;
-use rustc_span::def_id::LocalDefId;
 
 use std::any::Any;
 
@@ -53,36 +50,6 @@ fn try_collect_active_jobs(&self) -> Option<QueryMap<Self::DepKind>> {
         self.queries.try_collect_active_jobs(**self)
     }
 
-    fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) {
-        let cb = &super::QUERY_CALLBACKS[dep_node.kind as usize];
-        (cb.try_load_from_on_disk_cache)(*self, dep_node)
-    }
-
-    fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool {
-        debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
-
-        // We must avoid ever having to call `force_from_dep_node()` for a
-        // `DepNode::codegen_unit`:
-        // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
-        // would always end up having to evaluate the first caller of the
-        // `codegen_unit` query that *is* reconstructible. This might very well be
-        // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
-        // to re-trigger calling the `codegen_unit` query with the right key. At
-        // that point we would already have re-done all the work we are trying to
-        // avoid doing in the first place.
-        // The solution is simple: Just explicitly call the `codegen_unit` query for
-        // each CGU, right after partitioning. This way `try_mark_green` will always
-        // hit the cache instead of having to go through `force_from_dep_node`.
-        // This assertion makes sure, we actually keep applying the solution above.
-        debug_assert!(
-            dep_node.kind != DepKind::codegen_unit,
-            "calling force_from_dep_node() on DepKind::codegen_unit"
-        );
-
-        let cb = &super::QUERY_CALLBACKS[dep_node.kind as usize];
-        (cb.force_from_dep_node)(*self, dep_node)
-    }
-
     // Interactions with on_disk_cache
     fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects {
         self.queries
@@ -193,60 +160,6 @@ pub fn try_print_query_stack(
     }
 }
 
-/// This struct stores metadata about each Query.
-///
-/// Information is retrieved by indexing the `QUERIES` array using the integer value
-/// of the `DepKind`. Overall, this allows to implement `QueryContext` using this manual
-/// jump table instead of large matches.
-pub struct QueryStruct {
-    /// The red/green evaluation system will try to mark a specific DepNode in the
-    /// dependency graph as green by recursively trying to mark the dependencies of
-    /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
-    /// where we don't know if it is red or green and we therefore actually have
-    /// to recompute its value in order to find out. Since the only piece of
-    /// information that we have at that point is the `DepNode` we are trying to
-    /// re-evaluate, we need some way to re-run a query from just that. This is what
-    /// `force_from_dep_node()` implements.
-    ///
-    /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
-    /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
-    /// is usually constructed by computing a stable hash of the query-key that the
-    /// `DepNode` corresponds to. Consequently, it is not in general possible to go
-    /// back from hash to query-key (since hash functions are not reversible). For
-    /// this reason `force_from_dep_node()` is expected to fail from time to time
-    /// because we just cannot find out, from the `DepNode` alone, what the
-    /// corresponding query-key is and therefore cannot re-run the query.
-    ///
-    /// The system deals with this case letting `try_mark_green` fail which forces
-    /// the root query to be re-evaluated.
-    ///
-    /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
-    /// Fortunately, we can use some contextual information that will allow us to
-    /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
-    /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
-    /// valid `DefPathHash`. Since we also always build a huge table that maps every
-    /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
-    /// everything we need to re-run the query.
-    ///
-    /// Take the `mir_promoted` query as an example. Like many other queries, it
-    /// just has a single parameter: the `DefId` of the item it will compute the
-    /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
-    /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
-    /// is actually a `DefPathHash`, and can therefore just look up the corresponding
-    /// `DefId` in `tcx.def_path_hash_to_def_id`.
-    ///
-    /// When you implement a new query, it will likely have a corresponding new
-    /// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As
-    /// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter,
-    /// then `force_from_dep_node()` should not fail for it. Otherwise, you can just
-    /// add it to the "We don't have enough information to reconstruct..." group in
-    /// the match below.
-    pub(crate) force_from_dep_node: fn(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool,
-
-    /// Invoke a query to put the on-disk cached value in memory.
-    pub(crate) try_load_from_on_disk_cache: fn(QueryCtxt<'_>, &DepNode),
-}
-
 macro_rules! handle_cycle_error {
     ([][$tcx: expr, $error:expr]) => {{
         $error.emit();
@@ -291,14 +204,30 @@ macro_rules! is_eval_always {
 }
 
 macro_rules! hash_result {
-    ([][$hcx:expr, $result:expr]) => {{
-        dep_graph::hash_result($hcx, &$result)
+    ([]) => {{
+        Some(dep_graph::hash_result)
     }};
-    ([(no_hash) $($rest:tt)*][$hcx:expr, $result:expr]) => {{
+    ([(no_hash) $($rest:tt)*]) => {{
         None
     }};
+    ([$other:tt $($modifiers:tt)*]) => {
+        hash_result!([$($modifiers)*])
+    };
+}
+
+macro_rules! get_provider {
+    ([][$tcx:expr, $name:ident, $key:expr]) => {{
+        $tcx.queries.local_providers.$name
+    }};
+    ([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{
+        if $key.query_crate_is_local() {
+            $tcx.queries.local_providers.$name
+        } else {
+            $tcx.queries.extern_providers.$name
+        }
+    }};
     ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
-        hash_result!([$($modifiers)*][$($args)*])
+        get_provider!([$($modifiers)*][$($args)*])
     };
 }
 
@@ -374,10 +303,8 @@ pub mod queries {
             const NAME: &'static str = stringify!($name);
         }
 
-        impl<$tcx> QueryAccessors<QueryCtxt<$tcx>> for queries::$name<$tcx> {
-            const ANON: bool = is_anon!([$($modifiers)*]);
-            const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
-            const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$name;
+        impl<$tcx> QueryDescription<QueryCtxt<$tcx>> for queries::$name<$tcx> {
+            rustc_query_description! { $name<$tcx> }
 
             type Cache = query_storage::$name<$tcx>;
 
@@ -396,32 +323,25 @@ fn query_cache<'a>(tcx: QueryCtxt<$tcx>) -> &'a QueryCacheStore<Self::Cache>
             }
 
             #[inline]
-            fn compute_fn(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
-                fn(TyCtxt<'tcx>, Self::Key) -> Self::Value
+            fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
+                QueryVtable<QueryCtxt<$tcx>, Self::Key, Self::Value>
             {
-                if key.query_crate_is_local() {
-                    tcx.queries.local_providers.$name
-                } else {
-                    tcx.queries.extern_providers.$name
+                let compute = get_provider!([$($modifiers)*][tcx, $name, key]);
+                let cache_on_disk = Self::cache_on_disk(tcx.tcx, key);
+                QueryVtable {
+                    anon: is_anon!([$($modifiers)*]),
+                    eval_always: is_eval_always!([$($modifiers)*]),
+                    dep_kind: dep_graph::DepKind::$name,
+                    hash_result: hash_result!([$($modifiers)*]),
+                    handle_cycle_error: |tcx, mut error| handle_cycle_error!([$($modifiers)*][tcx, error]),
+                    compute,
+                    cache_on_disk,
+                    try_load_from_disk: Self::TRY_LOAD_FROM_DISK,
                 }
             }
-
-            fn hash_result(
-                _hcx: &mut StableHashingContext<'_>,
-                _result: &Self::Value
-            ) -> Option<Fingerprint> {
-                hash_result!([$($modifiers)*][_hcx, _result])
-            }
-
-            fn handle_cycle_error(
-                tcx: QueryCtxt<'tcx>,
-                mut error: DiagnosticBuilder<'_>,
-            ) -> Self::Value {
-                handle_cycle_error!([$($modifiers)*][tcx, error])
-            }
         })*
 
-        #[allow(non_upper_case_globals)]
+        #[allow(nonstandard_style)]
         pub mod query_callbacks {
             use super::*;
             use rustc_middle::dep_graph::DepNode;
@@ -431,68 +351,100 @@ pub mod query_callbacks {
             use rustc_query_system::dep_graph::FingerprintStyle;
 
             // We use this for most things when incr. comp. is turned off.
-            pub const Null: QueryStruct = QueryStruct {
-                force_from_dep_node: |_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node),
-                try_load_from_on_disk_cache: |_, _| {},
-            };
+            pub fn Null() -> DepKindStruct {
+                DepKindStruct {
+                    is_anon: false,
+                    is_eval_always: false,
+                    fingerprint_style: FingerprintStyle::Unit,
+                    force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)),
+                    try_load_from_on_disk_cache: None,
+                }
+            }
 
-            pub const TraitSelect: QueryStruct = QueryStruct {
-                force_from_dep_node: |_, _| false,
-                try_load_from_on_disk_cache: |_, _| {},
-            };
+            pub fn TraitSelect() -> DepKindStruct {
+                DepKindStruct {
+                    is_anon: true,
+                    is_eval_always: false,
+                    fingerprint_style: FingerprintStyle::Unit,
+                    force_from_dep_node: None,
+                    try_load_from_on_disk_cache: None,
+                }
+            }
 
-            pub const CompileCodegenUnit: QueryStruct = QueryStruct {
-                force_from_dep_node: |_, _| false,
-                try_load_from_on_disk_cache: |_, _| {},
-            };
+            pub fn CompileCodegenUnit() -> DepKindStruct {
+                DepKindStruct {
+                    is_anon: false,
+                    is_eval_always: false,
+                    fingerprint_style: FingerprintStyle::Opaque,
+                    force_from_dep_node: None,
+                    try_load_from_on_disk_cache: None,
+                }
+            }
 
-            pub const CompileMonoItem: QueryStruct = QueryStruct {
-                force_from_dep_node: |_, _| false,
-                try_load_from_on_disk_cache: |_, _| {},
-            };
+            pub fn CompileMonoItem() -> DepKindStruct {
+                DepKindStruct {
+                    is_anon: false,
+                    is_eval_always: false,
+                    fingerprint_style: FingerprintStyle::Opaque,
+                    force_from_dep_node: None,
+                    try_load_from_on_disk_cache: None,
+                }
+            }
 
-            $(pub const $name: QueryStruct = {
-                const is_anon: bool = is_anon!([$($modifiers)*]);
+            $(pub fn $name()-> DepKindStruct {
+                let is_anon = is_anon!([$($modifiers)*]);
+                let is_eval_always = is_eval_always!([$($modifiers)*]);
 
-                #[inline(always)]
-                fn fingerprint_style() -> FingerprintStyle {
-                    <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>
-                        ::fingerprint_style()
-                }
+                let fingerprint_style =
+                    <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::fingerprint_style();
 
-                fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<query_keys::$name<'tcx>> {
-                    <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node)
+                if is_anon || !fingerprint_style.reconstructible() {
+                    return DepKindStruct {
+                        is_anon,
+                        is_eval_always,
+                        fingerprint_style,
+                        force_from_dep_node: None,
+                        try_load_from_on_disk_cache: None,
+                    }
                 }
 
-                fn force_from_dep_node(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool {
-                    force_query::<queries::$name<'_>, _>(tcx, dep_node)
+                #[inline(always)]
+                fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> Option<query_keys::$name<'tcx>> {
+                    <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, &dep_node)
                 }
 
-                fn try_load_from_on_disk_cache(tcx: QueryCtxt<'_>, dep_node: &DepNode) {
-                    if is_anon {
-                        return
-                    }
-
-                    if !fingerprint_style().reconstructible() {
-                        return
+                fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool {
+                    if let Some(key) = recover(tcx, dep_node) {
+                        let tcx = QueryCtxt::from_tcx(tcx);
+                        force_query::<queries::$name<'_>, _>(tcx, key, dep_node);
+                        true
+                    } else {
+                        false
                     }
+                }
 
-                    debug_assert!(tcx.dep_graph.is_green(dep_node));
+                fn try_load_from_on_disk_cache(tcx: TyCtxt<'_>, dep_node: DepNode) {
+                    debug_assert!(tcx.dep_graph.is_green(&dep_node));
 
-                    let key = recover(*tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
-                    if queries::$name::cache_on_disk(tcx, &key, None) {
+                    let key = recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
+                    if queries::$name::cache_on_disk(tcx, &key) {
                         let _ = tcx.$name(key);
                     }
                 }
 
-                QueryStruct {
-                    force_from_dep_node,
-                    try_load_from_on_disk_cache,
+                DepKindStruct {
+                    is_anon,
+                    is_eval_always,
+                    fingerprint_style,
+                    force_from_dep_node: Some(force_from_dep_node),
+                    try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache),
                 }
-            };)*
+            })*
         }
 
-        static QUERY_CALLBACKS: &[QueryStruct] = &make_dep_kind_array!(query_callbacks);
+        pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct] {
+            arena.alloc_from_iter(make_dep_kind_array!(query_callbacks))
+        }
     }
 }
 
@@ -504,7 +456,7 @@ macro_rules! define_queries_struct {
      input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => {
         pub struct Queries<$tcx> {
             local_providers: Box<Providers>,
-            extern_providers: Box<Providers>,
+            extern_providers: Box<ExternProviders>,
 
             pub on_disk_cache: Option<OnDiskCache<$tcx>>,
 
@@ -517,7 +469,7 @@ pub struct Queries<$tcx> {
         impl<$tcx> Queries<$tcx> {
             pub fn new(
                 local_providers: Providers,
-                extern_providers: Providers,
+                extern_providers: ExternProviders,
                 on_disk_cache: Option<OnDiskCache<$tcx>>,
             ) -> Self {
                 Queries {
@@ -575,13 +527,3 @@ fn $name(
         }
     };
 }
-
-fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
-    if def_id.is_top_level_module() {
-        "top-level module".to_string()
-    } else {
-        format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
-    }
-}
-
-rustc_query_description! {}
index 8602219a7f32fd85453cc35827c17daf5d061ca3..c274c2cc26c157008ee9b7eec3d207564cfd385c 100644 (file)
@@ -60,8 +60,11 @@ impl<K: DepKind> DepNode<K> {
     /// Creates a new, parameterless DepNode. This method will assert
     /// that the DepNode corresponding to the given DepKind actually
     /// does not require any parameters.
-    pub fn new_no_params(kind: K) -> DepNode<K> {
-        debug_assert!(!kind.has_params());
+    pub fn new_no_params<Ctxt>(tcx: Ctxt, kind: K) -> DepNode<K>
+    where
+        Ctxt: super::DepContext<DepKind = K>,
+    {
+        debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit);
         DepNode { kind, hash: Fingerprint::ZERO.into() }
     }
 
@@ -75,7 +78,7 @@ pub fn construct<Ctxt, Key>(tcx: Ctxt, kind: K, arg: &Key) -> DepNode<K>
 
         #[cfg(debug_assertions)]
         {
-            if !kind.fingerprint_style().reconstructible()
+            if !tcx.fingerprint_style(kind).reconstructible()
                 && (tcx.sess().opts.debugging_opts.incremental_info
                     || tcx.sess().opts.debugging_opts.query_dep_graph)
             {
@@ -121,11 +124,12 @@ impl<Ctxt: DepContext, T> DepNodeParams<Ctxt> for T
 where
     T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug,
 {
-    #[inline]
+    #[inline(always)]
     default fn fingerprint_style() -> FingerprintStyle {
         FingerprintStyle::Opaque
     }
 
+    #[inline(always)]
     default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint {
         let mut hcx = tcx.create_stable_hashing_context();
         let mut hasher = StableHasher::new();
@@ -135,10 +139,12 @@ impl<Ctxt: DepContext, T> DepNodeParams<Ctxt> for T
         hasher.finish()
     }
 
+    #[inline(always)]
     default fn to_debug_str(&self, _: Ctxt) -> String {
         format!("{:?}", *self)
     }
 
+    #[inline(always)]
     default fn recover(_: Ctxt, _: &DepNode<Ctxt::DepKind>) -> Option<Self> {
         None
     }
index 114d12fb90b0a875bf6e6d014597f654889dd4a3..a8be1ca34c04f0f0e8cd59a8777d90e15a6eae13 100644 (file)
@@ -33,12 +33,6 @@ pub struct DepGraph<K: DepKind> {
     /// each task has a `DepNodeIndex` that uniquely identifies it. This unique
     /// ID is used for self-profiling.
     virtual_dep_node_index: Lrc<AtomicU32>,
-
-    /// The cached event id for profiling node interning. This saves us
-    /// from having to look up the event id every time we intern a node
-    /// which may incur too much overhead.
-    /// This will be None if self-profiling is disabled.
-    node_intern_event_id: Option<EventId>,
 }
 
 rustc_index::newtype_index! {
@@ -96,14 +90,13 @@ struct DepGraphData<K: DepKind> {
     dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>,
 }
 
-pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Option<Fingerprint>
+pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint
 where
     R: for<'a> HashStable<StableHashingContext<'a>>,
 {
     let mut stable_hasher = StableHasher::new();
     result.hash_stable(hcx, &mut stable_hasher);
-
-    Some(stable_hasher.finish())
+    stable_hasher.finish()
 }
 
 impl<K: DepKind> DepGraph<K> {
@@ -117,8 +110,13 @@ pub fn new(
     ) -> DepGraph<K> {
         let prev_graph_node_count = prev_graph.node_count();
 
-        let current =
-            CurrentDepGraph::new(prev_graph_node_count, encoder, record_graph, record_stats);
+        let current = CurrentDepGraph::new(
+            profiler,
+            prev_graph_node_count,
+            encoder,
+            record_graph,
+            record_stats,
+        );
 
         // Instantiate a dependy-less node only once for anonymous queries.
         let _green_node_index = current.intern_new_node(
@@ -129,10 +127,6 @@ pub fn new(
         );
         debug_assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
 
-        let node_intern_event_id = profiler
-            .get_or_alloc_cached_string("incr_comp_intern_dep_graph_node")
-            .map(EventId::from_label);
-
         DepGraph {
             data: Some(Lrc::new(DepGraphData {
                 previous_work_products: prev_work_products,
@@ -143,16 +137,11 @@ pub fn new(
                 colors: DepNodeColorMap::new(prev_graph_node_count),
             })),
             virtual_dep_node_index: Lrc::new(AtomicU32::new(0)),
-            node_intern_event_id,
         }
     }
 
     pub fn new_disabled() -> DepGraph<K> {
-        DepGraph {
-            data: None,
-            virtual_dep_node_index: Lrc::new(AtomicU32::new(0)),
-            node_intern_event_id: None,
-        }
+        DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) }
     }
 
     /// Returns `true` if we are actually building the full dep-graph, and `false` otherwise.
@@ -215,7 +204,7 @@ pub fn with_task<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
         cx: Ctxt,
         arg: A,
         task: fn(Ctxt, A) -> R,
-        hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
+        hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
     ) -> (R, DepNodeIndex) {
         if self.is_fully_enabled() {
             self.with_task_impl(key, cx, arg, task, hash_result)
@@ -234,7 +223,7 @@ fn with_task_impl<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
         cx: Ctxt,
         arg: A,
         task: fn(Ctxt, A) -> R,
-        hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
+        hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
     ) -> (R, DepNodeIndex) {
         // This function is only called when the graph is enabled.
         let data = self.data.as_ref().unwrap();
@@ -253,7 +242,7 @@ fn with_task_impl<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
             key
         );
 
-        let task_deps = if key.kind.is_eval_always() {
+        let task_deps = if cx.dep_context().is_eval_always(key.kind) {
             None
         } else {
             Some(Lock::new(TaskDeps {
@@ -268,15 +257,14 @@ fn with_task_impl<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
         let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads);
 
         let dcx = cx.dep_context();
-        let mut hcx = dcx.create_stable_hashing_context();
         let hashing_timer = dcx.profiler().incr_result_hashing();
-        let current_fingerprint = hash_result(&mut hcx, &result);
+        let current_fingerprint = hash_result.map(|f| {
+            let mut hcx = dcx.create_stable_hashing_context();
+            f(&mut hcx, &result)
+        });
 
         let print_status = cfg!(debug_assertions) && dcx.sess().opts.debugging_opts.dep_tasks;
 
-        // Get timer for profiling `DepNode` interning
-        let node_intern_timer =
-            self.node_intern_event_id.map(|eid| dcx.profiler().generic_activity_with_event_id(eid));
         // Intern the new `DepNode`.
         let (dep_node_index, prev_and_color) = data.current.intern_node(
             dcx.profiler(),
@@ -286,7 +274,6 @@ fn with_task_impl<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
             current_fingerprint,
             print_status,
         );
-        drop(node_intern_timer);
 
         hashing_timer.finish_with_query_invocation_id(dep_node_index.into());
 
@@ -315,7 +302,7 @@ pub fn with_anon_task<Ctxt: DepContext<DepKind = K>, OP, R>(
     where
         OP: FnOnce() -> R,
     {
-        debug_assert!(!dep_kind.is_eval_always());
+        debug_assert!(!cx.is_eval_always(dep_kind));
 
         if let Some(ref data) = self.data {
             let task_deps = Lock::new(TaskDeps::default());
@@ -492,7 +479,7 @@ pub fn try_mark_green<Ctxt: QueryContext<DepKind = K>>(
         tcx: Ctxt,
         dep_node: &DepNode<K>,
     ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
-        debug_assert!(!dep_node.kind.is_eval_always());
+        debug_assert!(!tcx.dep_context().is_eval_always(dep_node.kind));
 
         // Return None if the dep graph is disabled
         let data = self.data.as_ref()?;
@@ -552,7 +539,7 @@ fn try_mark_parent_green<Ctxt: QueryContext<DepKind = K>>(
 
         // We don't know the state of this dependency. If it isn't
         // an eval_always node, let's try to mark it green recursively.
-        if !dep_dep_node.kind.is_eval_always() {
+        if !tcx.dep_context().is_eval_always(dep_dep_node.kind) {
             debug!(
                 "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \
                                  is unknown, trying to mark it green",
@@ -575,7 +562,7 @@ fn try_mark_parent_green<Ctxt: QueryContext<DepKind = K>>(
             "try_mark_previous_green({:?}) --- trying to force dependency {:?}",
             dep_node, dep_dep_node
         );
-        if !tcx.try_force_from_dep_node(dep_dep_node) {
+        if !tcx.dep_context().try_force_from_dep_node(*dep_dep_node) {
             // The DepNode could not be forced.
             debug!(
                 "try_mark_previous_green({:?}) - END - dependency {:?} could not be forced",
@@ -642,7 +629,7 @@ fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>(
         }
 
         // We never try to mark eval_always nodes as green
-        debug_assert!(!dep_node.kind.is_eval_always());
+        debug_assert!(!tcx.dep_context().is_eval_always(dep_node.kind));
 
         debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node);
 
@@ -740,8 +727,7 @@ pub fn is_green(&self, dep_node: &DepNode<K>) -> bool {
     //
     // This method will only load queries that will end up in the disk cache.
     // Other queries will not be executed.
-    pub fn exec_cache_promotions<Ctxt: QueryContext<DepKind = K>>(&self, qcx: Ctxt) {
-        let tcx = qcx.dep_context();
+    pub fn exec_cache_promotions<Ctxt: DepContext<DepKind = K>>(&self, tcx: Ctxt) {
         let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion");
 
         let data = self.data.as_ref().unwrap();
@@ -749,7 +735,7 @@ pub fn exec_cache_promotions<Ctxt: QueryContext<DepKind = K>>(&self, qcx: Ctxt)
             match data.colors.get(prev_index) {
                 Some(DepNodeColor::Green(_)) => {
                     let dep_node = data.previous.index_to_node(prev_index);
-                    qcx.try_load_from_on_disk_cache(&dep_node);
+                    tcx.try_load_from_on_disk_cache(dep_node);
                 }
                 None | Some(DepNodeColor::Red) => {
                     // We can skip red nodes because a node can only be marked
@@ -876,10 +862,17 @@ pub(super) struct CurrentDepGraph<K: DepKind> {
     /// debugging and only active with `debug_assertions`.
     total_read_count: AtomicU64,
     total_duplicate_read_count: AtomicU64,
+
+    /// The cached event id for profiling node interning. This saves us
+    /// from having to look up the event id every time we intern a node
+    /// which may incur too much overhead.
+    /// This will be None if self-profiling is disabled.
+    node_intern_event_id: Option<EventId>,
 }
 
 impl<K: DepKind> CurrentDepGraph<K> {
     fn new(
+        profiler: &SelfProfilerRef,
         prev_graph_node_count: usize,
         encoder: FileEncoder,
         record_graph: bool,
@@ -908,6 +901,10 @@ fn new(
 
         let new_node_count_estimate = 102 * prev_graph_node_count / 100 + 200;
 
+        let node_intern_event_id = profiler
+            .get_or_alloc_cached_string("incr_comp_intern_dep_graph_node")
+            .map(EventId::from_label);
+
         CurrentDepGraph {
             encoder: Steal::new(GraphEncoder::new(
                 encoder,
@@ -927,6 +924,7 @@ fn new(
             forbidden_edge,
             total_read_count: AtomicU64::new(0),
             total_duplicate_read_count: AtomicU64::new(0),
+            node_intern_event_id,
         }
     }
 
@@ -970,6 +968,10 @@ fn intern_node(
     ) -> (DepNodeIndex, Option<(SerializedDepNodeIndex, DepNodeColor)>) {
         let print_status = cfg!(debug_assertions) && print_status;
 
+        // Get timer for profiling `DepNode` interning
+        let _node_intern_timer =
+            self.node_intern_event_id.map(|eid| profiler.generic_activity_with_event_id(eid));
+
         if let Some(prev_index) = prev_graph.node_to_index_opt(&key) {
             // Determine the color and index of the new `DepNode`.
             if let Some(fingerprint) = fingerprint {
index dcda5728334f2eface4a1f14fdfd5d4351993587..047fc9f10cc2f0e1e7e61e3fa4190400186b6ae0 100644 (file)
@@ -32,6 +32,17 @@ pub trait DepContext: Copy {
 
     /// Access the compiler session.
     fn sess(&self) -> &Session;
+
+    /// Return whether this kind always require evaluation.
+    fn is_eval_always(&self, kind: Self::DepKind) -> bool;
+
+    fn fingerprint_style(&self, kind: Self::DepKind) -> FingerprintStyle;
+
+    /// Try to force a dep node to execute and see if it's green.
+    fn try_force_from_dep_node(&self, dep_node: DepNode<Self::DepKind>) -> bool;
+
+    /// Load data from the on-disk cache.
+    fn try_load_from_on_disk_cache(&self, dep_node: DepNode<Self::DepKind>);
 }
 
 pub trait HasDepContext: Copy {
@@ -51,7 +62,7 @@ fn dep_context(&self) -> &Self::DepContext {
 }
 
 /// Describes the contents of the fingerprint generated by a given query.
-#[derive(PartialEq, Eq, Copy, Clone)]
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
 pub enum FingerprintStyle {
     /// The fingerprint is actually a DefPathHash.
     DefPathHash,
@@ -75,12 +86,6 @@ pub fn reconstructible(self) -> bool {
 pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> + 'static {
     const NULL: Self;
 
-    /// Return whether this kind always require evaluation.
-    fn is_eval_always(&self) -> bool;
-
-    /// Return whether this kind requires additional parameters to be executed.
-    fn has_params(&self) -> bool;
-
     /// Implementation of `std::fmt::Debug` for `DepNode`.
     fn debug_node(node: &DepNode<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
 
@@ -93,6 +98,4 @@ fn with_deps<OP, R>(deps: Option<&Lock<TaskDeps<Self>>>, op: OP) -> R
     fn read_deps<OP>(op: OP)
     where
         OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>);
-
-    fn fingerprint_style(&self) -> FingerprintStyle;
 }
index f5f67fcd0a08c322d3daca93e7ac299ef55a8ed4..47197a1e492a3d5901105c3894beeddac96cf6d5 100644 (file)
@@ -222,7 +222,7 @@ fn encode_node(
         index
     }
 
-    fn finish(self) -> FileEncodeResult {
+    fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult {
         let Self { mut encoder, total_node_count, total_edge_count, result, stats: _ } = self;
         let () = result?;
 
@@ -235,7 +235,11 @@ fn finish(self) -> FileEncodeResult {
         IntEncodedWithFixedSize(edge_count).encode(&mut encoder)?;
         debug!("position: {:?}", encoder.position());
         // Drop the encoder so that nothing is written after the counts.
-        encoder.flush()
+        let result = encoder.flush();
+        // FIXME(rylev): we hardcode the dep graph file name so we don't need a dependency on
+        // rustc_incremental just for that.
+        profiler.artifact_size("dep_graph", "dep-graph.bin", encoder.position() as u64);
+        result
     }
 }
 
@@ -332,6 +336,6 @@ pub(crate) fn send(
 
     pub fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult {
         let _prof_timer = profiler.generic_activity("incr_comp_encode_dep_graph");
-        self.status.into_inner().finish()
+        self.status.into_inner().finish(profiler)
     }
 }
index f2e935c59fce282f119d2c41ca79370c18ad08dd..5f31fa04b8a6e1c099a846cf76a28ffa09462e65 100644 (file)
@@ -1,6 +1,7 @@
 use crate::ich;
 use rustc_ast as ast;
 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::sync::Lrc;
 use rustc_hir as hir;
@@ -27,7 +28,6 @@ pub struct StableHashingContext<'a> {
     cstore: &'a dyn CrateStore,
     pub(super) body_resolver: BodyResolver<'a>,
     hash_spans: bool,
-    hash_bodies: bool,
     pub(super) node_id_hashing_mode: NodeIdHashingMode,
 
     // Very often, we are hashing something that does not need the
@@ -46,24 +46,19 @@ pub enum NodeIdHashingMode {
 /// We could also just store a plain reference to the `hir::Crate` but we want
 /// to avoid that the crate is used to get untracked access to all of the HIR.
 #[derive(Clone, Copy)]
-pub(super) struct BodyResolver<'tcx>(&'tcx hir::Crate<'tcx>);
-
-impl<'tcx> BodyResolver<'tcx> {
-    /// Returns a reference to the `hir::Body` with the given `BodyId`.
-    /// **Does not do any tracking**; use carefully.
-    pub(super) fn body(self, id: hir::BodyId) -> &'tcx hir::Body<'tcx> {
-        self.0.body(id)
-    }
+pub(super) enum BodyResolver<'tcx> {
+    Forbidden,
+    Traverse {
+        hash_bodies: bool,
+        owner: LocalDefId,
+        bodies: &'tcx SortedMap<hir::ItemLocalId, &'tcx hir::Body<'tcx>>,
+    },
 }
 
 impl<'a> StableHashingContext<'a> {
-    /// The `krate` here is only used for mapping `BodyId`s to `Body`s.
-    /// Don't use it for anything else or you'll run the risk of
-    /// leaking data out of the tracking system.
     #[inline]
     fn new_with_or_without_spans(
         sess: &'a Session,
-        krate: &'a hir::Crate<'a>,
         definitions: &'a Definitions,
         cstore: &'a dyn CrateStore,
         always_ignore_spans: bool,
@@ -72,13 +67,12 @@ fn new_with_or_without_spans(
             !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans;
 
         StableHashingContext {
-            body_resolver: BodyResolver(krate),
+            body_resolver: BodyResolver::Forbidden,
             definitions,
             cstore,
             caching_source_map: None,
             raw_source_map: sess.source_map(),
             hash_spans: hash_spans_initial,
-            hash_bodies: true,
             node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
         }
     }
@@ -86,13 +80,11 @@ fn new_with_or_without_spans(
     #[inline]
     pub fn new(
         sess: &'a Session,
-        krate: &'a hir::Crate<'a>,
         definitions: &'a Definitions,
         cstore: &'a dyn CrateStore,
     ) -> Self {
         Self::new_with_or_without_spans(
             sess,
-            krate,
             definitions,
             cstore,
             /*always_ignore_spans=*/ false,
@@ -102,20 +94,41 @@ pub fn new(
     #[inline]
     pub fn ignore_spans(
         sess: &'a Session,
-        krate: &'a hir::Crate<'a>,
         definitions: &'a Definitions,
         cstore: &'a dyn CrateStore,
     ) -> Self {
         let always_ignore_spans = true;
-        Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans)
+        Self::new_with_or_without_spans(sess, definitions, cstore, always_ignore_spans)
     }
 
+    /// Allow hashing
     #[inline]
-    pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self, hash_bodies: bool, f: F) {
-        let prev_hash_bodies = self.hash_bodies;
-        self.hash_bodies = hash_bodies;
+    pub fn while_hashing_hir_bodies(&mut self, hb: bool, f: impl FnOnce(&mut Self)) {
+        let prev = match &mut self.body_resolver {
+            BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."),
+            BodyResolver::Traverse { ref mut hash_bodies, .. } => {
+                std::mem::replace(hash_bodies, hb)
+            }
+        };
         f(self);
-        self.hash_bodies = prev_hash_bodies;
+        match &mut self.body_resolver {
+            BodyResolver::Forbidden => unreachable!(),
+            BodyResolver::Traverse { ref mut hash_bodies, .. } => *hash_bodies = prev,
+        }
+    }
+
+    #[inline]
+    pub fn with_hir_bodies(
+        &mut self,
+        hash_bodies: bool,
+        owner: LocalDefId,
+        bodies: &'a SortedMap<hir::ItemLocalId, &'a hir::Body<'a>>,
+        f: impl FnOnce(&mut Self),
+    ) {
+        let prev = self.body_resolver;
+        self.body_resolver = BodyResolver::Traverse { hash_bodies, owner, bodies };
+        f(self);
+        self.body_resolver = prev;
     }
 
     #[inline]
@@ -152,11 +165,6 @@ pub fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash {
         self.definitions.def_path_hash(def_id)
     }
 
-    #[inline]
-    pub fn hash_bodies(&self) -> bool {
-        self.hash_bodies
-    }
-
     #[inline]
     pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
         match self.caching_source_map {
index 04eb263a977187536acabe3a01a8bc25e6e222a2..3a0aab81fdb7b257b32908ba0aaf26482bc8195e 100644 (file)
@@ -1,12 +1,11 @@
 //! This module contains `HashStable` implementations for various HIR data
 //! types in no particular order.
 
+use crate::ich::hcx::BodyResolver;
 use crate::ich::{NodeIdHashingMode, StableHashingContext};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 use rustc_hir as hir;
-use rustc_hir::definitions::DefPathHash;
-use smallvec::SmallVec;
 use std::mem;
 
 impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
@@ -29,8 +28,13 @@ fn hash_hir_id(&mut self, hir_id: hir::HirId, hasher: &mut StableHasher) {
     #[inline]
     fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) {
         let hcx = self;
-        if hcx.hash_bodies() {
-            hcx.body_resolver.body(id).hash_stable(hcx, hasher);
+        match hcx.body_resolver {
+            BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."),
+            BodyResolver::Traverse { hash_bodies: false, .. } => {}
+            BodyResolver::Traverse { hash_bodies: true, owner, bodies } => {
+                assert_eq!(id.hir_id.owner, owner);
+                bodies[&id.hir_id.local_id].hash_stable(hcx, hasher);
+            }
         }
     }
 
@@ -115,6 +119,16 @@ fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F) {
 
         self.node_id_hashing_mode = prev_hash_node_ids;
     }
+
+    #[inline]
+    fn hash_hir_trait_candidate(&mut self, tc: &hir::TraitCandidate, hasher: &mut StableHasher) {
+        self.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            let hir::TraitCandidate { def_id, import_ids } = tc;
+
+            def_id.hash_stable(hcx, hasher);
+            import_ids.hash_stable(hcx, hasher);
+        });
+    }
 }
 
 impl<'a> HashStable<StableHashingContext<'a>> for hir::Body<'_> {
@@ -129,27 +143,3 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
         });
     }
 }
-
-impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitCandidate {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-            let hir::TraitCandidate { def_id, import_ids } = self;
-
-            def_id.hash_stable(hcx, hasher);
-            import_ids.hash_stable(hcx, hasher);
-        });
-    }
-}
-
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate {
-    type KeyType = (DefPathHash, SmallVec<[DefPathHash; 1]>);
-
-    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType {
-        let hir::TraitCandidate { def_id, import_ids } = self;
-
-        (
-            hcx.def_path_hash(*def_id),
-            import_ids.iter().map(|def_id| hcx.local_def_path_hash(*def_id)).collect(),
-        )
-    }
-}
index bc23de069b0d9fdbccf830ce8736ed644b0b84ed..1b992cdb0c94b2f0a3fbc7c491aa3bfc2fecff08 100644 (file)
@@ -3,6 +3,7 @@
 #![feature(core_intrinsics)]
 #![feature(hash_raw_entry)]
 #![feature(iter_zip)]
+#![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(thread_local_const_init)]
 
index 76a165ed8e6bcc482b6b5c52e040e976cb040411..d2b102b6f89681358bca92bfb1cd9b3bf8d53b87 100644 (file)
@@ -19,15 +19,16 @@ pub trait QueryConfig {
     type Stored: Clone;
 }
 
-pub(crate) struct QueryVtable<CTX: QueryContext, K, V> {
+pub struct QueryVtable<CTX: QueryContext, K, V> {
     pub anon: bool,
     pub dep_kind: CTX::DepKind,
     pub eval_always: bool,
+    pub cache_on_disk: bool,
 
-    pub hash_result: fn(&mut StableHashingContext<'_>, &V) -> Option<Fingerprint>,
+    pub compute: fn(CTX::DepContext, K) -> V,
+    pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
     pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V,
-    pub cache_on_disk: fn(CTX, &K, Option<&V>) -> bool,
-    pub try_load_from_disk: fn(CTX, SerializedDepNodeIndex) -> Option<V>,
+    pub try_load_from_disk: Option<fn(CTX, SerializedDepNodeIndex) -> Option<V>>,
 }
 
 impl<CTX: QueryContext, K, V> QueryVtable<CTX, K, V> {
@@ -38,30 +39,25 @@ pub(crate) fn to_dep_node(&self, tcx: CTX::DepContext, key: &K) -> DepNode<CTX::
         DepNode::construct(tcx, self.dep_kind, key)
     }
 
-    pub(crate) fn hash_result(
-        &self,
-        hcx: &mut StableHashingContext<'_>,
-        value: &V,
-    ) -> Option<Fingerprint> {
-        (self.hash_result)(hcx, value)
-    }
-
-    pub(crate) fn cache_on_disk(&self, tcx: CTX, key: &K, value: Option<&V>) -> bool {
-        (self.cache_on_disk)(tcx, key, value)
+    pub(crate) fn compute(&self, tcx: CTX::DepContext, key: K) -> V {
+        (self.compute)(tcx, key)
     }
 
     pub(crate) fn try_load_from_disk(&self, tcx: CTX, index: SerializedDepNodeIndex) -> Option<V> {
-        (self.try_load_from_disk)(tcx, index)
+        self.try_load_from_disk
+            .expect("QueryDescription::load_from_disk() called for an unsupported query.")(
+            tcx, index,
+        )
     }
 }
 
-pub trait QueryAccessors<CTX: QueryContext>: QueryConfig {
-    const ANON: bool;
-    const EVAL_ALWAYS: bool;
-    const DEP_KIND: CTX::DepKind;
+pub trait QueryDescription<CTX: QueryContext>: QueryConfig {
+    const TRY_LOAD_FROM_DISK: Option<fn(CTX, SerializedDepNodeIndex) -> Option<Self::Value>>;
 
     type Cache: QueryCache<Key = Self::Key, Stored = Self::Stored, Value = Self::Value>;
 
+    fn describe(tcx: CTX, key: Self::Key) -> String;
+
     // Don't use this method to access query results, instead use the methods on TyCtxt
     fn query_state<'a>(tcx: CTX) -> &'a QueryState<CTX::DepKind, Self::Key>
     where
@@ -73,43 +69,7 @@ fn query_cache<'a>(tcx: CTX) -> &'a QueryCacheStore<Self::Cache>
         CTX: 'a;
 
     // Don't use this method to compute query results, instead use the methods on TyCtxt
-    fn compute_fn(tcx: CTX, key: &Self::Key) -> fn(CTX::DepContext, Self::Key) -> Self::Value;
-
-    fn hash_result(hcx: &mut StableHashingContext<'_>, result: &Self::Value)
-    -> Option<Fingerprint>;
-
-    fn handle_cycle_error(tcx: CTX, diag: DiagnosticBuilder<'_>) -> Self::Value;
-}
-
-pub trait QueryDescription<CTX: QueryContext>: QueryAccessors<CTX> {
-    fn describe(tcx: CTX, key: Self::Key) -> String;
-
-    #[inline]
-    fn cache_on_disk(_: CTX, _: &Self::Key, _: Option<&Self::Value>) -> bool {
-        false
-    }
-
-    fn try_load_from_disk(_: CTX, _: SerializedDepNodeIndex) -> Option<Self::Value> {
-        panic!("QueryDescription::load_from_disk() called for an unsupported query.")
-    }
-}
-
-pub(crate) trait QueryVtableExt<CTX: QueryContext, K, V> {
-    const VTABLE: QueryVtable<CTX, K, V>;
-}
+    fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVtable<CTX, Self::Key, Self::Value>;
 
-impl<CTX, Q> QueryVtableExt<CTX, Q::Key, Q::Value> for Q
-where
-    CTX: QueryContext,
-    Q: QueryDescription<CTX>,
-{
-    const VTABLE: QueryVtable<CTX, Q::Key, Q::Value> = QueryVtable {
-        anon: Q::ANON,
-        dep_kind: Q::DEP_KIND,
-        eval_always: Q::EVAL_ALWAYS,
-        hash_result: Q::hash_result,
-        handle_cycle_error: Q::handle_cycle_error,
-        cache_on_disk: Q::cache_on_disk,
-        try_load_from_disk: Q::try_load_from_disk,
-    };
+    fn cache_on_disk(tcx: CTX::DepContext, key: &Self::Key) -> bool;
 }
index 98b2a450b19df73ff34e53d5e0078d580ea19b04..bd67303099220e39ee508d2e855ad8cdc1ea7ab3 100644 (file)
@@ -644,9 +644,7 @@ pub fn print_query_stack<CTX: QueryContext>(
         if Some(i) == num_frames {
             break;
         }
-        let query_info = if let Some(info) = query_map.as_ref().and_then(|map| map.get(&query)) {
-            info
-        } else {
+        let Some(query_info) = query_map.as_ref().and_then(|map| map.get(&query)) else {
             break;
         };
         let mut diag = Diagnostic::new(
index dffe7f3689ff4b52f80c4ff8af04b823a29bd9db..a2f7843baaa680b2c1b52cf679646d470102f0ae 100644 (file)
@@ -12,9 +12,9 @@
 };
 
 mod config;
-pub use self::config::{QueryAccessors, QueryConfig, QueryDescription};
+pub use self::config::{QueryConfig, QueryDescription, QueryVtable};
 
-use crate::dep_graph::{DepNode, DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
+use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
 
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::thin_vec::ThinVec;
@@ -122,12 +122,6 @@ pub trait QueryContext: HasDepContext {
 
     fn try_collect_active_jobs(&self) -> Option<QueryMap<Self::DepKind>>;
 
-    /// Load data from the on-disk cache.
-    fn try_load_from_on_disk_cache(&self, dep_node: &DepNode<Self::DepKind>);
-
-    /// Try to force a dep node to execute and see if it's green.
-    fn try_force_from_dep_node(&self, dep_node: &DepNode<Self::DepKind>) -> bool;
-
     /// Load side effects associated to the node in the previous session.
     fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects;
 
index 07d720599759607a25ee5f4c68df663f00c6fc39..238b92a61342b451ce842a09e46a8fc925a00de2 100644 (file)
@@ -2,9 +2,9 @@
 //! generate the actual methods on tcx which find and execute the provider,
 //! manage the caches, and so forth.
 
-use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams};
+use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams};
 use crate::query::caches::QueryCache;
-use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt};
+use crate::query::config::{QueryDescription, QueryVtable};
 use crate::query::job::{
     report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId,
 };
@@ -382,7 +382,6 @@ fn try_execute_query<CTX, C>(
     lookup: QueryLookup,
     dep_node: Option<DepNode<CTX::DepKind>>,
     query: &QueryVtable<CTX, C::Key, C::Value>,
-    compute: fn(CTX::DepContext, C::Key) -> C::Value,
 ) -> (C::Stored, Option<DepNodeIndex>)
 where
     C: QueryCache,
@@ -398,7 +397,7 @@ fn try_execute_query<CTX, C>(
         query.dep_kind,
     ) {
         TryGetJob::NotYetStarted(job) => {
-            let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id, compute);
+            let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id);
             let result = job.complete(cache, result, dep_node_index);
             (result, Some(dep_node_index))
         }
@@ -429,7 +428,6 @@ fn execute_job<CTX, K, V>(
     mut dep_node_opt: Option<DepNode<CTX::DepKind>>,
     query: &QueryVtable<CTX, K, V>,
     job_id: QueryJobId<CTX::DepKind>,
-    compute: fn(CTX::DepContext, K) -> V,
 ) -> (V, DepNodeIndex)
 where
     K: Clone + DepNodeParams<CTX::DepContext>,
@@ -441,7 +439,7 @@ fn execute_job<CTX, K, V>(
     // Fast path for when incr. comp. is off.
     if !dep_graph.is_fully_enabled() {
         let prof_timer = tcx.dep_context().profiler().query_provider();
-        let result = tcx.start_query(job_id, None, || compute(*tcx.dep_context(), key));
+        let result = tcx.start_query(job_id, None, || query.compute(*tcx.dep_context(), key));
         let dep_node_index = dep_graph.next_virtual_depnode_index();
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
         return (result, dep_node_index);
@@ -455,7 +453,7 @@ fn execute_job<CTX, K, V>(
         // The diagnostics for this query will be promoted to the current session during
         // `try_mark_green()`, so we can ignore them here.
         if let Some(ret) = tcx.start_query(job_id, None, || {
-            try_load_from_disk_and_cache_in_memory(tcx, &key, &dep_node, query, compute)
+            try_load_from_disk_and_cache_in_memory(tcx, &key, &dep_node, query)
         }) {
             return ret;
         }
@@ -467,14 +465,14 @@ fn execute_job<CTX, K, V>(
     let (result, dep_node_index) = tcx.start_query(job_id, Some(&diagnostics), || {
         if query.anon {
             return dep_graph.with_anon_task(*tcx.dep_context(), query.dep_kind, || {
-                compute(*tcx.dep_context(), key)
+                query.compute(*tcx.dep_context(), key)
             });
         }
 
         // `to_dep_node` is expensive for some `DepKind`s.
         let dep_node = dep_node_opt.unwrap_or_else(|| query.to_dep_node(*tcx.dep_context(), &key));
 
-        dep_graph.with_task(dep_node, *tcx.dep_context(), key, compute, query.hash_result)
+        dep_graph.with_task(dep_node, *tcx.dep_context(), key, query.compute, query.hash_result)
     });
 
     prof_timer.finish_with_query_invocation_id(dep_node_index.into());
@@ -498,7 +496,6 @@ fn try_load_from_disk_and_cache_in_memory<CTX, K, V>(
     key: &K,
     dep_node: &DepNode<CTX::DepKind>,
     query: &QueryVtable<CTX, K, V>,
-    compute: fn(CTX::DepContext, K) -> V,
 ) -> Option<(V, DepNodeIndex)>
 where
     K: Clone,
@@ -515,19 +512,11 @@ fn try_load_from_disk_and_cache_in_memory<CTX, K, V>(
 
     // First we try to load the result from the on-disk cache.
     // Some things are never cached on disk.
-    if query.cache_on_disk(tcx, key, None) {
+    if query.cache_on_disk {
         let prof_timer = tcx.dep_context().profiler().incr_cache_loading();
         let result = query.try_load_from_disk(tcx, prev_dep_node_index);
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
-        // We always expect to find a cached result for things that
-        // can be forced from `DepNode`.
-        debug_assert!(
-            !dep_node.kind.fingerprint_style().reconstructible() || result.is_some(),
-            "missing on-disk cache entry for {:?}",
-            dep_node
-        );
-
         if let Some(result) = result {
             // If `-Zincremental-verify-ich` is specified, re-hash results from
             // the cache and make sure that they have the expected fingerprint.
@@ -537,6 +526,14 @@ fn try_load_from_disk_and_cache_in_memory<CTX, K, V>(
 
             return Some((result, dep_node_index));
         }
+
+        // We always expect to find a cached result for things that
+        // can be forced from `DepNode`.
+        debug_assert!(
+            !tcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(),
+            "missing on-disk cache entry for {:?}",
+            dep_node
+        );
     }
 
     // We could not load a result from the on-disk cache, so
@@ -544,7 +541,7 @@ fn try_load_from_disk_and_cache_in_memory<CTX, K, V>(
     let prof_timer = tcx.dep_context().profiler().query_provider();
 
     // The dep-graph for this computation is already in-place.
-    let result = dep_graph.with_ignore(|| compute(*tcx.dep_context(), key.clone()));
+    let result = dep_graph.with_ignore(|| query.compute(*tcx.dep_context(), key.clone()));
 
     prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
@@ -577,12 +574,12 @@ fn incremental_verify_ich<CTX, K, V: Debug>(
     );
 
     debug!("BEGIN verify_ich({:?})", dep_node);
-    let mut hcx = tcx.create_stable_hashing_context();
-
-    let new_hash = query.hash_result(&mut hcx, result).unwrap_or(Fingerprint::ZERO);
-    debug!("END verify_ich({:?})", dep_node);
-
+    let new_hash = query.hash_result.map_or(Fingerprint::ZERO, |f| {
+        let mut hcx = tcx.create_stable_hashing_context();
+        f(&mut hcx, result)
+    });
     let old_hash = tcx.dep_graph().prev_fingerprint_of(dep_node);
+    debug!("END verify_ich({:?})", dep_node);
 
     if Some(new_hash) != old_hash {
         let run_cmd = if let Some(crate_name) = &tcx.sess().opts.crate_name {
@@ -665,41 +662,6 @@ fn ensure_must_run<CTX, K, V>(
     }
 }
 
-#[inline(never)]
-fn force_query_impl<CTX, C>(
-    tcx: CTX,
-    state: &QueryState<CTX::DepKind, C::Key>,
-    cache: &QueryCacheStore<C>,
-    key: C::Key,
-    dep_node: DepNode<CTX::DepKind>,
-    query: &QueryVtable<CTX, C::Key, C::Value>,
-    compute: fn(CTX::DepContext, C::Key) -> C::Value,
-) -> bool
-where
-    C: QueryCache,
-    C::Key: DepNodeParams<CTX::DepContext>,
-    CTX: QueryContext,
-{
-    debug_assert!(!query.anon);
-
-    // We may be concurrently trying both execute and force a query.
-    // Ensure that only one of them runs the query.
-    let cached = cache.cache.lookup(cache, &key, |_, index| {
-        if unlikely!(tcx.dep_context().profiler().enabled()) {
-            tcx.dep_context().profiler().query_cache_hit(index.into());
-        }
-    });
-
-    let lookup = match cached {
-        Ok(()) => return true,
-        Err(lookup) => lookup,
-    };
-
-    let _ =
-        try_execute_query(tcx, state, cache, DUMMY_SP, key, lookup, Some(dep_node), query, compute);
-    true
-}
-
 pub enum QueryMode {
     Get,
     Ensure,
@@ -717,9 +679,9 @@ pub fn get_query<Q, CTX>(
     Q::Key: DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
-    let query = &Q::VTABLE;
+    let query = Q::make_vtable(tcx, &key);
     let dep_node = if let QueryMode::Ensure = mode {
-        let (must_run, dep_node) = ensure_must_run(tcx, &key, query);
+        let (must_run, dep_node) = ensure_must_run(tcx, &key, &query);
         if !must_run {
             return None;
         }
@@ -729,7 +691,6 @@ pub fn get_query<Q, CTX>(
     };
 
     debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span);
-    let compute = Q::compute_fn(tcx, &key);
     let (result, dep_node_index) = try_execute_query(
         tcx,
         Q::query_state(tcx),
@@ -738,8 +699,7 @@ pub fn get_query<Q, CTX>(
         key,
         lookup,
         dep_node,
-        query,
-        compute,
+        &query,
     );
     if let Some(dep_node_index) = dep_node_index {
         tcx.dep_context().dep_graph().read_index(dep_node_index)
@@ -747,36 +707,29 @@ pub fn get_query<Q, CTX>(
     Some(result)
 }
 
-pub fn force_query<Q, CTX>(tcx: CTX, dep_node: &DepNode<CTX::DepKind>) -> bool
+pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, dep_node: DepNode<CTX::DepKind>)
 where
     Q: QueryDescription<CTX>,
     Q::Key: DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
-    if Q::ANON {
-        return false;
-    }
-
-    if !<Q::Key as DepNodeParams<CTX::DepContext>>::fingerprint_style().reconstructible() {
-        return false;
-    }
+    // We may be concurrently trying both execute and force a query.
+    // Ensure that only one of them runs the query.
+    let cache = Q::query_cache(tcx);
+    let cached = cache.cache.lookup(cache, &key, |_, index| {
+        if unlikely!(tcx.dep_context().profiler().enabled()) {
+            tcx.dep_context().profiler().query_cache_hit(index.into());
+        }
+    });
 
-    let key = if let Some(key) =
-        <Q::Key as DepNodeParams<CTX::DepContext>>::recover(*tcx.dep_context(), &dep_node)
-    {
-        key
-    } else {
-        return false;
+    let lookup = match cached {
+        Ok(()) => return,
+        Err(lookup) => lookup,
     };
 
-    let compute = Q::compute_fn(tcx, &key);
-    force_query_impl(
-        tcx,
-        Q::query_state(tcx),
-        Q::query_cache(tcx),
-        key,
-        *dep_node,
-        &Q::VTABLE,
-        compute,
-    )
+    let query = Q::make_vtable(tcx, &key);
+    let state = Q::query_state(tcx);
+    debug_assert!(!query.anon);
+
+    try_execute_query(tcx, state, cache, DUMMY_SP, key, lookup, Some(dep_node), &query);
 }
index f1d3315d6e66a95d7eace650757eb4cc063a1823..bd27c16c732a9b11c74d7751b6d80a3bf6f0713c 100644 (file)
@@ -23,6 +23,7 @@ rustc_feature = { path = "../rustc_feature" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_metadata = { path = "../rustc_metadata" }
+rustc_query_system = { path = "../rustc_query_system" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
index 2a562a06cb3cdc001544b01959bca02811a4c7b5..33af9884cbb6686ced37c2729251fdb5094491e1 100644 (file)
@@ -145,17 +145,11 @@ pub fn expect_module(&mut self, def_id: DefId) -> Module<'a> {
                     } else {
                         def_key.disambiguated_data.data.get_opt_name().expect("module without name")
                     };
-                    let expn_id = if def_kind == DefKind::Mod {
-                        self.cstore().module_expansion_untracked(def_id, &self.session)
-                    } else {
-                        // FIXME: Parent expansions for enums and traits are not kept in metadata.
-                        ExpnId::root()
-                    };
 
                     Some(self.new_module(
                         parent,
                         ModuleKind::Def(def_kind, def_id, name),
-                        expn_id,
+                        self.cstore().module_expansion_untracked(def_id, &self.session),
                         self.cstore().get_span_untracked(def_id, &self.session),
                         // FIXME: Account for `#[no_implicit_prelude]` attributes.
                         parent.map_or(false, |module| module.no_implicit_prelude),
index e3970038a33b03dad9fbe195ecae9fd23a49add1..ff0d76e94fdf5c231a8b8f193e034c4a0d4201f1 100644 (file)
@@ -66,6 +66,8 @@ impl TypoSuggestion {
     pub descr: &'static str,
     pub path: Path,
     pub accessible: bool,
+    /// An extra note that should be issued if this item is suggested
+    pub note: Option<String>,
 }
 
 /// Adjust the impl span so that just the `impl` keyword is taken by removing
@@ -418,6 +420,10 @@ impl<'a> Resolver<'a> {
                 err.span_label(span, label);
 
                 if let Some((suggestions, msg, applicability)) = suggestion {
+                    if suggestions.is_empty() {
+                        err.help(&msg);
+                        return err;
+                    }
                     err.multipart_suggestion(&msg, suggestions, applicability);
                 }
 
@@ -829,11 +835,22 @@ fn lookup_import_candidates_from_module<FilterFn>(
                     return;
                 }
 
+                // #90113: Do not count an inaccessible reexported item as a candidate.
+                if let NameBindingKind::Import { binding, .. } = name_binding.kind {
+                    if this.is_accessible_from(binding.vis, parent_scope.module)
+                        && !this.is_accessible_from(name_binding.vis, parent_scope.module)
+                    {
+                        return;
+                    }
+                }
+
                 // collect results based on the filter function
                 // avoid suggesting anything from the same module in which we are resolving
+                // avoid suggesting anything with a hygienic name
                 if ident.name == lookup_ident.name
                     && ns == namespace
                     && !ptr::eq(in_module, parent_scope.module)
+                    && !ident.span.normalize_to_macros_2_0().from_expansion()
                 {
                     let res = name_binding.res();
                     if filter_fn(res) {
@@ -863,11 +880,38 @@ fn lookup_import_candidates_from_module<FilterFn>(
                         }
 
                         if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
+                            // See if we're recommending TryFrom, TryInto, or FromIterator and add
+                            // a note about editions
+                            let note = if let Some(did) = did {
+                                let requires_note = !did.is_local()
+                                    && this.cstore().item_attrs(did, this.session).iter().any(
+                                        |attr| {
+                                            if attr.has_name(sym::rustc_diagnostic_item) {
+                                                [sym::TryInto, sym::TryFrom, sym::FromIterator]
+                                                    .map(|x| Some(x))
+                                                    .contains(&attr.value_str())
+                                            } else {
+                                                false
+                                            }
+                                        },
+                                    );
+
+                                requires_note.then(|| {
+                                    format!(
+                                        "'{}' is included in the prelude starting in Edition 2021",
+                                        path_names_to_string(&path)
+                                    )
+                                })
+                            } else {
+                                None
+                            };
+
                             candidates.push(ImportSuggestion {
                                 did,
                                 descr: res.descr(),
                                 path,
                                 accessible: child_accessible,
+                                note,
                             });
                         }
                     }
@@ -1156,14 +1200,9 @@ fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: b
             (b1, b2, misc1, misc2, false)
         };
 
-        let mut err = struct_span_err!(
-            self.session,
-            ident.span,
-            E0659,
-            "`{ident}` is ambiguous ({why})",
-            why = kind.descr()
-        );
+        let mut err = struct_span_err!(self.session, ident.span, E0659, "`{ident}` is ambiguous");
         err.span_label(ident.span, "ambiguous name");
+        err.note(&format!("ambiguous because of {}", kind.descr()));
 
         let mut could_refer_to = |b: &NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
             let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
@@ -1327,7 +1366,7 @@ pub(crate) fn make_path_suggestion(
                 if fst.ident.span.rust_2018() && !fst.ident.is_path_segment_keyword() =>
             {
                 // Insert a placeholder that's later replaced by `self`/`super`/etc.
-                path.insert(0, Segment::from_ident(Ident::invalid()));
+                path.insert(0, Segment::from_ident(Ident::empty()));
             }
             _ => return None,
         }
@@ -1471,9 +1510,7 @@ pub(crate) fn check_for_module_export_macro(
         module: ModuleOrUniformRoot<'b>,
         ident: Ident,
     ) -> Option<(Option<Suggestion>, Vec<String>)> {
-        let mut crate_module = if let ModuleOrUniformRoot::Module(module) = module {
-            module
-        } else {
+        let ModuleOrUniformRoot::Module(mut crate_module) = module else {
             return None;
         };
 
@@ -1762,12 +1799,14 @@ fn find_span_immediately_after_crate_name(
         return;
     }
 
-    let mut accessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
-    let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
+    let mut accessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>)> =
+        Vec::new();
+    let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>)> =
+        Vec::new();
 
     candidates.iter().for_each(|c| {
         (if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings })
-            .push((path_names_to_string(&c.path), c.descr, c.did))
+            .push((path_names_to_string(&c.path), c.descr, c.did, &c.note))
     });
 
     // we want consistent results across executions, but candidates are produced
@@ -1790,6 +1829,10 @@ fn find_span_immediately_after_crate_name(
         let instead = if instead { " instead" } else { "" };
         let mut msg = format!("consider importing {} {}{}", determiner, kind, instead);
 
+        for note in accessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() {
+            err.note(note);
+        }
+
         if let Some(span) = use_placement_span {
             for candidate in &mut accessible_path_strings {
                 // produce an additional newline to separate the new use statement
@@ -1818,7 +1861,7 @@ fn find_span_immediately_after_crate_name(
         assert!(!inaccessible_path_strings.is_empty());
 
         if inaccessible_path_strings.len() == 1 {
-            let (name, descr, def_id) = &inaccessible_path_strings[0];
+            let (name, descr, def_id, note) = &inaccessible_path_strings[0];
             let msg = format!("{} `{}` exists but is inaccessible", descr, name);
 
             if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
@@ -1830,14 +1873,17 @@ fn find_span_immediately_after_crate_name(
             } else {
                 err.note(&msg);
             }
+            if let Some(note) = (*note).as_deref() {
+                err.note(note);
+            }
         } else {
-            let (_, descr_first, _) = &inaccessible_path_strings[0];
+            let (_, descr_first, _, _) = &inaccessible_path_strings[0];
             let descr = if inaccessible_path_strings
                 .iter()
                 .skip(1)
-                .all(|(_, descr, _)| descr == descr_first)
+                .all(|(_, descr, _, _)| descr == descr_first)
             {
-                format!("{}", descr_first)
+                descr_first.to_string()
             } else {
                 "item".to_string()
             };
@@ -1846,7 +1892,7 @@ fn find_span_immediately_after_crate_name(
             let mut has_colon = false;
 
             let mut spans = Vec::new();
-            for (name, _, def_id) in &inaccessible_path_strings {
+            for (name, _, def_id, _) in &inaccessible_path_strings {
                 if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
                     let span = definitions.def_span(local_def_id);
                     let span = session.source_map().guess_head_span(span);
@@ -1866,6 +1912,10 @@ fn find_span_immediately_after_crate_name(
                 multi_span.push_span_label(span, format!("`{}`: not accessible", name));
             }
 
+            for note in inaccessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() {
+                err.note(note);
+            }
+
             err.span_note(multi_span, &msg);
         }
     }
index 515b2c3fd27909d0d72bdb4c838591a0d0d1593a..936ab81914a99be5cfe57cf9b900c46d96d1e606 100644 (file)
@@ -978,7 +978,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
                     // HACK(eddyb) `lint_if_path_starts_with_module` needs at least
                     // 2 segments, so the `resolve_path` above won't trigger it.
                     let mut full_path = import.module_path.clone();
-                    full_path.push(Segment::from_ident(Ident::invalid()));
+                    full_path.push(Segment::from_ident(Ident::empty()));
                     self.r.lint_if_path_starts_with_module(
                         import.crate_lint(),
                         &full_path,
index 9563325796538dab148fc9d45d5f3448ba6a0980..0a24e00ee4bf5137b88eadef81b20a09266b4ebb 100644 (file)
@@ -1994,7 +1994,7 @@ fn smart_resolve_path_fragment(
                 if ns == ValueNS {
                     let item_name = path.last().unwrap().ident;
                     let traits = self.traits_in_scope(item_name, ns);
-                    self.r.trait_map.as_mut().unwrap().insert(id, traits);
+                    self.r.trait_map.insert(id, traits);
                 }
 
                 if PrimTy::from_name(path[0].ident.name).is_some() {
@@ -2479,12 +2479,12 @@ fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &'ast Expr) {
                 // the field name so that we can do some nice error reporting
                 // later on in typeck.
                 let traits = self.traits_in_scope(ident, ValueNS);
-                self.r.trait_map.as_mut().unwrap().insert(expr.id, traits);
+                self.r.trait_map.insert(expr.id, traits);
             }
             ExprKind::MethodCall(ref segment, ..) => {
                 debug!("(recording candidate traits for expr) recording traits for {}", expr.id);
                 let traits = self.traits_in_scope(segment.ident, ValueNS);
-                self.r.trait_map.as_mut().unwrap().insert(expr.id, traits);
+                self.r.trait_map.insert(expr.id, traits);
             }
             _ => {
                 // Nothing to do.
index 7b0dd82f0e6d1fde33cbbec9cdbcd7b81d07a97c..5f90fcdfa64e2cc205525adfa782b98bdb29484b 100644 (file)
@@ -1502,6 +1502,7 @@ fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion
                                 descr: "module",
                                 path,
                                 accessible: true,
+                                note: None,
                             },
                         ));
                     } else {
@@ -1552,7 +1553,7 @@ fn suggest_using_enum_variant(
             matches!(source, PathSource::TupleStruct(..)) || source.is_call();
         if suggest_only_tuple_variants {
             // Suggest only tuple variants regardless of whether they have fields and do not
-            // suggest path with added parenthesis.
+            // suggest path with added parentheses.
             let mut suggestable_variants = variants
                 .iter()
                 .filter(|(.., kind)| *kind == CtorKind::Fn)
index eb6f302a11da825aa195388a3bc29df9333c4f20..94563400a8b53580578424ca2251b4169e3c4391 100644 (file)
@@ -1057,9 +1057,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     match param.kind {
                         GenericParamKind::Lifetime { .. } => {
                             let (name, reg) = Region::early(&self.tcx.hir(), &mut index, &param);
-                            let def_id = if let Region::EarlyBound(_, def_id, _) = reg {
-                                def_id
-                            } else {
+                            let Region::EarlyBound(_, def_id, _) = reg else {
                                 bug!();
                             };
                             // We cannot predict what lifetimes are unused in opaque type.
index 9652c483686f06558438b529328e8abe289e4393..5f3620b247e26e1885a7361d282316268b84b1fb 100644 (file)
@@ -15,6 +15,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(format_args_capture)]
 #![feature(iter_zip)]
+#![feature(let_else)]
 #![feature(never_type)]
 #![feature(nll)]
 #![recursion_limit = "256"]
 use rustc_middle::span_bug;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs};
+use rustc_query_system::ich::StableHashingContext;
 use rustc_session::cstore::{CrateStore, MetadataLoaderDyn};
 use rustc_session::lint;
 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext, Transparency};
-use rustc_span::source_map::{CachingSourceMapView, Spanned};
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
@@ -725,23 +727,21 @@ enum AmbiguityKind {
 impl AmbiguityKind {
     fn descr(self) -> &'static str {
         match self {
-            AmbiguityKind::Import => "name vs any other name during import resolution",
-            AmbiguityKind::BuiltinAttr => "built-in attribute vs any other name",
-            AmbiguityKind::DeriveHelper => "derive helper attribute vs any other name",
+            AmbiguityKind::Import => "multiple potential import sources",
+            AmbiguityKind::BuiltinAttr => "a name conflict with a builtin attribute",
+            AmbiguityKind::DeriveHelper => "a name conflict with a derive helper attribute",
             AmbiguityKind::MacroRulesVsModularized => {
-                "`macro_rules` vs non-`macro_rules` from other module"
+                "a conflict between a `macro_rules` name and a non-`macro_rules` name from another module"
             }
             AmbiguityKind::GlobVsOuter => {
-                "glob import vs any other name from outer scope during import/macro resolution"
+                "a conflict between a name from a glob import and an outer scope during import or macro resolution"
             }
-            AmbiguityKind::GlobVsGlob => "glob import vs glob import in the same module",
+            AmbiguityKind::GlobVsGlob => "multiple glob imports of a name in the same module",
             AmbiguityKind::GlobVsExpanded => {
-                "glob import vs macro-expanded name in the same \
-                 module during import/macro resolution"
+                "a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution"
             }
             AmbiguityKind::MoreExpandedVsOuter => {
-                "macro-expanded name vs less macro-expanded name \
-                 from outer scope during import/macro resolution"
+                "a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution"
             }
         }
     }
@@ -930,7 +930,7 @@ pub struct Resolver<'a> {
     /// `CrateNum` resolutions of `extern crate` items.
     extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
     export_map: ExportMap,
-    trait_map: Option<NodeMap<Vec<TraitCandidate>>>,
+    trait_map: NodeMap<Vec<TraitCandidate>>,
 
     /// A map from nodes to anonymous modules.
     /// Anonymous modules are pseudo-modules that are implicitly created around items
@@ -1177,6 +1177,10 @@ fn definitions(&mut self) -> &mut Definitions {
         &mut self.definitions
     }
 
+    fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
+        StableHashingContext::new(self.session, &self.definitions, self.crate_loader.cstore())
+    }
+
     fn lint_buffer(&mut self) -> &mut LintBuffer {
         &mut self.lint_buffer
     }
@@ -1185,8 +1189,8 @@ fn next_node_id(&mut self) -> NodeId {
         self.next_node_id()
     }
 
-    fn take_trait_map(&mut self) -> NodeMap<Vec<TraitCandidate>> {
-        std::mem::replace(&mut self.trait_map, None).unwrap()
+    fn take_trait_map(&mut self, node: NodeId) -> Option<Vec<TraitCandidate>> {
+        self.trait_map.remove(&node)
     }
 
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
@@ -1245,37 +1249,6 @@ fn create_def(
     }
 }
 
-struct ExpandHasher<'a, 'b> {
-    source_map: CachingSourceMapView<'a>,
-    resolver: &'a Resolver<'b>,
-}
-
-impl<'a, 'b> rustc_span::HashStableContext for ExpandHasher<'a, 'b> {
-    #[inline]
-    fn hash_spans(&self) -> bool {
-        true
-    }
-
-    #[inline]
-    fn def_span(&self, id: LocalDefId) -> Span {
-        self.resolver.def_span(id)
-    }
-
-    #[inline]
-    fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
-        self.resolver.def_path_hash(def_id)
-    }
-
-    #[inline]
-    fn span_data_to_lines_and_cols(
-        &mut self,
-        span: &rustc_span::SpanData,
-    ) -> Option<(Lrc<rustc_span::SourceFile>, usize, rustc_span::BytePos, usize, rustc_span::BytePos)>
-    {
-        self.source_map.span_data_to_lines_and_cols(span)
-    }
-}
-
 impl<'a> Resolver<'a> {
     pub fn new(
         session: &'a Session,
@@ -1363,7 +1336,7 @@ pub fn new(
             label_res_map: Default::default(),
             extern_crate_map: Default::default(),
             export_map: FxHashMap::default(),
-            trait_map: Some(NodeMap::default()),
+            trait_map: NodeMap::default(),
             underscore_disambiguator: 0,
             empty_module,
             module_map,
@@ -1456,13 +1429,6 @@ fn new_module(
         self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude, module_map)
     }
 
-    fn create_stable_hashing_context(&self) -> ExpandHasher<'_, 'a> {
-        ExpandHasher {
-            source_map: CachingSourceMapView::new(self.session.source_map()),
-            resolver: self,
-        }
-    }
-
     pub fn next_node_id(&mut self) -> NodeId {
         let next = self
             .next_node_id
@@ -2557,19 +2523,29 @@ enum FindBindingResult<'a> {
                         } else {
                             (
                                 format!("use of undeclared crate or module `{}`", ident),
-                                self.find_similarly_named_module_or_crate(
-                                    ident.name,
-                                    &parent_scope.module,
-                                )
-                                .map(|sugg| {
-                                    (
-                                        vec![(ident.span, sugg.to_string())],
+                                if ident.name == sym::alloc {
+                                    Some((
+                                        vec![],
                                         String::from(
-                                            "there is a crate or module with a similar name",
+                                            "add `extern crate alloc` to use the `alloc` crate",
                                         ),
                                         Applicability::MaybeIncorrect,
+                                    ))
+                                } else {
+                                    self.find_similarly_named_module_or_crate(
+                                        ident.name,
+                                        &parent_scope.module,
                                     )
-                                }),
+                                    .map(|sugg| {
+                                        (
+                                            vec![(ident.span, sugg.to_string())],
+                                            String::from(
+                                                "there is a crate or module with a similar name",
+                                            ),
+                                            Applicability::MaybeIncorrect,
+                                        )
+                                    })
+                                },
                             )
                         }
                     } else {
index f4567b334836ae476984386399dafba9f1d10a48..f1a5282b08871323aa2b0a18be0103481ae1fffd 100644 (file)
@@ -236,7 +236,7 @@ fn process_formals(&mut self, formals: &'tcx [hir::Param<'tcx>], qualname: &str)
                             id,
                             span,
                             name: ident.to_string(),
-                            qualname: format!("{}::{}", qualname, ident.to_string()),
+                            qualname: format!("{}::{}", qualname, ident),
                             value: typ,
                             parent: None,
                             children: vec![],
@@ -889,7 +889,7 @@ fn process_var_decl(&mut self, pat: &'tcx hir::Pat<'tcx>) {
 
                     // Rust uses the id of the pattern for var lookups, so we'll use it too.
                     if !self.span.filter_generated(ident.span) {
-                        let qualname = format!("{}${}", ident.to_string(), hir_id);
+                        let qualname = format!("{}${}", ident, hir_id);
                         let id = id_from_hir_id(hir_id, &self.save_ctxt);
                         let span = self.span_from_span(ident.span);
 
index 6671c7c0fa60ca18d15472ef72157f6b54a86a9f..e32e4493726dbb7d279c66e1451a10d99ccfc41b 100644 (file)
@@ -500,8 +500,8 @@ fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         d.read_seq(|d, len| {
             assert!(len == N);
             let mut v = [0u8; N];
-            for x in &mut v {
-                *x = d.read_seq_elt(|d| Decodable::decode(d))?;
+            for i in 0..len {
+                v[i] = d.read_seq_elt(|d| Decodable::decode(d))?;
             }
             Ok(v)
         })
index ac4bce7350b9079c4530686d496e43bc77c0e4d1..299dfed9d5dcea7845f2898b3cb612e1ddc96d80 100644 (file)
@@ -174,6 +174,20 @@ pub fn enabled(&self) -> bool {
     }
 }
 
+/// The different settings that can be enabled via the `-Z location-detail` flag.
+#[derive(Clone, PartialEq, Hash, Debug)]
+pub struct LocationDetail {
+    pub file: bool,
+    pub line: bool,
+    pub column: bool,
+}
+
+impl LocationDetail {
+    pub fn all() -> Self {
+        Self { file: true, line: true, column: true }
+    }
+}
+
 #[derive(Clone, PartialEq, Hash, Debug)]
 pub enum SwitchWithOptPath {
     Enabled(Option<PathBuf>),
@@ -2422,7 +2436,7 @@ pub fn needs_analysis(&self) -> bool {
     use super::LdImpl;
     use super::{
         CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
-        LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
+        LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
         SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
     };
     use crate::lint;
@@ -2513,6 +2527,7 @@ fn hash(
         Option<LdImpl>,
         OutputType,
         RealFileName,
+        LocationDetail,
     );
 
     impl<T1, T2> DepTrackingHash for (T1, T2)
index b3d36b396c51cafe80e657ec51e1202831b41af4..3add3e861484e82b862ec6f156497847143fa6ad 100644 (file)
@@ -351,8 +351,7 @@ mod desc {
     pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
     pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
     pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
-    pub const parse_sanitizers: &str =
-        "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
+    pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory` or `thread`";
     pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
     pub const parse_cfguard: &str =
         "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@@ -368,6 +367,8 @@ mod desc {
         "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
     pub const parse_linker_plugin_lto: &str =
         "either a boolean (`yes`, `no`, `on`, `off`, etc), or the path to the linker plugin";
+    pub const parse_location_detail: &str =
+        "comma seperated list of location details to track: `file`, `line`, or `column`";
     pub const parse_switch_with_opt_path: &str =
         "an optional path to the profiling data output directory";
     pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`";
@@ -484,6 +485,25 @@ mod parse {
         }
     }
 
+    crate fn parse_location_detail(ld: &mut LocationDetail, v: Option<&str>) -> bool {
+        if let Some(v) = v {
+            ld.line = false;
+            ld.file = false;
+            ld.column = false;
+            for s in v.split(',') {
+                match s {
+                    "file" => ld.file = true,
+                    "line" => ld.line = true,
+                    "column" => ld.column = true,
+                    _ => return false,
+                }
+            }
+            true
+        } else {
+            false
+        }
+    }
+
     crate fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
         match v {
             Some(s) => {
@@ -584,6 +604,7 @@ mod parse {
             for s in v.split(',') {
                 *slot |= match s {
                     "address" => SanitizerSet::ADDRESS,
+                    "cfi" => SanitizerSet::CFI,
                     "leak" => SanitizerSet::LEAK,
                     "memory" => SanitizerSet::MEMORY,
                     "thread" => SanitizerSet::THREAD,
@@ -1152,6 +1173,9 @@ mod parse {
         "a list LLVM plugins to enable (space separated)"),
     llvm_time_trace: bool = (false, parse_bool, [UNTRACKED],
         "generate JSON tracing data file from LLVM data (default: no)"),
+    location_detail: LocationDetail = (LocationDetail::all(), parse_location_detail, [TRACKED],
+        "comma seperated list of location details to be tracked when using caller_location \
+        valid options are `file`, `line`, and `column` (default: all)"),
     ls: bool = (false, parse_bool, [UNTRACKED],
         "list the symbols defined by a library crate (default: no)"),
     macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
@@ -1169,7 +1193,7 @@ mod parse {
     move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
         "the size at which the `large_assignments` lint starts to be emitted"),
     mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "emit noalias metadata for mutable references (default: yes for LLVM >= 12, otherwise no)"),
+        "emit noalias metadata for mutable references (default: yes)"),
     new_llvm_pass_manager: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "use new LLVM pass manager (default: no)"),
     nll_facts: bool = (false, parse_bool, [UNTRACKED],
@@ -1190,6 +1214,8 @@ mod parse {
         "compile without linking"),
     no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED],
         "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
+    no_unique_section_names: bool = (false, parse_bool, [TRACKED],
+        "do not use unique names for text and data sections when -Z function-sections is used"),
     no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
         "prevent automatic injection of the profiler_builtins crate"),
     normalize_docs: bool = (false, parse_bool, [TRACKED],
@@ -1283,7 +1309,7 @@ mod parse {
         "specify the events recorded by the self profiler;
         for example: `-Z self-profile-events=default,query-keys`
         all options: none, all, default, generic-activity, query-provider, query-cache-hit
-                     query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm"),
+                     query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"),
     share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "make the current crate share its generic instantiations"),
     show_span: Option<String> = (None, parse_opt_string, [TRACKED],
index a007b530302719a9ee4b22ba2b656a63baf81123..f7246641dca3e952f8369c034a92c80de8988265 100644 (file)
@@ -174,9 +174,14 @@ pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> Self {
         }
     }
 
-    pub fn with_silent_emitter() -> Self {
+    pub fn with_silent_emitter(fatal_note: Option<String>) -> Self {
         let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-        let handler = Handler::with_emitter(false, None, Box::new(SilentEmitter));
+        let fatal_handler = Handler::with_tty_emitter(ColorConfig::Auto, false, None, None);
+        let handler = Handler::with_emitter(
+            false,
+            None,
+            Box::new(SilentEmitter { fatal_handler, fatal_note }),
+        );
         ParseSess::with_span_handler(handler, sm)
     }
 
index b6ba6cc1dd659861202d40b14ff8c75dd8fea001..0f6a3ddccbaf0fbc62628cdb6d16b234c038b2be 100644 (file)
@@ -672,6 +672,9 @@ pub fn unstable_options(&self) -> bool {
     pub fn is_nightly_build(&self) -> bool {
         self.opts.unstable_features.is_nightly_build()
     }
+    pub fn is_sanitizer_cfi_enabled(&self) -> bool {
+        self.opts.debugging_opts.sanitizer.contains(SanitizerSet::CFI)
+    }
     pub fn overflow_checks(&self) -> bool {
         self.opts
             .cg
@@ -1398,6 +1401,16 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
                                 disable it using `-C target-feature=-crt-static`",
         );
     }
+
+    // LLVM CFI requires LTO.
+    if sess.is_sanitizer_cfi_enabled() {
+        if sess.opts.cg.lto == config::LtoCli::Unspecified
+            || sess.opts.cg.lto == config::LtoCli::No
+            || sess.opts.cg.lto == config::LtoCli::Thin
+        {
+            sess.err("`-Zsanitizer=cfi` requires `-Clto`");
+        }
+    }
 }
 
 /// Holds data on the current incremental compilation session, if there is one.
index aa15febe8853d709855a1ffc919dc18c67f4e5c9..724d1904dc33c7125d7231f2190abc64d7d4f7c9 100644 (file)
@@ -709,7 +709,7 @@ pub fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<
     ///         pub fn f() {} // `f`'s `SyntaxContext` has a single `ExpnId` from `m`.
     ///         pub fn $i() {} // `$i`'s `SyntaxContext` is empty.
     ///     }
-    ///     n(f);
+    ///     n!(f);
     ///     macro n($j:ident) {
     ///         use foo::*;
     ///         f(); // `f`'s `SyntaxContext` has a mark from `m` and a mark from `n`
index cea7871923bc689dc44ca295518c64f8c502eeac..c10968e06d79a66b4150c2cac6b95e9b3a06f433 100644 (file)
@@ -58,34 +58,28 @@ pub fn find_best_match_for_name(
     let lookup = &lookup.as_str();
     let max_dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3);
 
-    let (case_insensitive_match, levenshtein_match) = name_vec
+    // Priority of matches:
+    // 1. Exact case insensitive match
+    // 2. Levenshtein distance match
+    // 3. Sorted word match
+    if let Some(case_insensitive_match) =
+        name_vec.iter().find(|candidate| candidate.as_str().to_uppercase() == lookup.to_uppercase())
+    {
+        return Some(*case_insensitive_match);
+    }
+    let levenshtein_match = name_vec
         .iter()
         .filter_map(|&name| {
             let dist = lev_distance(lookup, &name.as_str());
             if dist <= max_dist { Some((name, dist)) } else { None }
         })
         // Here we are collecting the next structure:
-        // (case_insensitive_match, (levenshtein_match, levenshtein_distance))
-        .fold((None, None), |result, (candidate, dist)| {
-            (
-                if candidate.as_str().to_uppercase() == lookup.to_uppercase() {
-                    Some(candidate)
-                } else {
-                    result.0
-                },
-                match result.1 {
-                    None => Some((candidate, dist)),
-                    Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }),
-                },
-            )
+        // (levenshtein_match, levenshtein_distance)
+        .fold(None, |result, (candidate, dist)| match result {
+            None => Some((candidate, dist)),
+            Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }),
         });
-    // Priority of matches:
-    // 1. Exact case insensitive match
-    // 2. Levenshtein distance match
-    // 3. Sorted word match
-    if let Some(candidate) = case_insensitive_match {
-        Some(candidate)
-    } else if levenshtein_match.is_some() {
+    if levenshtein_match.is_some() {
         levenshtein_match.map(|(candidate, _)| candidate)
     } else {
         find_match_by_sorted_words(name_vec, lookup)
index 11822e9ef974236c9784405674e178fa70a327b7..b32f8d32c1391e0be3e54c76c7ccf351bba1745d 100644 (file)
@@ -31,16 +31,12 @@ fn test_find_best_match_for_name() {
 
         assert_eq!(find_best_match_for_name(&input, Symbol::intern("1111111111"), None), None);
 
-        let input = vec![Symbol::intern("aAAA")];
+        let input = vec![Symbol::intern("AAAA")];
         assert_eq!(
-            find_best_match_for_name(&input, Symbol::intern("AAAA"), None),
-            Some(Symbol::intern("aAAA"))
+            find_best_match_for_name(&input, Symbol::intern("aaaa"), None),
+            Some(Symbol::intern("AAAA"))
         );
 
-        let input = vec![Symbol::intern("AAAA")];
-        // Returns None because `lev_distance > max_dist / 3`
-        assert_eq!(find_best_match_for_name(&input, Symbol::intern("aaaa"), None), None);
-
         let input = vec![Symbol::intern("AAAA")];
         assert_eq!(
             find_best_match_for_name(&input, Symbol::intern("aaaa"), Some(4)),
index fddb225345f49bad1000807db842563489ae6b1e..52e2a8f48e23be3f62f4f419d1ba34e7359c5b82 100644 (file)
         await_macro,
         bang,
         begin_panic,
-        begin_panic_fmt,
         bench,
         bin,
         bind_by_move_pattern_guards,
         cfg_target_thread_local,
         cfg_target_vendor,
         cfg_version,
+        cfi,
         char,
         client,
         clippy,
         div_assign,
         doc,
         doc_alias,
+        doc_auto_cfg,
         doc_cfg,
         doc_cfg_hide,
         doc_keyword,
         rustc_partition_reused,
         rustc_peek,
         rustc_peek_definite_init,
-        rustc_peek_indirectly_mutable,
         rustc_peek_liveness,
         rustc_peek_maybe_init,
         rustc_peek_maybe_uninit,
         rustc_specialization_trait,
         rustc_stable,
         rustc_std_internal_symbol,
+        rustc_strict_coherence,
         rustc_symbol_name,
         rustc_synthetic,
         rustc_test_marker,
         type_alias_enum_variants,
         type_alias_impl_trait,
         type_ascription,
+        type_changing_struct_update,
         type_id,
         type_length_limit,
         type_macros,
@@ -1453,7 +1455,7 @@ pub const fn with_dummy_span(name: Symbol) -> Ident {
     }
 
     #[inline]
-    pub fn invalid() -> Ident {
+    pub fn empty() -> Ident {
         Ident::with_dummy_span(kw::Empty)
     }
 
index 220c9f7e2ec2bbeca37d4835041743be5d7e2e3f..bb7b4529556091923e6c947750e1fa1a0c6fa8df 100644 (file)
 use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Instance, TyCtxt};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_session::config::SymbolManglingVersion;
+use rustc_target::abi::call::FnAbi;
 
 use tracing::debug;
 
@@ -150,6 +151,11 @@ fn symbol_name_provider(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::Symb
     ty::SymbolName::new(tcx, &symbol_name)
 }
 
+/// This function computes the typeid for the given function ABI.
+pub fn typeid_for_fnabi(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
+    v0::mangle_typeid_for_fnabi(tcx, fn_abi)
+}
+
 /// Computes the symbol name for the given instance. This function will call
 /// `compute_instantiating_crate` if it needs to factor the instantiating crate
 /// into the symbol name.
index 521730dfeb01cc22266da68404b104321abf2c39..0363ddb0e6eee17b2e9d79ce3ad334a20459a6bf 100644 (file)
@@ -9,6 +9,7 @@
 use rustc_middle::ty::print::{Print, Printer};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
 use rustc_middle::ty::{self, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
+use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::Integer;
 use rustc_target::spec::abi::Abi;
 
@@ -55,6 +56,41 @@ pub(super) fn mangle(
     std::mem::take(&mut cx.out)
 }
 
+pub(super) fn mangle_typeid_for_fnabi(
+    _tcx: TyCtxt<'tcx>,
+    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+) -> String {
+    // LLVM uses type metadata to allow IR modules to aggregate pointers by their types.[1] This
+    // type metadata is used by LLVM Control Flow Integrity to test whether a given pointer is
+    // associated with a type identifier (i.e., test type membership).
+    //
+    // Clang uses the Itanium C++ ABI's[2] virtual tables and RTTI typeinfo structure name[3] as
+    // type metadata identifiers for function pointers. The typeinfo name encoding is a
+    // two-character code (i.e., “TS”) prefixed to the type encoding for the function.
+    //
+    // For cross-language LLVM CFI support, a compatible encoding must be used by either
+    //
+    //  a. Using a superset of types that encompasses types used by Clang (i.e., Itanium C++ ABI's
+    //     type encodings[4]), or at least types used at the FFI boundary.
+    //  b. Reducing the types to the least common denominator between types used by Clang (or at
+    //     least types used at the FFI boundary) and Rust compilers (if even possible).
+    //  c. Creating a new ABI for cross-language CFI and using it for Clang and Rust compilers (and
+    //     possibly other compilers).
+    //
+    // Option (b) may weaken the protection for Rust-compiled only code, so it should be provided
+    // as an alternative to a Rust-specific encoding for when mixing Rust and C and C++ -compiled
+    // code. Option (c) would require changes to Clang to use the new ABI.
+    //
+    // [1] https://llvm.org/docs/TypeMetadata.html
+    // [2] https://itanium-cxx-abi.github.io/cxx-abi/abi.html
+    // [3] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-vtables
+    // [4] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-type
+    //
+    // FIXME(rcvalle): See comment above.
+    let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize;
+    format!("typeid{}", arg_count)
+}
+
 struct BinderLevel {
     /// The range of distances from the root of what's
     /// being printed, to the lifetimes in a binder.
index d9eb299e2fd350781725927aade13b5bfad1166c..4768c9e2db5e109ddca539d463d9b8fb381968ed 100644 (file)
@@ -68,8 +68,10 @@ pub struct ArgAttribute: u16 {
             const NonNull   = 1 << 3;
             const ReadOnly  = 1 << 4;
             const InReg     = 1 << 5;
-            // NoAlias on &mut arguments can only be used with LLVM >= 12 due to miscompiles
-            // in earlier versions. FIXME: Remove this distinction once possible.
+            // Due to past miscompiles in LLVM, we use a separate attribute for
+            // &mut arguments, so that the codegen backend can decide whether
+            // or not to actually emit the attribute. It can also be controlled
+            // with the `-Zmutable-noalias` debugging option.
             const NoAliasMutRef = 1 << 6;
         }
     }
index 616071592087da8a5573884bdc47b851bcd78ab3..a57ad8f2bbd1bf1bee765d6e2ad4de4f79d74032 100644 (file)
@@ -1117,7 +1117,7 @@ pub fn reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Sc
         // In practice this means that enums with `count > 1` are unlikely to claim niche zero, since they have to fit perfectly.
         // If niche zero is already reserved, the selection of bounds are of little interest.
         let move_start = |v: WrappingRange| {
-            let start = v.start.wrapping_sub(1) & max_value;
+            let start = v.start.wrapping_sub(count) & max_value;
             Some((start, Scalar { value, valid_range: v.with_start(start) }))
         };
         let move_end = |v: WrappingRange| {
index dc91f1230964921d22bd30924373df7fc78744cf..ca3550e9278d10426b2a7902e695c01849f60157 100644 (file)
@@ -2,11 +2,11 @@
 
 pub fn target() -> Target {
     let mut base = super::apple_base::opts("macos");
-    base.cpu = "apple-a12".to_string();
+    base.cpu = "apple-a14".to_string();
     base.max_atomic_width = Some(128);
 
     // FIXME: The leak sanitizer currently fails the tests, see #88132.
-    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
+    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
 
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]);
     base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
index 71ee6deb07f903b5c64b9b46d8e5ec59e9c6c1bd..a393858879bfe725ab4c239e6da04dbec1622cb5 100644 (file)
@@ -8,6 +8,7 @@ pub fn target() -> Target {
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
         options: TargetOptions {
+            features: "+outline-atomics".to_string(),
             max_atomic_width: Some(128),
             mcount: "\u{1}_mcount".to_string(),
             endian: Endian::Big,
index e05360ea45c6c5b677f07ace67752a0a11f3a31b..e75100f1435115300f61dd274db7b86988d5ed17 100644 (file)
@@ -12,6 +12,7 @@ pub fn target() -> Target {
         arch: "aarch64".to_string(),
         options: TargetOptions {
             abi: "ilp32".to_string(),
+            features: "+outline-atomics".to_string(),
             mcount: "\u{1}_mcount".to_string(),
             endian: Endian::Big,
             ..base
index 56d71df6bda242af9d55c0dace7aa5d6689868dd..05e0c65dd5c38654b001db52bb786972476cca21 100644 (file)
@@ -8,7 +8,7 @@ pub fn target() -> Target {
         arch: "aarch64".to_string(),
         options: TargetOptions {
             max_atomic_width: Some(128),
-            supported_sanitizers: SanitizerSet::ADDRESS,
+            supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI,
             ..super::fuchsia_base::opts()
         },
     }
index 409cab72ec2196898ba478fa53d379c6041cb51d..1e9abbbe1e7878c5553f39983046d01b758acf86 100644 (file)
@@ -14,7 +14,7 @@ pub fn target() -> Target {
             // As documented in https://developer.android.com/ndk/guides/cpu-features.html
             // the neon (ASIMD) and FP must exist on all android aarch64 targets.
             features: "+neon,+fp-armv8".to_string(),
-            supported_sanitizers: SanitizerSet::HWADDRESS,
+            supported_sanitizers: SanitizerSet::CFI | SanitizerSet::HWADDRESS,
             ..super::android_base::opts()
         },
     }
index 0caecd2987bd52e845430949f43f9b466112ed4b..03ee7ba4875c956a8d2b67628f87d8b6f848d8ce 100644 (file)
@@ -9,6 +9,7 @@ pub fn target() -> Target {
         options: TargetOptions {
             max_atomic_width: Some(128),
             supported_sanitizers: SanitizerSet::ADDRESS
+                | SanitizerSet::CFI
                 | SanitizerSet::MEMORY
                 | SanitizerSet::THREAD,
             ..super::freebsd_base::opts()
index 3e92ecbae054cc429c1ab49d97c698250ffeee67..850381f7fb073e6fb12c3dd1dc736cc7cdcb2dc5 100644 (file)
@@ -7,9 +7,11 @@ pub fn target() -> Target {
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
         options: TargetOptions {
+            features: "+outline-atomics".to_string(),
             mcount: "\u{1}_mcount".to_string(),
             max_atomic_width: Some(128),
             supported_sanitizers: SanitizerSet::ADDRESS
+                | SanitizerSet::CFI
                 | SanitizerSet::LEAK
                 | SanitizerSet::MEMORY
                 | SanitizerSet::THREAD
index 8522405f61feb50fbb2972a9990f72994b6816f6..1c931d5a705f0df3b95f75363f15ffb93bedf7c4 100644 (file)
@@ -8,6 +8,7 @@ pub fn target() -> Target {
         arch: "aarch64".to_string(),
         options: TargetOptions {
             abi: "ilp32".to_string(),
+            features: "+outline-atomics".to_string(),
             max_atomic_width: Some(128),
             mcount: "\u{1}_mcount".to_string(),
             ..super::linux_gnu_base::opts()
index 6a16b4ce419647f0569220f47e35f6f68540b0c1..0770f3496c2792bc87fbed8dc393fa6c4e9e385d 100644 (file)
@@ -9,6 +9,10 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        options: TargetOptions { mcount: "\u{1}_mcount".to_string(), ..base },
+        options: TargetOptions {
+            features: "+outline-atomics".to_string(),
+            mcount: "\u{1}_mcount".to_string(),
+            ..base
+        },
     }
 }
index c55a46e69a8334be202a23cf84c6b28425e60431..ce3dad26458d0c3d113b4e63f76e4275466002c9 100644 (file)
@@ -1,4 +1,4 @@
-use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions, TlsModel};
+use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     let mut pre_link_args = LinkArgs::new();
@@ -8,17 +8,14 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        os: "hermit".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         disable_redzone: true,
         linker: Some("rust-lld".to_owned()),
         executables: true,
-        has_elf_tls: true,
         pre_link_args,
         panic_strategy: PanicStrategy::Abort,
         position_independent_executables: true,
         static_position_independent_executables: true,
-        tls_model: TlsModel::InitialExec,
         ..Default::default()
     }
 }
index ff5dfa3f746254b0364c4faf37b17f81e941346b..0b95d1ca851a16fd593b41427edb6fa0f829b5ae 100644 (file)
@@ -602,6 +602,7 @@ pub struct SanitizerSet: u8 {
         const MEMORY  = 1 << 2;
         const THREAD  = 1 << 3;
         const HWADDRESS = 1 << 4;
+        const CFI     = 1 << 5;
     }
 }
 
@@ -612,6 +613,7 @@ impl SanitizerSet {
     fn as_str(self) -> Option<&'static str> {
         Some(match self {
             SanitizerSet::ADDRESS => "address",
+            SanitizerSet::CFI => "cfi",
             SanitizerSet::LEAK => "leak",
             SanitizerSet::MEMORY => "memory",
             SanitizerSet::THREAD => "thread",
@@ -644,6 +646,7 @@ impl IntoIterator for SanitizerSet {
     fn into_iter(self) -> Self::IntoIter {
         [
             SanitizerSet::ADDRESS,
+            SanitizerSet::CFI,
             SanitizerSet::LEAK,
             SanitizerSet::MEMORY,
             SanitizerSet::THREAD,
@@ -954,6 +957,8 @@ fn $module() {
     ("armv6k-nintendo-3ds", armv6k_nintendo_3ds),
 
     ("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf),
+
+    ("x86_64-unknown-none", x86_64_unknown_none),
 }
 
 /// Warnings encountered when parsing the target `json`.
@@ -1522,6 +1527,7 @@ pub fn is_abi_supported(&self, abi: Abi) -> Option<bool> {
             AmdGpuKernel => self.arch == "amdgcn",
             AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr",
             Wasm => ["wasm32", "wasm64"].contains(&&self.arch[..]),
+            Thiscall { .. } => self.arch == "x86",
             // On windows these fall-back to platform native calling convention (C) when the
             // architecture is not supported.
             //
@@ -1552,15 +1558,13 @@ pub fn is_abi_supported(&self, abi: Abi) -> Option<bool> {
             // > convention is used.
             //
             // -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
-            Stdcall { .. } | Fastcall | Thiscall { .. } | Vectorcall if self.is_like_windows => {
-                true
-            }
+            Stdcall { .. } | Fastcall | Vectorcall if self.is_like_windows => true,
             // Outside of Windows we want to only support these calling conventions for the
             // architectures for which these calling conventions are actually well defined.
-            Stdcall { .. } | Fastcall | Thiscall { .. } if self.arch == "x86" => true,
+            Stdcall { .. } | Fastcall if self.arch == "x86" => true,
             Vectorcall if ["x86", "x86_64"].contains(&&self.arch[..]) => true,
             // Return a `None` for other cases so that we know to emit a future compat lint.
-            Stdcall { .. } | Fastcall | Thiscall { .. } | Vectorcall => return None,
+            Stdcall { .. } | Fastcall | Vectorcall => return None,
         })
     }
 
@@ -1805,6 +1809,7 @@ macro_rules! key {
                         for s in a {
                             base.$key_name |= match s.as_string() {
                                 Some("address") => SanitizerSet::ADDRESS,
+                                Some("cfi") => SanitizerSet::CFI,
                                 Some("leak") => SanitizerSet::LEAK,
                                 Some("memory") => SanitizerSet::MEMORY,
                                 Some("thread") => SanitizerSet::THREAD,
index 60fd42970c7d6c908ee152473841654081a9bf6d..22fdaabfcb89b68821fde9b65c7a137c2b1439ba 100644 (file)
@@ -13,7 +13,8 @@ pub fn target() -> Target {
     base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
     // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
     base.stack_probes = StackProbeType::Call;
-    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD;
+    base.supported_sanitizers =
+        SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD;
 
     // Clang automatically chooses a more specific target based on
     // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
index aa65ebe1f9dbd77615e0f381b5ef7eb098b6438c..c253c0c30b3d34c442baa2995e63e4c645b3e7fb 100644 (file)
@@ -6,7 +6,7 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(64);
     // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
     base.stack_probes = StackProbeType::Call;
-    base.supported_sanitizers = SanitizerSet::ADDRESS;
+    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
 
     Target {
         llvm_target: "x86_64-fuchsia".to_string(),
index 34b6d2901c82039010871fc2376b12c4a815ec9d..6aa0728668277f52e723f14a42ce3a67218c2e87 100644 (file)
@@ -8,7 +8,7 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(64);
     // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
     base.stack_probes = StackProbeType::Call;
-    base.supported_sanitizers = SanitizerSet::ADDRESS;
+    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
 
     Target {
         llvm_target: "x86_64-pc-solaris".to_string(),
index b5fc15f5e04bf200038118a5f9ae0d5db909c0fc..24cc7ae788b458dbfa268841cfba06f7fc202502 100644 (file)
@@ -7,7 +7,8 @@ pub fn target() -> Target {
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
     // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
     base.stack_probes = StackProbeType::Call;
-    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+    base.supported_sanitizers =
+        SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::MEMORY | SanitizerSet::THREAD;
 
     Target {
         llvm_target: "x86_64-unknown-freebsd".to_string(),
index ec196a7f823296d651a4ea9c8ead65122f29f4eb..79ccf63acfada71a1d2d268bf0a963b97f3368b6 100644 (file)
@@ -5,7 +5,7 @@ pub fn target() -> Target {
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string(), "-std=c99".to_string()]);
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.supported_sanitizers = SanitizerSet::ADDRESS;
+    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
 
     Target {
         // LLVM does not currently have a separate illumos target,
index 085079e06e570a0e3f7aea0aa4f119c8eb4f8638..c2484f2d8f66d88b8bfd23f3d88497b255a4eb24 100644 (file)
@@ -7,8 +7,11 @@ pub fn target() -> Target {
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
     // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
     base.stack_probes = StackProbeType::Call;
-    base.supported_sanitizers =
-        SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+    base.supported_sanitizers = SanitizerSet::ADDRESS
+        | SanitizerSet::CFI
+        | SanitizerSet::LEAK
+        | SanitizerSet::MEMORY
+        | SanitizerSet::THREAD;
 
     Target {
         llvm_target: "x86_64-unknown-linux-gnu".to_string(),
index 5ad243aa4075e2c3616e24a053e213cf22a3c96e..a5e79803335b7ae027f2c678740288ee72a39f7c 100644 (file)
@@ -8,8 +8,11 @@ pub fn target() -> Target {
     // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
     base.stack_probes = StackProbeType::Call;
     base.static_position_independent_executables = true;
-    base.supported_sanitizers =
-        SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+    base.supported_sanitizers = SanitizerSet::ADDRESS
+        | SanitizerSet::CFI
+        | SanitizerSet::LEAK
+        | SanitizerSet::MEMORY
+        | SanitizerSet::THREAD;
 
     Target {
         llvm_target: "x86_64-unknown-linux-musl".to_string(),
index 9ba86280d519731d78e5fa13b73ce7feb7ff49c8..bdb2be4f863e2bed0d37e2f1c60247568ec9baf5 100644 (file)
@@ -7,8 +7,11 @@ pub fn target() -> Target {
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
     // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
     base.stack_probes = StackProbeType::Call;
-    base.supported_sanitizers =
-        SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+    base.supported_sanitizers = SanitizerSet::ADDRESS
+        | SanitizerSet::CFI
+        | SanitizerSet::LEAK
+        | SanitizerSet::MEMORY
+        | SanitizerSet::THREAD;
 
     Target {
         llvm_target: "x86_64-unknown-netbsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs
new file mode 100644 (file)
index 0000000..722409d
--- /dev/null
@@ -0,0 +1,41 @@
+// Generic x86-64 target for bare-metal code - Floating point disabled
+//
+// Can be used in conjunction with the `target-feature` and
+// `target-cpu` compiler flags to opt-in more hardware-specific
+// features.
+
+use super::{
+    CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, RelroLevel, StackProbeType,
+    Target, TargetOptions,
+};
+
+pub fn target() -> Target {
+    let opts = TargetOptions {
+        cpu: "x86-64".to_string(),
+        max_atomic_width: Some(64),
+        // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+        stack_probes: StackProbeType::Call,
+        position_independent_executables: true,
+        static_position_independent_executables: true,
+        relro_level: RelroLevel::Full,
+        relocation_model: RelocModel::Pic,
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+        linker: Some("rust-lld".to_owned()),
+        features:
+            "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"
+                .to_string(),
+        executables: true,
+        disable_redzone: true,
+        panic_strategy: PanicStrategy::Abort,
+        code_model: Some(CodeModel::Kernel),
+        ..Default::default()
+    };
+    Target {
+        llvm_target: "x86_64-unknown-none-elf".to_string(),
+        pointer_width: 64,
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
+        arch: "x86_64".to_string(),
+        options: opts,
+    }
+}
index 017a7c45bbf9d21fd8d6c49dad2264a9a6beac92..1a049e6ec649da4bcd0c63408e40b7e5106f6d0a 100644 (file)
@@ -17,6 +17,7 @@
 #![feature(hash_drain_filter)]
 #![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
+#![feature(let_else)]
 #![feature(never_type)]
 #![feature(crate_visibility_modifier)]
 #![feature(control_flow_enum)]
index c2205462680fc88d48aa100d1c3f172752392e06..75d57d78e3b0294be8d2138590248c775ddb6048 100644 (file)
@@ -1,61 +1,14 @@
-use crate::traits::{self, ObligationCause, PredicateObligation};
+use crate::traits;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::Lrc;
-use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
-use rustc_infer::infer::free_regions::FreeRegionRelations;
-use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{self, InferCtxt, InferOk};
-use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
+use rustc_infer::infer::InferCtxt;
+use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
 use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt};
 use rustc_span::Span;
 
-use std::ops::ControlFlow;
-
-/// Whether member constraints should be generated for all opaque types
-#[derive(Debug)]
-pub enum GenerateMemberConstraints {
-    /// The default, used by typeck
-    WhenRequired,
-    /// The borrow checker needs member constraints in any case where we don't
-    /// have a `'static` bound. This is because the borrow checker has more
-    /// flexibility in the values of regions. For example, given `f<'a, 'b>`
-    /// the borrow checker can have an inference variable outlive `'a` and `'b`,
-    /// but not be equal to `'static`.
-    IfNoStaticBound,
-}
-
 pub trait InferCtxtExt<'tcx> {
-    fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
-        &self,
-        body_id: hir::HirId,
-        param_env: ty::ParamEnv<'tcx>,
-        value: T,
-        value_span: Span,
-    ) -> InferOk<'tcx, T>;
-
-    fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR);
-
-    fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
-        &self,
-        opaque_type_key: OpaqueTypeKey<'tcx>,
-        opaque_defn: &OpaqueTypeDecl<'tcx>,
-        mode: GenerateMemberConstraints,
-        free_region_relations: &FRR,
-    );
-
-    /*private*/
-    fn generate_member_constraint(
-        &self,
-        concrete_ty: Ty<'tcx>,
-        opaque_defn: &OpaqueTypeDecl<'tcx>,
-        opaque_type_key: OpaqueTypeKey<'tcx>,
-        first_own_region_index: usize,
-    );
-
     fn infer_opaque_definition_from_instantiation(
         &self,
         opaque_type_key: OpaqueTypeKey<'tcx>,
@@ -65,416 +18,6 @@ fn infer_opaque_definition_from_instantiation(
 }
 
 impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
-    /// Replaces all opaque types in `value` with fresh inference variables
-    /// and creates appropriate obligations. For example, given the input:
-    ///
-    ///     impl Iterator<Item = impl Debug>
-    ///
-    /// this method would create two type variables, `?0` and `?1`. It would
-    /// return the type `?0` but also the obligations:
-    ///
-    ///     ?0: Iterator<Item = ?1>
-    ///     ?1: Debug
-    ///
-    /// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to
-    /// info about the `impl Iterator<..>` type and `?1` to info about
-    /// the `impl Debug` type.
-    ///
-    /// # Parameters
-    ///
-    /// - `parent_def_id` -- the `DefId` of the function in which the opaque type
-    ///   is defined
-    /// - `body_id` -- the body-id with which the resulting obligations should
-    ///   be associated
-    /// - `param_env` -- the in-scope parameter environment to be used for
-    ///   obligations
-    /// - `value` -- the value within which we are instantiating opaque types
-    /// - `value_span` -- the span where the value came from, used in error reporting
-    fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
-        &self,
-        body_id: hir::HirId,
-        param_env: ty::ParamEnv<'tcx>,
-        value: T,
-        value_span: Span,
-    ) -> InferOk<'tcx, T> {
-        debug!(
-            "instantiate_opaque_types(value={:?}, body_id={:?}, \
-             param_env={:?}, value_span={:?})",
-            value, body_id, param_env, value_span,
-        );
-        let mut instantiator =
-            Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
-        let value = instantiator.instantiate_opaque_types_in_map(value);
-        InferOk { value, obligations: instantiator.obligations }
-    }
-
-    /// Given the map `opaque_types` containing the opaque
-    /// `impl Trait` types whose underlying, hidden types are being
-    /// inferred, this method adds constraints to the regions
-    /// appearing in those underlying hidden types to ensure that they
-    /// at least do not refer to random scopes within the current
-    /// function. These constraints are not (quite) sufficient to
-    /// guarantee that the regions are actually legal values; that
-    /// final condition is imposed after region inference is done.
-    ///
-    /// # The Problem
-    ///
-    /// Let's work through an example to explain how it works. Assume
-    /// the current function is as follows:
-    ///
-    /// ```text
-    /// fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>)
-    /// ```
-    ///
-    /// Here, we have two `impl Trait` types whose values are being
-    /// inferred (the `impl Bar<'a>` and the `impl
-    /// Bar<'b>`). Conceptually, this is sugar for a setup where we
-    /// define underlying opaque types (`Foo1`, `Foo2`) and then, in
-    /// the return type of `foo`, we *reference* those definitions:
-    ///
-    /// ```text
-    /// type Foo1<'x> = impl Bar<'x>;
-    /// type Foo2<'x> = impl Bar<'x>;
-    /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
-    ///                    //  ^^^^ ^^
-    ///                    //  |    |
-    ///                    //  |    substs
-    ///                    //  def_id
-    /// ```
-    ///
-    /// As indicating in the comments above, each of those references
-    /// is (in the compiler) basically a substitution (`substs`)
-    /// applied to the type of a suitable `def_id` (which identifies
-    /// `Foo1` or `Foo2`).
-    ///
-    /// Now, at this point in compilation, what we have done is to
-    /// replace each of the references (`Foo1<'a>`, `Foo2<'b>`) with
-    /// fresh inference variables C1 and C2. We wish to use the values
-    /// of these variables to infer the underlying types of `Foo1` and
-    /// `Foo2`. That is, this gives rise to higher-order (pattern) unification
-    /// constraints like:
-    ///
-    /// ```text
-    /// for<'a> (Foo1<'a> = C1)
-    /// for<'b> (Foo1<'b> = C2)
-    /// ```
-    ///
-    /// For these equation to be satisfiable, the types `C1` and `C2`
-    /// can only refer to a limited set of regions. For example, `C1`
-    /// can only refer to `'static` and `'a`, and `C2` can only refer
-    /// to `'static` and `'b`. The job of this function is to impose that
-    /// constraint.
-    ///
-    /// Up to this point, C1 and C2 are basically just random type
-    /// inference variables, and hence they may contain arbitrary
-    /// regions. In fact, it is fairly likely that they do! Consider
-    /// this possible definition of `foo`:
-    ///
-    /// ```text
-    /// fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) {
-    ///         (&*x, &*y)
-    ///     }
-    /// ```
-    ///
-    /// Here, the values for the concrete types of the two impl
-    /// traits will include inference variables:
-    ///
-    /// ```text
-    /// &'0 i32
-    /// &'1 i32
-    /// ```
-    ///
-    /// Ordinarily, the subtyping rules would ensure that these are
-    /// sufficiently large. But since `impl Bar<'a>` isn't a specific
-    /// type per se, we don't get such constraints by default. This
-    /// is where this function comes into play. It adds extra
-    /// constraints to ensure that all the regions which appear in the
-    /// inferred type are regions that could validly appear.
-    ///
-    /// This is actually a bit of a tricky constraint in general. We
-    /// want to say that each variable (e.g., `'0`) can only take on
-    /// values that were supplied as arguments to the opaque type
-    /// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in
-    /// scope. We don't have a constraint quite of this kind in the current
-    /// region checker.
-    ///
-    /// # The Solution
-    ///
-    /// We generally prefer to make `<=` constraints, since they
-    /// integrate best into the region solver. To do that, we find the
-    /// "minimum" of all the arguments that appear in the substs: that
-    /// is, some region which is less than all the others. In the case
-    /// of `Foo1<'a>`, that would be `'a` (it's the only choice, after
-    /// all). Then we apply that as a least bound to the variables
-    /// (e.g., `'a <= '0`).
-    ///
-    /// In some cases, there is no minimum. Consider this example:
-    ///
-    /// ```text
-    /// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... }
-    /// ```
-    ///
-    /// Here we would report a more complex "in constraint", like `'r
-    /// in ['a, 'b, 'static]` (where `'r` is some region appearing in
-    /// the hidden type).
-    ///
-    /// # Constrain regions, not the hidden concrete type
-    ///
-    /// Note that generating constraints on each region `Rc` is *not*
-    /// the same as generating an outlives constraint on `Tc` iself.
-    /// For example, if we had a function like this:
-    ///
-    /// ```rust
-    /// fn foo<'a, T>(x: &'a u32, y: T) -> impl Foo<'a> {
-    ///   (x, y)
-    /// }
-    ///
-    /// // Equivalent to:
-    /// type FooReturn<'a, T> = impl Foo<'a>;
-    /// fn foo<'a, T>(..) -> FooReturn<'a, T> { .. }
-    /// ```
-    ///
-    /// then the hidden type `Tc` would be `(&'0 u32, T)` (where `'0`
-    /// is an inference variable). If we generated a constraint that
-    /// `Tc: 'a`, then this would incorrectly require that `T: 'a` --
-    /// but this is not necessary, because the opaque type we
-    /// create will be allowed to reference `T`. So we only generate a
-    /// constraint that `'0: 'a`.
-    ///
-    /// # The `free_region_relations` parameter
-    ///
-    /// The `free_region_relations` argument is used to find the
-    /// "minimum" of the regions supplied to a given opaque type.
-    /// It must be a relation that can answer whether `'a <= 'b`,
-    /// where `'a` and `'b` are regions that appear in the "substs"
-    /// for the opaque type references (the `<'a>` in `Foo1<'a>`).
-    ///
-    /// Note that we do not impose the constraints based on the
-    /// generic regions from the `Foo1` definition (e.g., `'x`). This
-    /// is because the constraints we are imposing here is basically
-    /// the concern of the one generating the constraining type C1,
-    /// which is the current function. It also means that we can
-    /// take "implied bounds" into account in some cases:
-    ///
-    /// ```text
-    /// trait SomeTrait<'a, 'b> { }
-    /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. }
-    /// ```
-    ///
-    /// Here, the fact that `'b: 'a` is known only because of the
-    /// implied bounds from the `&'a &'b u32` parameter, and is not
-    /// "inherent" to the opaque type definition.
-    ///
-    /// # Parameters
-    ///
-    /// - `opaque_types` -- the map produced by `instantiate_opaque_types`
-    /// - `free_region_relations` -- something that can be used to relate
-    ///   the free regions (`'a`) that appear in the impl trait.
-    fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR) {
-        let opaque_types = self.inner.borrow().opaque_types.clone();
-        for (opaque_type_key, opaque_defn) in opaque_types {
-            self.constrain_opaque_type(
-                opaque_type_key,
-                &opaque_defn,
-                GenerateMemberConstraints::WhenRequired,
-                free_region_relations,
-            );
-        }
-    }
-
-    /// See `constrain_opaque_types` for documentation.
-    #[instrument(level = "debug", skip(self, free_region_relations))]
-    fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
-        &self,
-        opaque_type_key: OpaqueTypeKey<'tcx>,
-        opaque_defn: &OpaqueTypeDecl<'tcx>,
-        mode: GenerateMemberConstraints,
-        free_region_relations: &FRR,
-    ) {
-        let def_id = opaque_type_key.def_id;
-
-        let tcx = self.tcx;
-
-        let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
-
-        debug!(?concrete_ty);
-
-        let first_own_region = match opaque_defn.origin {
-            hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => {
-                // We lower
-                //
-                // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
-                //
-                // into
-                //
-                // type foo::<'p0..'pn>::Foo<'q0..'qm>
-                // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
-                //
-                // For these types we only iterate over `'l0..lm` below.
-                tcx.generics_of(def_id).parent_count
-            }
-            // These opaque type inherit all lifetime parameters from their
-            // parent, so we have to check them all.
-            hir::OpaqueTyOrigin::TyAlias => 0,
-        };
-
-        let span = tcx.def_span(def_id);
-
-        // Check if the `impl Trait` bounds include region bounds.
-        // For example, this would be true for:
-        //
-        //     fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b
-        //
-        // but false for:
-        //
-        //     fn foo<'c>() -> impl Trait<'c>
-        //
-        // unless `Trait` was declared like:
-        //
-        //     trait Trait<'c>: 'c
-        //
-        // in which case it would be true.
-        //
-        // This is used during regionck to decide whether we need to
-        // impose any additional constraints to ensure that region
-        // variables in `concrete_ty` wind up being constrained to
-        // something from `substs` (or, at minimum, things that outlive
-        // the fn body). (Ultimately, writeback is responsible for this
-        // check.)
-        let bounds = tcx.explicit_item_bounds(def_id);
-        debug!("{:#?}", bounds);
-        let bounds = bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs));
-        debug!("{:#?}", bounds);
-        let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs);
-
-        let required_region_bounds = required_region_bounds(tcx, opaque_type, bounds);
-        if !required_region_bounds.is_empty() {
-            for required_region in required_region_bounds {
-                concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
-                    tcx,
-                    op: |r| self.sub_regions(infer::CallReturn(span), required_region, r),
-                });
-            }
-            if let GenerateMemberConstraints::IfNoStaticBound = mode {
-                self.generate_member_constraint(
-                    concrete_ty,
-                    opaque_defn,
-                    opaque_type_key,
-                    first_own_region,
-                );
-            }
-            return;
-        }
-
-        // There were no `required_region_bounds`,
-        // so we have to search for a `least_region`.
-        // Go through all the regions used as arguments to the
-        // opaque type. These are the parameters to the opaque
-        // type; so in our example above, `substs` would contain
-        // `['a]` for the first impl trait and `'b` for the
-        // second.
-        let mut least_region = None;
-
-        for subst_arg in &opaque_type_key.substs[first_own_region..] {
-            let subst_region = match subst_arg.unpack() {
-                GenericArgKind::Lifetime(r) => r,
-                GenericArgKind::Type(_) | GenericArgKind::Const(_) => continue,
-            };
-
-            // Compute the least upper bound of it with the other regions.
-            debug!(?least_region);
-            debug!(?subst_region);
-            match least_region {
-                None => least_region = Some(subst_region),
-                Some(lr) => {
-                    if free_region_relations.sub_free_regions(self.tcx, lr, subst_region) {
-                        // keep the current least region
-                    } else if free_region_relations.sub_free_regions(self.tcx, subst_region, lr) {
-                        // switch to `subst_region`
-                        least_region = Some(subst_region);
-                    } else {
-                        // There are two regions (`lr` and
-                        // `subst_region`) which are not relatable. We
-                        // can't find a best choice. Therefore,
-                        // instead of creating a single bound like
-                        // `'r: 'a` (which is our preferred choice),
-                        // we will create a "in bound" like `'r in
-                        // ['a, 'b, 'c]`, where `'a..'c` are the
-                        // regions that appear in the impl trait.
-
-                        return self.generate_member_constraint(
-                            concrete_ty,
-                            opaque_defn,
-                            opaque_type_key,
-                            first_own_region,
-                        );
-                    }
-                }
-            }
-        }
-
-        let least_region = least_region.unwrap_or(tcx.lifetimes.re_static);
-        debug!(?least_region);
-
-        if let GenerateMemberConstraints::IfNoStaticBound = mode {
-            if least_region != tcx.lifetimes.re_static {
-                self.generate_member_constraint(
-                    concrete_ty,
-                    opaque_defn,
-                    opaque_type_key,
-                    first_own_region,
-                );
-            }
-        }
-        concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
-            tcx,
-            op: |r| self.sub_regions(infer::CallReturn(span), least_region, r),
-        });
-    }
-
-    /// As a fallback, we sometimes generate an "in constraint". For
-    /// a case like `impl Foo<'a, 'b>`, where `'a` and `'b` cannot be
-    /// related, we would generate a constraint `'r in ['a, 'b,
-    /// 'static]` for each region `'r` that appears in the hidden type
-    /// (i.e., it must be equal to `'a`, `'b`, or `'static`).
-    ///
-    /// `conflict1` and `conflict2` are the two region bounds that we
-    /// detected which were unrelated. They are used for diagnostics.
-    fn generate_member_constraint(
-        &self,
-        concrete_ty: Ty<'tcx>,
-        opaque_defn: &OpaqueTypeDecl<'tcx>,
-        opaque_type_key: OpaqueTypeKey<'tcx>,
-        first_own_region: usize,
-    ) {
-        // Create the set of choice regions: each region in the hidden
-        // type can be equal to any of the region parameters of the
-        // opaque type definition.
-        let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
-            opaque_type_key.substs[first_own_region..]
-                .iter()
-                .filter_map(|arg| match arg.unpack() {
-                    GenericArgKind::Lifetime(r) => Some(r),
-                    GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
-                })
-                .chain(std::iter::once(self.tcx.lifetimes.re_static))
-                .collect(),
-        );
-
-        concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
-            tcx: self.tcx,
-            op: |r| {
-                self.member_constraint(
-                    opaque_type_key.def_id,
-                    opaque_defn.definition_span,
-                    concrete_ty,
-                    r,
-                    &choice_regions,
-                )
-            },
-        });
-    }
-
     /// Given the fully resolved, instantiated type for an opaque
     /// type, i.e., the value of an inference variable like C1 or C2
     /// (*), computes the "definition type" for an opaque type
@@ -490,7 +33,7 @@ fn generate_member_constraint(
     /// purpose of this function is to do that translation.
     ///
     /// (*) C1 and C2 were introduced in the comments on
-    /// `constrain_opaque_types`. Read that comment for more context.
+    /// `constrain_opaque_type`. Read that comment for more context.
     ///
     /// # Parameters
     ///
@@ -536,83 +79,6 @@ fn infer_opaque_definition_from_instantiation(
     }
 }
 
-// Visitor that requires that (almost) all regions in the type visited outlive
-// `least_region`. We cannot use `push_outlives_components` because regions in
-// closure signatures are not included in their outlives components. We need to
-// ensure all regions outlive the given bound so that we don't end up with,
-// say, `ReVar` appearing in a return type and causing ICEs when other
-// functions end up with region constraints involving regions from other
-// functions.
-//
-// We also cannot use `for_each_free_region` because for closures it includes
-// the regions parameters from the enclosing item.
-//
-// 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>,
-    op: OP,
-}
-
-impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, 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>,
-    ) -> ControlFlow<Self::BreakTy> {
-        t.as_ref().skip_binder().visit_with(self);
-        ControlFlow::CONTINUE
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match *r {
-            // ignore bound regions, keep visiting
-            ty::ReLateBound(_, _) => ControlFlow::CONTINUE,
-            _ => {
-                (self.op)(r);
-                ControlFlow::CONTINUE
-            }
-        }
-    }
-
-    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) {
-            return ControlFlow::CONTINUE;
-        }
-
-        match ty.kind() {
-            ty::Closure(_, ref substs) => {
-                // Skip lifetime parameters of the enclosing item(s)
-
-                substs.as_closure().tupled_upvars_ty().visit_with(self);
-                substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
-            }
-
-            ty::Generator(_, ref substs, _) => {
-                // Skip lifetime parameters of the enclosing item(s)
-                // Also skip the witness type, because that has no free regions.
-
-                substs.as_generator().tupled_upvars_ty().visit_with(self);
-                substs.as_generator().return_ty().visit_with(self);
-                substs.as_generator().yield_ty().visit_with(self);
-                substs.as_generator().resume_ty().visit_with(self);
-            }
-            _ => {
-                ty.super_visit_with(self);
-            }
-        }
-
-        ControlFlow::CONTINUE
-    }
-}
-
 struct ReverseMapper<'tcx> {
     tcx: TyCtxt<'tcx>,
 
@@ -855,235 +321,6 @@ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
     }
 }
 
-struct Instantiator<'a, 'tcx> {
-    infcx: &'a InferCtxt<'a, 'tcx>,
-    body_id: hir::HirId,
-    param_env: ty::ParamEnv<'tcx>,
-    value_span: Span,
-    obligations: Vec<PredicateObligation<'tcx>>,
-}
-
-impl<'a, 'tcx> Instantiator<'a, 'tcx> {
-    fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
-        let tcx = self.infcx.tcx;
-        value.fold_with(&mut BottomUpFolder {
-            tcx,
-            ty_op: |ty| {
-                if ty.references_error() {
-                    return tcx.ty_error();
-                } else if let ty::Opaque(def_id, substs) = ty.kind() {
-                    // Check that this is `impl Trait` type is
-                    // declared by `parent_def_id` -- i.e., one whose
-                    // value we are inferring.  At present, this is
-                    // always true during the first phase of
-                    // type-check, but not always true later on during
-                    // NLL. Once we support named opaque types more fully,
-                    // this same scenario will be able to arise during all phases.
-                    //
-                    // Here is an example using type alias `impl Trait`
-                    // that indicates the distinction we are checking for:
-                    //
-                    // ```rust
-                    // mod a {
-                    //   pub type Foo = impl Iterator;
-                    //   pub fn make_foo() -> Foo { .. }
-                    // }
-                    //
-                    // mod b {
-                    //   fn foo() -> a::Foo { a::make_foo() }
-                    // }
-                    // ```
-                    //
-                    // Here, the return type of `foo` references an
-                    // `Opaque` indeed, but not one whose value is
-                    // presently being inferred. You can get into a
-                    // similar situation with closure return types
-                    // today:
-                    //
-                    // ```rust
-                    // fn foo() -> impl Iterator { .. }
-                    // fn bar() {
-                    //     let x = || foo(); // returns the Opaque assoc with `foo`
-                    // }
-                    // ```
-                    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 def_scope_default = || {
-                            let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
-                            parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
-                        };
-                        let (in_definition_scope, origin) =
-                            match tcx.hir().expect_item(opaque_hir_id).kind {
-                                // Anonymous `impl Trait`
-                                hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-                                    impl_trait_fn: Some(parent),
-                                    origin,
-                                    ..
-                                }) => (parent == parent_def_id.to_def_id(), origin),
-                                // Named `type Foo = impl Bar;`
-                                hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-                                    impl_trait_fn: None,
-                                    origin,
-                                    ..
-                                }) => (
-                                    may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
-                                    origin,
-                                ),
-                                _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
-                            };
-                        if in_definition_scope {
-                            let opaque_type_key =
-                                OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
-                            return self.fold_opaque_ty(ty, opaque_type_key, origin);
-                        }
-
-                        debug!(
-                            "instantiate_opaque_types_in_map: \
-                             encountered opaque outside its definition scope \
-                             def_id={:?}",
-                            def_id,
-                        );
-                    }
-                }
-
-                ty
-            },
-            lt_op: |lt| lt,
-            ct_op: |ct| ct,
-        })
-    }
-
-    #[instrument(skip(self), level = "debug")]
-    fn fold_opaque_ty(
-        &mut self,
-        ty: Ty<'tcx>,
-        opaque_type_key: OpaqueTypeKey<'tcx>,
-        origin: hir::OpaqueTyOrigin,
-    ) -> Ty<'tcx> {
-        let infcx = self.infcx;
-        let tcx = infcx.tcx;
-        let OpaqueTypeKey { def_id, substs } = opaque_type_key;
-
-        // Use the same type variable if the exact same opaque type appears more
-        // than once in the return type (e.g., if it's passed to a type alias).
-        if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
-            debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
-            return opaque_defn.concrete_ty;
-        }
-
-        let ty_var = infcx.next_ty_var(TypeVariableOrigin {
-            kind: TypeVariableOriginKind::TypeInference,
-            span: self.value_span,
-        });
-
-        // Ideally, we'd get the span where *this specific `ty` came
-        // from*, but right now we just use the span from the overall
-        // value being folded. In simple cases like `-> impl Foo`,
-        // these are the same span, but not in cases like `-> (impl
-        // Foo, impl Bar)`.
-        let definition_span = self.value_span;
-
-        {
-            let mut infcx = self.infcx.inner.borrow_mut();
-            infcx.opaque_types.insert(
-                OpaqueTypeKey { def_id, substs },
-                OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
-            );
-            infcx.opaque_types_vars.insert(ty_var, ty);
-        }
-
-        debug!("generated new type inference var {:?}", ty_var.kind());
-
-        let item_bounds = tcx.explicit_item_bounds(def_id);
-
-        self.obligations.reserve(item_bounds.len());
-        for (predicate, _) in item_bounds {
-            debug!(?predicate);
-            let predicate = predicate.subst(tcx, substs);
-            debug!(?predicate);
-
-            // 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,
-                ty_op: |ty| match ty.kind() {
-                    ty::Projection(projection_ty) => infcx.infer_projection(
-                        self.param_env,
-                        *projection_ty,
-                        ObligationCause::misc(self.value_span, self.body_id),
-                        0,
-                        &mut self.obligations,
-                    ),
-                    _ => ty,
-                },
-                lt_op: |lt| lt,
-                ct_op: |ct| ct,
-            });
-            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.
-                    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);
-
-            // Require that the predicate holds for the concrete type.
-            debug!(?predicate);
-            self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
-        }
-
-        ty_var
-    }
-}
-
-/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`.
-///
-/// Example:
-/// ```rust
-/// pub mod foo {
-///     pub mod bar {
-///         pub trait Bar { .. }
-///
-///         pub type Baz = impl Bar;
-///
-///         fn f1() -> Baz { .. }
-///     }
-///
-///     fn f2() -> bar::Baz { .. }
-/// }
-/// ```
-///
-/// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`),
-/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`.
-/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
-fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool {
-    let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-
-    // Named opaque types can be defined by any siblings or children of siblings.
-    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);
-    }
-    // Syntactically, we are allowed to define the concrete type if:
-    let res = hir_id == scope;
-    trace!(
-        "may_define_opaque_type(def={:?}, opaque_node={:?}) = {}",
-        tcx.hir().find(hir_id),
-        tcx.hir().get(opaque_hir_id),
-        res
-    );
-    res
-}
-
 /// Given a set of predicates that apply to an object type, returns
 /// the region bounds that the (erased) `Self` type must
 /// outlive. Precisely *because* the `Self` type is erased, the
index 622c9edc4345035b2af384334f8109d424489ac8..6452b520452d6802b157c023ecf457620a3da1c3 100644 (file)
@@ -286,6 +286,8 @@ fn evaluate_predicates(
                 substs: infcx.tcx.mk_substs_trait(ty, &[]),
             },
             constness: ty::BoundConstness::NotConst,
+            // Auto traits are positive
+            polarity: ty::ImplPolarity::Positive,
         }));
 
         let computed_preds = param_env.caller_bounds().iter();
index 668a74bd6971506b02351ac309a8b892db2661e8..42d3194aed48af5883490d2d7be5d738024b209e 100644 (file)
@@ -5,9 +5,12 @@
 //! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
 
 use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt};
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::select::IntercrateAmbiguityCause;
 use crate::traits::SkipLeakCheck;
-use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext};
+use crate::traits::{
+    self, Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext,
+};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::Subst;
@@ -158,6 +161,19 @@ fn overlap_within_probe(
     b_def_id: DefId,
     snapshot: &CombinedSnapshot<'_, 'tcx>,
 ) -> Option<OverlapResult<'tcx>> {
+    fn loose_check(selcx: &mut SelectionContext<'cx, 'tcx>, o: &PredicateObligation<'tcx>) -> bool {
+        !selcx.predicate_may_hold_fatal(o)
+    }
+
+    fn strict_check(selcx: &SelectionContext<'cx, 'tcx>, o: &PredicateObligation<'tcx>) -> bool {
+        let infcx = selcx.infcx();
+        let tcx = infcx.tcx;
+        o.flip_polarity(tcx)
+            .as_ref()
+            .map(|o| selcx.infcx().predicate_must_hold_modulo_regions(o))
+            .unwrap_or(false)
+    }
+
     // For the purposes of this check, we don't bring any placeholder
     // types into scope; instead, we replace the generic types with
     // fresh type variables, and hence we do our evaluations in an
@@ -184,8 +200,29 @@ fn overlap_within_probe(
 
     debug!("overlap: unification check succeeded");
 
-    // Are any of the obligations unsatisfiable? If so, no overlap.
+    // There's no overlap if obligations are unsatisfiable or if the obligation negated is
+    // satisfied.
+    //
+    // For example, given these two impl headers:
+    //
+    // `impl<'a> From<&'a str> for Box<dyn Error>`
+    // `impl<E> From<E> for Box<dyn Error> where E: Error`
+    //
+    // So we have:
+    //
+    // `Box<dyn Error>: From<&'?a str>`
+    // `Box<dyn Error>: From<?E>`
+    //
+    // After equating the two headers:
+    //
+    // `Box<dyn Error> = Box<dyn Error>`
+    // So, `?E = &'?a str` and then given the where clause `&'?a str: Error`.
+    //
+    // If the obligation `&'?a str: Error` holds, it means that there's overlap. If that doesn't
+    // hold we need to check if `&'?a str: !Error` holds, if doesn't hold there's overlap because
+    // at some point an impl for `&'?a str: Error` could be added.
     let infcx = selcx.infcx();
+    let tcx = infcx.tcx;
     let opt_failing_obligation = a_impl_header
         .predicates
         .iter()
@@ -199,7 +236,17 @@ fn overlap_within_probe(
             predicate: p,
         })
         .chain(obligations)
-        .find(|o| !selcx.predicate_may_hold_fatal(o));
+        .find(|o| {
+            // if both impl headers are set to strict coherence it means that this will be accepted
+            // only if it's stated that T: !Trait. So only prove that the negated obligation holds.
+            if tcx.has_attr(a_def_id, sym::rustc_strict_coherence)
+                && tcx.has_attr(b_def_id, sym::rustc_strict_coherence)
+            {
+                strict_check(selcx, o)
+            } else {
+                loose_check(selcx, o) || tcx.features().negative_impls && strict_check(selcx, o)
+            }
+        });
     // FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported
     // to the canonical trait query form, `infcx.predicate_may_hold`, once
     // the new system supports intercrate mode (which coherence needs).
index 1193d10d6a7d730e8631ecfa1c8bbb826baee67d..8edb7069fc45f9a19c55f3c66f75a0bc79b9870f 100644 (file)
@@ -80,9 +80,8 @@ enum FailureKind {
                     Concrete,
                 }
                 let mut failure_kind = FailureKind::Concrete;
-                walk_abstract_const::<!, _>(tcx, ct, |node| match node.root() {
+                walk_abstract_const::<!, _>(tcx, ct, |node| match node.root(tcx) {
                     Node::Leaf(leaf) => {
-                        let leaf = leaf.subst(tcx, ct.substs);
                         if leaf.has_infer_types_or_consts() {
                             failure_kind = FailureKind::MentionsInfer;
                         } else if leaf.definitely_has_param_types_or_consts(tcx) {
@@ -92,7 +91,6 @@ enum FailureKind {
                         ControlFlow::CONTINUE
                     }
                     Node::Cast(_, _, ty) => {
-                        let ty = ty.subst(tcx, ct.substs);
                         if ty.has_infer_types_or_consts() {
                             failure_kind = FailureKind::MentionsInfer;
                         } else if ty.definitely_has_param_types_or_consts(tcx) {
@@ -187,8 +185,8 @@ enum FailureKind {
 pub struct AbstractConst<'tcx> {
     // FIXME: Consider adding something like `IndexSlice`
     // and use this here.
-    pub inner: &'tcx [Node<'tcx>],
-    pub substs: SubstsRef<'tcx>,
+    inner: &'tcx [Node<'tcx>],
+    substs: SubstsRef<'tcx>,
 }
 
 impl<'tcx> AbstractConst<'tcx> {
@@ -218,8 +216,14 @@ pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> {
     }
 
     #[inline]
-    pub fn root(self) -> Node<'tcx> {
-        self.inner.last().copied().unwrap()
+    pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> {
+        let node = self.inner.last().copied().unwrap();
+        match node {
+            Node::Leaf(leaf) => Node::Leaf(leaf.subst(tcx, self.substs)),
+            Node::Cast(kind, operand, ty) => Node::Cast(kind, operand, ty.subst(tcx, self.substs)),
+            // Don't perform substitution on the following as they can't directly contain generic params
+            Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node,
+        }
     }
 }
 
@@ -542,7 +546,7 @@ fn recurse<'tcx, R>(
         f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow<R>,
     ) -> ControlFlow<R> {
         f(ct)?;
-        let root = ct.root();
+        let root = ct.root(tcx);
         match root {
             Node::Leaf(_) => ControlFlow::CONTINUE,
             Node::Binop(_, l, r) => {
@@ -570,16 +574,14 @@ pub(super) fn try_unify<'tcx>(
     // We substitute generics repeatedly to allow AbstractConsts to unify where a
     // ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g.
     // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
-    while let Node::Leaf(a_ct) = a.root() {
-        let a_ct = a_ct.subst(tcx, a.substs);
+    while let Node::Leaf(a_ct) = a.root(tcx) {
         match AbstractConst::from_const(tcx, a_ct) {
             Ok(Some(a_act)) => a = a_act,
             Ok(None) => break,
             Err(_) => return true,
         }
     }
-    while let Node::Leaf(b_ct) = b.root() {
-        let b_ct = b_ct.subst(tcx, b.substs);
+    while let Node::Leaf(b_ct) = b.root(tcx) {
         match AbstractConst::from_const(tcx, b_ct) {
             Ok(Some(b_act)) => b = b_act,
             Ok(None) => break,
@@ -587,10 +589,8 @@ pub(super) fn try_unify<'tcx>(
         }
     }
 
-    match (a.root(), b.root()) {
+    match (a.root(tcx), b.root(tcx)) {
         (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
-            let a_ct = a_ct.subst(tcx, a.substs);
-            let b_ct = b_ct.subst(tcx, b.substs);
             if a_ct.ty != b_ct.ty {
                 return false;
             }
index 225ff5e597ed03a097d6f94fb584a41488261a83..a9125b9fd2280ed259e52e0dcffccc54ce941169 100644 (file)
@@ -34,6 +34,7 @@
 
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use crate::traits::query::normalize::AtExt as _;
+use crate::traits::specialize::to_pretty_impl_header;
 use on_unimplemented::InferCtxtExt as _;
 use suggestions::InferCtxtExt as _;
 
@@ -241,6 +242,15 @@ fn report_selection_error(
         let mut span = obligation.cause.span;
 
         let mut err = match *error {
+            SelectionError::Ambiguous(ref impls) => {
+                let mut err = self.tcx.sess.struct_span_err(
+                    obligation.cause.span,
+                    &format!("multiple applicable `impl`s for `{}`", obligation.predicate),
+                );
+                self.annotate_source_of_ambiguity(&mut err, impls, obligation.predicate);
+                err.emit();
+                return;
+            }
             SelectionError::Unimplemented => {
                 // If this obligation was generated as a result of well-formedness checking, see if we
                 // can get a better error message by performing HIR-based well-formedness checking.
@@ -1138,6 +1148,13 @@ fn suggest_unsized_bound_if_applicable(
         obligation: &PredicateObligation<'tcx>,
     );
 
+    fn annotate_source_of_ambiguity(
+        &self,
+        err: &mut DiagnosticBuilder<'tcx>,
+        impls: &[DefId],
+        predicate: ty::Predicate<'tcx>,
+    );
+
     fn maybe_suggest_unsized_generics(
         &self,
         err: &mut DiagnosticBuilder<'tcx>,
@@ -1475,6 +1492,9 @@ fn get_parent_trait_ref(
                     }
                 }
             }
+            ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
+                self.get_parent_trait_ref(&parent_code)
+            }
             _ => None,
         }
     }
@@ -1549,11 +1569,8 @@ fn maybe_report_ambiguity(
             ?predicate, ?obligation.cause.code,
         );
 
-        // Ambiguity errors are often caused as fallout from earlier
-        // errors. So just ignore them if this infcx is tainted.
-        if self.is_tainted_by_errors() {
-            return;
-        }
+        // Ambiguity errors are often caused as fallout from earlier errors.
+        // We ignore them if this `infcx` is tainted in some cases below.
 
         let bound_predicate = predicate.kind();
         let mut err = match bound_predicate.skip_binder() {
@@ -1601,10 +1618,19 @@ fn maybe_report_ambiguity(
                 // check upstream for type errors and don't add the obligations to
                 // begin with in those cases.
                 if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
-                    self.emit_inference_failure_err(body_id, span, subst, vec![], ErrorCode::E0282)
+                    if !self.is_tainted_by_errors() {
+                        self.emit_inference_failure_err(
+                            body_id,
+                            span,
+                            subst,
+                            vec![],
+                            ErrorCode::E0282,
+                        )
                         .emit();
+                    }
                     return;
                 }
+
                 let impl_candidates = self.find_similar_impl_candidates(trait_ref);
                 let mut err = self.emit_inference_failure_err(
                     body_id,
@@ -1613,7 +1639,29 @@ fn maybe_report_ambiguity(
                     impl_candidates,
                     ErrorCode::E0283,
                 );
-                err.note(&format!("cannot satisfy `{}`", predicate));
+
+                let obligation = Obligation::new(
+                    obligation.cause.clone(),
+                    obligation.param_env,
+                    trait_ref.to_poly_trait_predicate(),
+                );
+                let mut selcx = SelectionContext::with_query_mode(
+                    &self,
+                    crate::traits::TraitQueryMode::Standard,
+                );
+                match selcx.select_from_obligation(&obligation) {
+                    Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => {
+                        self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+                    }
+                    _ => {
+                        if self.is_tainted_by_errors() {
+                            err.cancel();
+                            return;
+                        }
+                        err.note(&format!("cannot satisfy `{}`", predicate));
+                    }
+                }
+
                 if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
                     self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
                 } else if let (
@@ -1674,7 +1722,10 @@ fn maybe_report_ambiguity(
             ty::PredicateKind::WellFormed(arg) => {
                 // Same hacky approach as above to avoid deluging user
                 // with error messages.
-                if arg.references_error() || self.tcx.sess.has_errors() {
+                if arg.references_error()
+                    || self.tcx.sess.has_errors()
+                    || self.is_tainted_by_errors()
+                {
                     return;
                 }
 
@@ -1682,7 +1733,10 @@ fn maybe_report_ambiguity(
             }
 
             ty::PredicateKind::Subtype(data) => {
-                if data.references_error() || self.tcx.sess.has_errors() {
+                if data.references_error()
+                    || self.tcx.sess.has_errors()
+                    || self.is_tainted_by_errors()
+                {
                     // no need to overload user in such cases
                     return;
                 }
@@ -1694,7 +1748,7 @@ fn maybe_report_ambiguity(
             ty::PredicateKind::Projection(data) => {
                 let self_ty = data.projection_ty.self_ty();
                 let ty = data.ty;
-                if predicate.references_error() {
+                if predicate.references_error() || self.is_tainted_by_errors() {
                     return;
                 }
                 if self_ty.needs_infer() && ty.needs_infer() {
@@ -1722,7 +1776,7 @@ fn maybe_report_ambiguity(
             }
 
             _ => {
-                if self.tcx.sess.has_errors() {
+                if self.tcx.sess.has_errors() || self.is_tainted_by_errors() {
                     return;
                 }
                 let mut err = struct_span_err!(
@@ -1740,6 +1794,96 @@ fn maybe_report_ambiguity(
         err.emit();
     }
 
+    fn annotate_source_of_ambiguity(
+        &self,
+        err: &mut DiagnosticBuilder<'tcx>,
+        impls: &[DefId],
+        predicate: ty::Predicate<'tcx>,
+    ) {
+        let mut spans = vec![];
+        let mut crates = vec![];
+        let mut post = vec![];
+        for def_id in impls {
+            match self.tcx.span_of_impl(*def_id) {
+                Ok(span) => spans.push(self.tcx.sess.source_map().guess_head_span(span)),
+                Err(name) => {
+                    crates.push(name);
+                    if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) {
+                        post.push(header);
+                    }
+                }
+            }
+        }
+        let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
+        let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
+        crate_names.sort();
+        crate_names.dedup();
+        post.sort();
+        post.dedup();
+
+        if self.is_tainted_by_errors()
+            && crate_names.len() == 1
+            && crate_names[0] == "`core`"
+            && spans.len() == 0
+        {
+            // Avoid complaining about other inference issues for expressions like
+            // `42 >> 1`, where the types are still `{integer}`, but we want to
+            // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too?
+            err.cancel();
+            return;
+        }
+        let post = if post.len() > 4 {
+            format!(
+                ":\n{}\nand {} more",
+                post.iter().map(|p| format!("- {}", p)).take(4).collect::<Vec<_>>().join("\n"),
+                post.len() - 4,
+            )
+        } else if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
+            format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
+        } else if post.len() == 1 {
+            format!(": `{}`", post[0])
+        } else {
+            String::new()
+        };
+
+        match (spans.len(), crates.len(), crate_names.len()) {
+            (0, 0, 0) => {
+                err.note(&format!("cannot satisfy `{}`", predicate));
+            }
+            (0, _, 1) => {
+                err.note(&format!("{} in the `{}` crate{}", msg, crates[0], post,));
+            }
+            (0, _, _) => {
+                err.note(&format!(
+                    "{} in the following crates: {}{}",
+                    msg,
+                    crate_names.join(", "),
+                    post,
+                ));
+            }
+            (_, 0, 0) => {
+                let span: MultiSpan = spans.into();
+                err.span_note(span, &msg);
+            }
+            (_, 1, 1) => {
+                let span: MultiSpan = spans.into();
+                err.span_note(span, &msg);
+                err.note(
+                    &format!("and another `impl` found in the `{}` crate{}", crates[0], post,),
+                );
+            }
+            _ => {
+                let span: MultiSpan = spans.into();
+                err.span_note(span, &msg);
+                err.note(&format!(
+                    "and more `impl`s found in the following crates: {}{}",
+                    crate_names.join(", "),
+                    post,
+                ));
+            }
+        }
+    }
+
     /// Returns `true` if the trait predicate may apply for *some* assignment
     /// to the type parameters.
     fn predicate_can_apply(
index 1a8f863952e6ad5cddaabc3247c5864edac6b354..2689e2134fc6b5e0ded2dd2e01f732375f0e4424 100644 (file)
@@ -151,7 +151,7 @@ fn note_obligation_cause_for_async_await(
         outer_generator: Option<DefId>,
         trait_ref: ty::TraitRef<'tcx>,
         target_ty: Ty<'tcx>,
-        typeck_results: &ty::TypeckResults<'tcx>,
+        typeck_results: Option<&ty::TypeckResults<'tcx>>,
         obligation: &PredicateObligation<'tcx>,
         next_code: Option<&ObligationCauseCode<'tcx>>,
     );
@@ -299,18 +299,15 @@ fn suggest_restriction(
                 generics,
                 trait_ref.without_const().to_predicate(tcx).to_string(),
             ),
-            (None, Some((ident, []))) => (
-                ident.span.shrink_to_hi(),
-                format!(": {}", trait_ref.print_only_trait_path().to_string()),
-            ),
-            (_, Some((_, [.., bounds]))) => (
-                bounds.span().shrink_to_hi(),
-                format!(" + {}", trait_ref.print_only_trait_path().to_string()),
-            ),
-            (Some(_), Some((_, []))) => (
-                generics.span.shrink_to_hi(),
-                format!(": {}", trait_ref.print_only_trait_path().to_string()),
-            ),
+            (None, Some((ident, []))) => {
+                (ident.span.shrink_to_hi(), format!(": {}", trait_ref.print_only_trait_path()))
+            }
+            (_, Some((_, [.., bounds]))) => {
+                (bounds.span().shrink_to_hi(), format!(" + {}", trait_ref.print_only_trait_path()))
+            }
+            (Some(_), Some((_, []))) => {
+                (generics.span.shrink_to_hi(), format!(": {}", trait_ref.print_only_trait_path()))
+            }
         };
 
         err.span_suggestion_verbose(
@@ -1038,13 +1035,11 @@ fn suggest_impl_trait(
         let hir = self.tcx.hir();
         let parent_node = hir.get_parent_node(obligation.cause.body_id);
         let node = hir.find(parent_node);
-        let (sig, body_id) = if let Some(hir::Node::Item(hir::Item {
+        let Some(hir::Node::Item(hir::Item {
             kind: hir::ItemKind::Fn(sig, _, body_id),
             ..
         })) = node
-        {
-            (sig, body_id)
-        } else {
+        else {
             return false;
         };
         let body = hir.body(*body_id);
@@ -1427,6 +1422,9 @@ fn maybe_note_obligation_cause_for_async_await(
         while let Some(code) = next_code {
             debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
             match code {
+                ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
+                    next_code = Some(parent_code.as_ref());
+                }
                 ObligationCauseCode::DerivedObligation(derived_obligation)
                 | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation)
                 | ObligationCauseCode::ImplDerivedObligation(derived_obligation) => {
@@ -1465,11 +1463,7 @@ fn maybe_note_obligation_cause_for_async_await(
         }
 
         // Only continue if a generator was found.
-        debug!(
-            "maybe_note_obligation_cause_for_async_await: generator={:?} trait_ref={:?} \
-                target_ty={:?}",
-            generator, trait_ref, target_ty
-        );
+        debug!(?generator, ?trait_ref, ?target_ty, "maybe_note_obligation_cause_for_async_await");
         let (generator_did, trait_ref, target_ty) = match (generator, trait_ref, target_ty) {
             (Some(generator_did), Some(trait_ref), Some(target_ty)) => {
                 (generator_did, trait_ref, target_ty)
@@ -1479,14 +1473,6 @@ fn maybe_note_obligation_cause_for_async_await(
 
         let span = self.tcx.def_span(generator_did);
 
-        // Do not ICE on closure typeck (#66868).
-        if !generator_did.is_local() {
-            return false;
-        }
-
-        // Get the typeck results from the infcx if the generator is the function we are
-        // currently type-checking; otherwise, get them by performing a query.
-        // This is needed to avoid cycles.
         let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
         let generator_did_root = self.tcx.closure_base_def_id(generator_did);
         debug!(
@@ -1497,14 +1483,6 @@ fn maybe_note_obligation_cause_for_async_await(
             in_progress_typeck_results.as_ref().map(|t| t.hir_owner),
             span
         );
-        let query_typeck_results;
-        let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results {
-            Some(t) if t.hir_owner.to_def_id() == generator_did_root => t,
-            _ => {
-                query_typeck_results = self.tcx.typeck(generator_did.expect_local());
-                &query_typeck_results
-            }
-        };
 
         let generator_body = generator_did
             .as_local()
@@ -1547,51 +1525,59 @@ fn maybe_note_obligation_cause_for_async_await(
         let mut interior_or_upvar_span = None;
         let mut interior_extra_info = None;
 
-        if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
-            interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
-                let upvar_ty = typeck_results.node_type(*upvar_id);
-                let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
-                if ty_matches(ty::Binder::dummy(upvar_ty)) {
-                    Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
-                } else {
-                    None
-                }
-            });
+        // Get the typeck results from the infcx if the generator is the function we are currently
+        // type-checking; otherwise, get them by performing a query.  This is needed to avoid
+        // cycles. If we can't use resolved types because the generator comes from another crate,
+        // we still provide a targeted error but without all the relevant spans.
+        let query_typeck_results;
+        let typeck_results: Option<&TypeckResults<'tcx>> = match &in_progress_typeck_results {
+            Some(t) if t.hir_owner.to_def_id() == generator_did_root => Some(&t),
+            _ if generator_did.is_local() => {
+                query_typeck_results = self.tcx.typeck(generator_did.expect_local());
+                Some(&query_typeck_results)
+            }
+            _ => None, // Do not ICE on closure typeck (#66868).
         };
+        if let Some(typeck_results) = typeck_results {
+            if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
+                interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
+                    let upvar_ty = typeck_results.node_type(*upvar_id);
+                    let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
+                    if ty_matches(ty::Binder::dummy(upvar_ty)) {
+                        Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
+                    } else {
+                        None
+                    }
+                });
+            };
 
-        // The generator interior types share the same binders
-        if let Some(cause) =
-            typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
-                |ty::GeneratorInteriorTypeCause { ty, .. }| {
-                    ty_matches(typeck_results.generator_interior_types.rebind(ty))
-                },
-            )
-        {
-            // Check to see if any awaited expressions have the target type.
-            let from_awaited_ty = visitor
-                .awaits
-                .into_iter()
-                .map(|id| hir.expect_expr(id))
-                .find(|await_expr| {
-                    let ty = typeck_results.expr_ty_adjusted(&await_expr);
-                    debug!(
-                        "maybe_note_obligation_cause_for_async_await: await_expr={:?}",
-                        await_expr
-                    );
-                    ty_matches(ty::Binder::dummy(ty))
-                })
-                .map(|expr| expr.span);
-            let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause;
+            // The generator interior types share the same binders
+            if let Some(cause) =
+                typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
+                    |ty::GeneratorInteriorTypeCause { ty, .. }| {
+                        ty_matches(typeck_results.generator_interior_types.rebind(ty))
+                    },
+                )
+            {
+                // Check to see if any awaited expressions have the target type.
+                let from_awaited_ty = visitor
+                    .awaits
+                    .into_iter()
+                    .map(|id| hir.expect_expr(id))
+                    .find(|await_expr| {
+                        ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
+                    })
+                    .map(|expr| expr.span);
+                let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
+                    cause;
 
-            interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
-            interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
-        };
+                interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
+                interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
+            };
+        } else {
+            interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
+        }
 
-        debug!(
-            "maybe_note_obligation_cause_for_async_await: interior_or_upvar={:?} \
-                generator_interior_types={:?}",
-            interior_or_upvar_span, typeck_results.generator_interior_types
-        );
         if let Some(interior_or_upvar_span) = interior_or_upvar_span {
             self.note_obligation_cause_for_async_await(
                 err,
@@ -1622,7 +1608,7 @@ fn note_obligation_cause_for_async_await(
         outer_generator: Option<DefId>,
         trait_ref: ty::TraitRef<'tcx>,
         target_ty: Ty<'tcx>,
-        typeck_results: &ty::TypeckResults<'tcx>,
+        typeck_results: Option<&ty::TypeckResults<'tcx>>,
         obligation: &PredicateObligation<'tcx>,
         next_code: Option<&ObligationCauseCode<'tcx>>,
     ) {
@@ -1833,7 +1819,7 @@ fn note_obligation_cause_for_async_await(
                         // Look at the last interior type to get a span for the `.await`.
                         debug!(
                             "note_obligation_cause_for_async_await generator_interior_types: {:#?}",
-                            typeck_results.generator_interior_types
+                            typeck_results.as_ref().map(|t| &t.generator_interior_types)
                         );
                         explain_yield(interior_span, yield_span, scope_span);
                     }
@@ -1854,10 +1840,14 @@ fn note_obligation_cause_for_async_await(
                             // ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
                             // ```
                             //
-                            let is_region_borrow = typeck_results
-                                .expr_adjustments(expr)
-                                .iter()
-                                .any(|adj| adj.is_region_borrow());
+                            let is_region_borrow = if let Some(typeck_results) = typeck_results {
+                                typeck_results
+                                    .expr_adjustments(expr)
+                                    .iter()
+                                    .any(|adj| adj.is_region_borrow())
+                            } else {
+                                false
+                            };
 
                             // ```rust
                             // struct Foo(*const u8);
@@ -1870,15 +1860,16 @@ fn note_obligation_cause_for_async_await(
                                     DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(),
                                     _ => false,
                                 };
-
-                            if (typeck_results.is_method_call(e) && is_region_borrow)
-                                || is_raw_borrow_inside_fn_like_call
-                            {
-                                err.span_help(
-                                    parent_span,
-                                    "consider moving this into a `let` \
+                            if let Some(typeck_results) = typeck_results {
+                                if (typeck_results.is_method_call(e) && is_region_borrow)
+                                    || is_raw_borrow_inside_fn_like_call
+                                {
+                                    err.span_help(
+                                        parent_span,
+                                        "consider moving this into a `let` \
                         binding to create a shorter lived borrow",
-                                );
+                                    );
+                                }
                             }
                         }
                     }
index b31d6d68b0a245b4a8d2215ef88a533bb99973a5..8f247184e880873d6f1d4a1419ee959c2753b16e 100644 (file)
@@ -748,6 +748,9 @@ fn vtable_trait_first_method_offset<'tcx>(
 ) -> usize {
     let (trait_to_be_found, trait_owning_vtable) = key;
 
+    // #90177
+    let trait_to_be_found_erased = tcx.erase_regions(trait_to_be_found);
+
     let vtable_segment_callback = {
         let mut vtable_base = 0;
 
@@ -757,7 +760,7 @@ fn vtable_trait_first_method_offset<'tcx>(
                     vtable_base += COMMON_VTABLE_ENTRIES.len();
                 }
                 VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
-                    if trait_ref == trait_to_be_found {
+                    if tcx.erase_regions(trait_ref) == trait_to_be_found_erased {
                         return ControlFlow::Break(vtable_base);
                     }
                     vtable_base += util::count_own_vtable_entries(tcx, trait_ref);
@@ -804,6 +807,7 @@ pub fn vtable_trait_upcasting_coercion_new_vptr_slot(
         ty::Binder::dummy(ty::TraitPredicate {
             trait_ref,
             constness: ty::BoundConstness::NotConst,
+            polarity: ty::ImplPolarity::Positive,
         }),
     );
 
index 0bb00dfeb43ad92fd54f6d035dd4d545403df7f7..afc546540d2e262d99c2818a6125805a07746eb6 100644 (file)
@@ -647,9 +647,7 @@ fn receiver_is_dispatchable<'tcx>(
     debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
 
     let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait());
-    let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits {
-        (u, cu)
-    } else {
+    let (Some(unsize_did), Some(dispatch_from_dyn_did)) = traits else {
         debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
         return false;
     };
@@ -839,14 +837,13 @@ fn visit_unevaluated_const(
             // constants which are not considered const evaluatable.
             use rustc_middle::thir::abstract_const::Node;
             if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) {
-                const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() {
-                    Node::Leaf(leaf) => {
-                        let leaf = leaf.subst(self.tcx, ct.substs);
-                        self.visit_const(leaf)
-                    }
-                    Node::Cast(_, _, ty) => self.visit_ty(ty),
-                    Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
-                        ControlFlow::CONTINUE
+                const_evaluatable::walk_abstract_const(self.tcx, ct, |node| {
+                    match node.root(self.tcx) {
+                        Node::Leaf(leaf) => self.visit_const(leaf),
+                        Node::Cast(_, _, ty) => self.visit_ty(ty),
+                        Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
+                            ControlFlow::CONTINUE
+                        }
                     }
                 })
             } else {
index 209fd83b3ab3467caf30665072f510088acf139d..85ca4db7d747d1fbd98bad87763259bf923189e2 100644 (file)
@@ -164,9 +164,7 @@ pub fn of_item(
     ) -> Result<Option<Self>, ErrorReported> {
         let attrs = tcx.get_attrs(impl_def_id);
 
-        let attr = if let Some(item) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) {
-            item
-        } else {
+        let Some(attr) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) else {
             return Ok(None);
         };
 
index db8a6d962049540f9e257c8e50b1e6a136697dfe..b8c66931cbe52ef093ce8cfb2629d29f72ec7268 100644 (file)
@@ -1734,7 +1734,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
         ty: ret_type,
     });
 
-    confirm_param_env_candidate(selcx, obligation, predicate, false)
+    confirm_param_env_candidate(selcx, obligation, predicate, true)
 }
 
 fn confirm_param_env_candidate<'cx, 'tcx>(
@@ -1754,8 +1754,18 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
     );
 
     let cache_projection = cache_entry.projection_ty;
-    let obligation_projection = obligation.predicate;
     let mut nested_obligations = Vec::new();
+    let obligation_projection = obligation.predicate;
+    let obligation_projection = ensure_sufficient_stack(|| {
+        normalize_with_depth_to(
+            selcx,
+            obligation.param_env,
+            obligation.cause.clone(),
+            obligation.recursion_depth + 1,
+            obligation_projection,
+            &mut nested_obligations,
+        )
+    });
     let cache_projection = if potentially_unnormalized_candidate {
         ensure_sufficient_stack(|| {
             normalize_with_depth_to(
@@ -1771,6 +1781,8 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
         cache_projection
     };
 
+    debug!(?cache_projection, ?obligation_projection);
+
     match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) {
         Ok(InferOk { value: _, obligations }) => {
             nested_obligations.extend(obligations);
index 7751dd84f4cac95d4b61f62d6706e67c7c23df16..e0098cc92d51569ac0509b08e34024fca73648b1 100644 (file)
@@ -44,6 +44,7 @@ pub(crate) fn update<'tcx, T>(
                             ty::PredicateKind::Trait(ty::TraitPredicate {
                                 trait_ref,
                                 constness: predicate.constness,
+                                polarity: predicate.polarity,
                             })
                         })
                         .to_predicate(infcx.tcx),
index 856ea43b1ff4e5508cedd2d1927967e39502b69e..1d0c54f86dea8bef96e9edb4f930df885799f9ad 100644 (file)
@@ -18,7 +18,7 @@
 use crate::traits::coherence::Conflict;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::{util, SelectionResult};
-use crate::traits::{ErrorReporting, Overflow, Unimplemented};
+use crate::traits::{Ambiguous, ErrorReporting, Overflow, Unimplemented};
 
 use super::BuiltinImplConditions;
 use super::IntercrateAmbiguityCause;
@@ -121,7 +121,7 @@ fn candidate_from_obligation_no_cache<'o>(
             return Ok(None);
         }
 
-        let mut candidates = candidate_set.vec;
+        let candidates = candidate_set.vec;
 
         debug!(?stack, ?candidates, "assembled {} candidates", candidates.len());
 
@@ -134,6 +134,8 @@ fn candidate_from_obligation_no_cache<'o>(
         // candidate which assumes $0 == int, one that assumes `$0 ==
         // usize`, etc. This spells an ambiguity.
 
+        let mut candidates = self.filter_impls(candidates, stack.obligation);
+
         // If there is more than one candidate, first winnow them down
         // by considering extra conditions (nested obligations and so
         // forth). We don't winnow if there is exactly one
@@ -149,7 +151,7 @@ fn candidate_from_obligation_no_cache<'o>(
         // Instead, we select the right impl now but report "`Bar` does
         // not implement `Clone`".
         if candidates.len() == 1 {
-            return self.filter_impls(candidates.pop().unwrap(), stack.obligation);
+            return self.filter_reservation_impls(candidates.pop().unwrap(), stack.obligation);
         }
 
         // Winnow, but record the exact outcome of evaluation, which
@@ -195,7 +197,15 @@ fn candidate_from_obligation_no_cache<'o>(
                     // and report ambiguity.
                     if i > 1 {
                         debug!("multiple matches, ambig");
-                        return Ok(None);
+                        return Err(Ambiguous(
+                            candidates
+                                .into_iter()
+                                .filter_map(|c| match c.candidate {
+                                    SelectionCandidate::ImplCandidate(def_id) => Some(def_id),
+                                    _ => None,
+                                })
+                                .collect(),
+                        ));
                     }
                 }
             }
@@ -223,7 +233,7 @@ fn candidate_from_obligation_no_cache<'o>(
         }
 
         // Just one candidate left.
-        self.filter_impls(candidates.pop().unwrap().candidate, stack.obligation)
+        self.filter_reservation_impls(candidates.pop().unwrap().candidate, stack.obligation)
     }
 
     #[instrument(skip(self, stack), level = "debug")]
@@ -254,68 +264,75 @@ pub(super) fn assemble_candidates<'o>(
 
         let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
 
-        self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
-
-        // Other bounds. Consider both in-scope bounds from fn decl
-        // and applicable impls. There is a certain set of precedence rules here.
-        let def_id = obligation.predicate.def_id();
-        let lang_items = self.tcx().lang_items();
-
-        if lang_items.copy_trait() == Some(def_id) {
-            debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
-
-            // User-defined copy impls are permitted, but only for
-            // structs and enums.
+        // The only way to prove a NotImplemented(T: Foo) predicate is via a negative impl.
+        // There are no compiler built-in rules for this.
+        if obligation.polarity() == ty::ImplPolarity::Negative {
+            self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
             self.assemble_candidates_from_impls(obligation, &mut candidates);
-
-            // For other types, we'll use the builtin rules.
-            let copy_conditions = self.copy_clone_conditions(obligation);
-            self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
-        } else if lang_items.discriminant_kind_trait() == Some(def_id) {
-            // `DiscriminantKind` is automatically implemented for every type.
-            candidates.vec.push(DiscriminantKindCandidate);
-        } else if lang_items.pointee_trait() == Some(def_id) {
-            // `Pointee` is automatically implemented for every type.
-            candidates.vec.push(PointeeCandidate);
-        } else if lang_items.sized_trait() == Some(def_id) {
-            // Sized is never implementable by end-users, it is
-            // always automatically computed.
-            let sized_conditions = self.sized_conditions(obligation);
-            self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
-        } else if lang_items.unsize_trait() == Some(def_id) {
-            self.assemble_candidates_for_unsizing(obligation, &mut candidates);
-        } else if lang_items.drop_trait() == Some(def_id)
-            && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
-        {
-            if self.is_in_const_context {
-                self.assemble_const_drop_candidates(obligation, &mut candidates)?;
-            } else {
-                debug!("passing ~const Drop bound; in non-const context");
-                // `~const Drop` when we are not in a const context has no effect.
-                candidates.vec.push(ConstDropCandidate)
-            }
         } else {
-            if lang_items.clone_trait() == Some(def_id) {
-                // Same builtin conditions as `Copy`, i.e., every type which has builtin support
-                // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
-                // types have builtin support for `Clone`.
-                let clone_conditions = self.copy_clone_conditions(obligation);
-                self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
-            }
+            self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
+
+            // Other bounds. Consider both in-scope bounds from fn decl
+            // and applicable impls. There is a certain set of precedence rules here.
+            let def_id = obligation.predicate.def_id();
+            let lang_items = self.tcx().lang_items();
+
+            if lang_items.copy_trait() == Some(def_id) {
+                debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
+
+                // User-defined copy impls are permitted, but only for
+                // structs and enums.
+                self.assemble_candidates_from_impls(obligation, &mut candidates);
+
+                // For other types, we'll use the builtin rules.
+                let copy_conditions = self.copy_clone_conditions(obligation);
+                self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
+            } else if lang_items.discriminant_kind_trait() == Some(def_id) {
+                // `DiscriminantKind` is automatically implemented for every type.
+                candidates.vec.push(DiscriminantKindCandidate);
+            } else if lang_items.pointee_trait() == Some(def_id) {
+                // `Pointee` is automatically implemented for every type.
+                candidates.vec.push(PointeeCandidate);
+            } else if lang_items.sized_trait() == Some(def_id) {
+                // Sized is never implementable by end-users, it is
+                // always automatically computed.
+                let sized_conditions = self.sized_conditions(obligation);
+                self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
+            } else if lang_items.unsize_trait() == Some(def_id) {
+                self.assemble_candidates_for_unsizing(obligation, &mut candidates);
+            } else if lang_items.drop_trait() == Some(def_id)
+                && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
+            {
+                if self.is_in_const_context {
+                    self.assemble_const_drop_candidates(obligation, &mut candidates)?;
+                } else {
+                    debug!("passing ~const Drop bound; in non-const context");
+                    // `~const Drop` when we are not in a const context has no effect.
+                    candidates.vec.push(ConstDropCandidate)
+                }
+            } else {
+                if lang_items.clone_trait() == Some(def_id) {
+                    // Same builtin conditions as `Copy`, i.e., every type which has builtin support
+                    // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
+                    // types have builtin support for `Clone`.
+                    let clone_conditions = self.copy_clone_conditions(obligation);
+                    self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
+                }
 
-            self.assemble_generator_candidates(obligation, &mut candidates);
-            self.assemble_closure_candidates(obligation, &mut candidates);
-            self.assemble_fn_pointer_candidates(obligation, &mut candidates);
-            self.assemble_candidates_from_impls(obligation, &mut candidates);
-            self.assemble_candidates_from_object_ty(obligation, &mut candidates);
-        }
+                self.assemble_generator_candidates(obligation, &mut candidates);
+                self.assemble_closure_candidates(obligation, &mut candidates);
+                self.assemble_fn_pointer_candidates(obligation, &mut candidates);
+                self.assemble_candidates_from_impls(obligation, &mut candidates);
+                self.assemble_candidates_from_object_ty(obligation, &mut candidates);
+            }
 
-        self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
-        self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
-        // Auto implementations have lower priority, so we only
-        // consider triggering a default if there is no other impl that can apply.
-        if candidates.vec.is_empty() {
-            self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
+            self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
+            self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
+            // Auto implementations have lower priority, so we only
+            // consider triggering a default if there is no other impl that can apply.
+            if candidates.vec.is_empty() {
+                self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
+            }
         }
         debug!("candidate list size: {}", candidates.vec.len());
         Ok(candidates)
@@ -376,7 +393,7 @@ fn assemble_candidates_from_caller_bounds<'o>(
         for bound in matching_bounds {
             let wc = self.evaluate_where_clause(stack, bound.value)?;
             if wc.may_apply() {
-                candidates.vec.push(ParamCandidate(bound));
+                candidates.vec.push(ParamCandidate((bound, stack.obligation.polarity())));
             }
         }
 
@@ -716,9 +733,7 @@ fn need_migrate_deref_output_trait_object(
             cause.clone(),
         );
 
-        let data = if let ty::Dynamic(ref data, ..) = normalized_ty.kind() {
-            data
-        } else {
+        let ty::Dynamic(data, ..) = normalized_ty.kind() else {
             return None;
         };
 
@@ -915,6 +930,7 @@ fn assemble_const_drop_candidates(
                         substs: self.tcx().mk_substs_trait(ty, &[]),
                     },
                     constness: ty::BoundConstness::NotConst,
+                    polarity: ty::ImplPolarity::Positive,
                 }));
             copy_obligation.recursion_depth = depth + 1;
             self.assemble_candidates_from_impls(&copy_obligation, &mut copy_candidates);
index a36cb1358b64c8afc4e5e3bf5ce3ccd0c2f1f2bf..2f1f7971a7926aa433352e92bfe306c48d26d8b0 100644 (file)
@@ -58,8 +58,8 @@ pub(super) fn confirm_candidate(
             }
 
             ParamCandidate(param) => {
-                let obligations = self.confirm_param_candidate(obligation, param.value);
-                Ok(ImplSource::Param(obligations, param.constness))
+                let obligations = self.confirm_param_candidate(obligation, param.0.value);
+                Ok(ImplSource::Param(obligations, param.0.constness))
             }
 
             ImplCandidate(impl_def_id) => {
@@ -620,23 +620,37 @@ fn confirm_closure_candidate(
             _ => bug!("closure candidate for non-closure {:?}", obligation),
         };
 
+        let obligation_predicate = obligation.predicate.to_poly_trait_ref();
+        let Normalized { value: obligation_predicate, mut obligations } =
+            ensure_sufficient_stack(|| {
+                normalize_with_depth(
+                    self,
+                    obligation.param_env,
+                    obligation.cause.clone(),
+                    obligation.recursion_depth + 1,
+                    obligation_predicate,
+                )
+            });
+
         let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs);
-        let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| {
-            normalize_with_depth(
-                self,
-                obligation.param_env,
-                obligation.cause.clone(),
-                obligation.recursion_depth + 1,
-                trait_ref,
-            )
-        });
+        let Normalized { value: trait_ref, obligations: trait_ref_obligations } =
+            ensure_sufficient_stack(|| {
+                normalize_with_depth(
+                    self,
+                    obligation.param_env,
+                    obligation.cause.clone(),
+                    obligation.recursion_depth + 1,
+                    trait_ref,
+                )
+            });
 
         debug!(?closure_def_id, ?trait_ref, ?obligations, "confirm closure candidate obligations");
 
+        obligations.extend(trait_ref_obligations);
         obligations.extend(self.confirm_poly_trait_refs(
             obligation.cause.clone(),
             obligation.param_env,
-            obligation.predicate.to_poly_trait_ref(),
+            obligation_predicate,
             trait_ref,
         )?);
 
@@ -948,52 +962,24 @@ fn confirm_builtin_unsize_candidate(
                 let tail_field_ty = tcx.type_of(tail_field.did);
 
                 let mut unsizing_params = GrowableBitSet::new_empty();
-                if tcx.features().relaxed_struct_unsize {
-                    for arg in tail_field_ty.walk(tcx) {
-                        if let Some(i) = maybe_unsizing_param_idx(arg) {
-                            unsizing_params.insert(i);
-                        }
-                    }
-
-                    // 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) {
-                            if let Some(i) = maybe_unsizing_param_idx(arg) {
-                                unsizing_params.remove(i);
-                            }
-                        }
+                for arg in tail_field_ty.walk(tcx) {
+                    if let Some(i) = maybe_unsizing_param_idx(arg) {
+                        unsizing_params.insert(i);
                     }
+                }
 
-                    if unsizing_params.is_empty() {
-                        return Err(Unimplemented);
-                    }
-                } else {
-                    let mut found = false;
-                    for arg in tail_field_ty.walk(tcx) {
+                // 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) {
                         if let Some(i) = maybe_unsizing_param_idx(arg) {
-                            unsizing_params.insert(i);
-                            found = true;
+                            unsizing_params.remove(i);
                         }
                     }
-                    if !found {
-                        return Err(Unimplemented);
-                    }
+                }
 
-                    // Ensure none of the other fields mention the parameters used
-                    // in unsizing.
-                    // FIXME(eddyb) cache this (including computing `unsizing_params`)
-                    // by putting it in a query; it would only need the `DefId` as it
-                    // looks at declared field types, not anything substituted.
-                    for field in prefix_fields {
-                        for arg in tcx.type_of(field.did).walk(tcx) {
-                            if let Some(i) = maybe_unsizing_param_idx(arg) {
-                                if unsizing_params.contains(i) {
-                                    return Err(Unimplemented);
-                                }
-                            }
-                        }
-                    }
+                if unsizing_params.is_empty() {
+                    return Err(Unimplemented);
                 }
 
                 // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`.
index 85502a399dedac0bbc74781160255accebbba09d..60676ad3f4f606b9cec87aec869d4083b539f098 100644 (file)
@@ -20,7 +20,7 @@
 use super::Selection;
 use super::SelectionResult;
 use super::TraitQueryMode;
-use super::{ErrorReporting, Overflow, SelectionError, Unimplemented};
+use super::{ErrorReporting, Overflow, SelectionError};
 use super::{ObligationCause, PredicateObligation, TraitObligation};
 
 use crate::infer::{InferCtxt, InferOk, TypeFreshener};
@@ -357,18 +357,16 @@ pub fn select(
         &mut self,
         obligation: &TraitObligation<'tcx>,
     ) -> SelectionResult<'tcx, Selection<'tcx>> {
-        debug_assert!(!obligation.predicate.has_escaping_bound_vars());
-
-        let pec = &ProvisionalEvaluationCache::default();
-        let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
-
-        let candidate = match self.candidate_from_obligation(&stack) {
+        let candidate = match self.select_from_obligation(obligation) {
             Err(SelectionError::Overflow) => {
                 // In standard mode, overflow must have been caught and reported
                 // earlier.
                 assert!(self.query_mode == TraitQueryMode::Canonical);
                 return Err(SelectionError::Overflow);
             }
+            Err(SelectionError::Ambiguous(_)) => {
+                return Ok(None);
+            }
             Err(e) => {
                 return Err(e);
             }
@@ -391,6 +389,18 @@ pub fn select(
         }
     }
 
+    crate fn select_from_obligation(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+    ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+        debug_assert!(!obligation.predicate.has_escaping_bound_vars());
+
+        let pec = &ProvisionalEvaluationCache::default();
+        let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
+
+        self.candidate_from_obligation(&stack)
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // EVALUATION
     //
@@ -709,7 +719,11 @@ fn evaluate_trait_predicate_recursively<'o>(
 
         debug!(?fresh_trait_ref);
 
-        if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) {
+        if let Some(result) = self.check_evaluation_cache(
+            obligation.param_env,
+            fresh_trait_ref,
+            obligation.polarity(),
+        ) {
             debug!(?result, "CACHE HIT");
             return Ok(result);
         }
@@ -739,12 +753,19 @@ fn evaluate_trait_predicate_recursively<'o>(
         let reached_depth = stack.reached_depth.get();
         if reached_depth >= stack.depth {
             debug!(?result, "CACHE MISS");
-            self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
+            self.insert_evaluation_cache(
+                obligation.param_env,
+                fresh_trait_ref,
+                obligation.polarity(),
+                dep_node,
+                result,
+            );
 
             stack.cache().on_completion(stack.dfn, |fresh_trait_ref, provisional_result| {
                 self.insert_evaluation_cache(
                     obligation.param_env,
                     fresh_trait_ref,
+                    obligation.polarity(),
                     dep_node,
                     provisional_result.max(result),
                 );
@@ -855,34 +876,39 @@ fn evaluate_stack<'o>(
         // precise still.
         let unbound_input_types =
             stack.fresh_trait_ref.value.skip_binder().substs.types().any(|ty| ty.is_fresh());
-        // This check was an imperfect workaround for a bug in the old
-        // intercrate mode; it should be removed when that goes away.
-        if unbound_input_types && self.intercrate {
-            debug!("evaluate_stack --> unbound argument, intercrate -->  ambiguous",);
-            // Heuristics: show the diagnostics when there are no candidates in crate.
-            if self.intercrate_ambiguity_causes.is_some() {
-                debug!("evaluate_stack: intercrate_ambiguity_causes is some");
-                if let Ok(candidate_set) = self.assemble_candidates(stack) {
-                    if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
-                        let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
-                        let self_ty = trait_ref.self_ty();
-                        let cause =
-                            with_no_trimmed_paths(|| IntercrateAmbiguityCause::DownstreamCrate {
-                                trait_desc: trait_ref.print_only_trait_path().to_string(),
-                                self_desc: if self_ty.has_concrete_skeleton() {
-                                    Some(self_ty.to_string())
-                                } else {
-                                    None
-                                },
+
+        if stack.obligation.polarity() != ty::ImplPolarity::Negative {
+            // This check was an imperfect workaround for a bug in the old
+            // intercrate mode; it should be removed when that goes away.
+            if unbound_input_types && self.intercrate {
+                debug!("evaluate_stack --> unbound argument, intercrate -->  ambiguous",);
+                // Heuristics: show the diagnostics when there are no candidates in crate.
+                if self.intercrate_ambiguity_causes.is_some() {
+                    debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+                    if let Ok(candidate_set) = self.assemble_candidates(stack) {
+                        if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
+                            let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+                            let self_ty = trait_ref.self_ty();
+                            let cause = with_no_trimmed_paths(|| {
+                                IntercrateAmbiguityCause::DownstreamCrate {
+                                    trait_desc: trait_ref.print_only_trait_path().to_string(),
+                                    self_desc: if self_ty.has_concrete_skeleton() {
+                                        Some(self_ty.to_string())
+                                    } else {
+                                        None
+                                    },
+                                }
                             });
 
-                        debug!(?cause, "evaluate_stack: pushing cause");
-                        self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+                            debug!(?cause, "evaluate_stack: pushing cause");
+                            self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+                        }
                     }
                 }
+                return Ok(EvaluatedToAmbig);
             }
-            return Ok(EvaluatedToAmbig);
         }
+
         if unbound_input_types
             && stack.iter().skip(1).any(|prev| {
                 stack.obligation.param_env == prev.obligation.param_env
@@ -899,6 +925,7 @@ fn evaluate_stack<'o>(
 
         match self.candidate_from_obligation(stack) {
             Ok(Some(c)) => self.evaluate_candidate(stack, &c),
+            Err(SelectionError::Ambiguous(_)) => Ok(EvaluatedToAmbig),
             Ok(None) => Ok(EvaluatedToAmbig),
             Err(Overflow) => Err(OverflowError::Canonical),
             Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
@@ -977,6 +1004,7 @@ fn check_evaluation_cache(
         &self,
         param_env: ty::ParamEnv<'tcx>,
         trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+        polarity: ty::ImplPolarity,
     ) -> Option<EvaluationResult> {
         // Neither the global nor local cache is aware of intercrate
         // mode, so don't do any caching. In particular, we might
@@ -988,17 +1016,19 @@ fn check_evaluation_cache(
 
         let tcx = self.tcx();
         if self.can_use_global_caches(param_env) {
-            if let Some(res) = tcx.evaluation_cache.get(&param_env.and(trait_ref), tcx) {
+            if let Some(res) = tcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
+            {
                 return Some(res);
             }
         }
-        self.infcx.evaluation_cache.get(&param_env.and(trait_ref), tcx)
+        self.infcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
     }
 
     fn insert_evaluation_cache(
         &mut self,
         param_env: ty::ParamEnv<'tcx>,
         trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+        polarity: ty::ImplPolarity,
         dep_node: DepNodeIndex,
         result: EvaluationResult,
     ) {
@@ -1023,13 +1053,17 @@ fn insert_evaluation_cache(
                 // FIXME: Due to #50507 this overwrites the different values
                 // This should be changed to use HashMapExt::insert_same
                 // when that is fixed
-                self.tcx().evaluation_cache.insert(param_env.and(trait_ref), dep_node, result);
+                self.tcx().evaluation_cache.insert(
+                    (param_env.and(trait_ref), polarity),
+                    dep_node,
+                    result,
+                );
                 return;
             }
         }
 
         debug!(?trait_ref, ?result, "insert_evaluation_cache");
-        self.infcx.evaluation_cache.insert(param_env.and(trait_ref), dep_node, result);
+        self.infcx.evaluation_cache.insert((param_env.and(trait_ref), polarity), dep_node, result);
     }
 
     /// For various reasons, it's possible for a subobligation
@@ -1094,67 +1128,89 @@ fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex)
         (result, dep_node)
     }
 
+    /// filter_impls filters constant trait obligations and candidates that have a positive impl
+    /// for a negative goal and a negative impl for a positive goal
     #[instrument(level = "debug", skip(self))]
     fn filter_impls(
         &mut self,
-        candidate: SelectionCandidate<'tcx>,
+        candidates: Vec<SelectionCandidate<'tcx>>,
         obligation: &TraitObligation<'tcx>,
-    ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+    ) -> Vec<SelectionCandidate<'tcx>> {
         let tcx = self.tcx();
-        // Respect const trait obligations
-        if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
-            match candidate {
-                // const impl
-                ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {}
-                // const param
-                ParamCandidate(ty::ConstnessAnd {
-                    constness: ty::BoundConstness::ConstIfConst,
-                    ..
-                }) => {}
-                // auto trait impl
-                AutoImplCandidate(..) => {}
-                // generator, this will raise error in other places
-                // or ignore error with const_async_blocks feature
-                GeneratorCandidate => {}
-                // FnDef where the function is const
-                FnPointerCandidate { is_const: true } => {}
-                ConstDropCandidate => {}
-                _ => {
-                    // reject all other types of candidates
-                    return Err(Unimplemented);
+        let mut result = Vec::with_capacity(candidates.len());
+
+        for candidate in candidates {
+            // Respect const trait obligations
+            if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
+                match candidate {
+                    // const impl
+                    ImplCandidate(def_id)
+                        if tcx.impl_constness(def_id) == hir::Constness::Const => {}
+                    // const param
+                    ParamCandidate((
+                        ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
+                        _,
+                    )) => {}
+                    // auto trait impl
+                    AutoImplCandidate(..) => {}
+                    // generator, this will raise error in other places
+                    // or ignore error with const_async_blocks feature
+                    GeneratorCandidate => {}
+                    // FnDef where the function is const
+                    FnPointerCandidate { is_const: true } => {}
+                    ConstDropCandidate => {}
+                    _ => {
+                        // reject all other types of candidates
+                        continue;
+                    }
                 }
             }
+
+            if let ImplCandidate(def_id) = candidate {
+                if ty::ImplPolarity::Reservation == tcx.impl_polarity(def_id)
+                    || obligation.polarity() == tcx.impl_polarity(def_id)
+                    || self.allow_negative_impls
+                {
+                    result.push(candidate);
+                }
+            } else {
+                result.push(candidate);
+            }
         }
-        // Treat negative impls as unimplemented, and reservation impls as ambiguity.
+
+        result
+    }
+
+    /// filter_reservation_impls filter reservation impl for any goal as ambiguous
+    #[instrument(level = "debug", skip(self))]
+    fn filter_reservation_impls(
+        &mut self,
+        candidate: SelectionCandidate<'tcx>,
+        obligation: &TraitObligation<'tcx>,
+    ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+        let tcx = self.tcx();
+        // Treat reservation impls as ambiguity.
         if let ImplCandidate(def_id) = candidate {
-            match tcx.impl_polarity(def_id) {
-                ty::ImplPolarity::Negative if !self.allow_negative_impls => {
-                    return Err(Unimplemented);
-                }
-                ty::ImplPolarity::Reservation => {
-                    if let Some(intercrate_ambiguity_clauses) =
-                        &mut self.intercrate_ambiguity_causes
-                    {
-                        let attrs = tcx.get_attrs(def_id);
-                        let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl);
-                        let value = attr.and_then(|a| a.value_str());
-                        if let Some(value) = value {
-                            debug!(
-                                "filter_impls: \
+            if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
+                if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
+                    let attrs = tcx.get_attrs(def_id);
+                    let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl);
+                    let value = attr.and_then(|a| a.value_str());
+                    if let Some(value) = value {
+                        debug!(
+                            "filter_reservation_impls: \
                                  reservation impl ambiguity on {:?}",
-                                def_id
-                            );
-                            intercrate_ambiguity_clauses.push(
-                                IntercrateAmbiguityCause::ReservationImpl {
-                                    message: value.to_string(),
-                                },
-                            );
-                        }
+                            def_id
+                        );
+                        intercrate_ambiguity_clauses.push(
+                            IntercrateAmbiguityCause::ReservationImpl {
+                                message: value.to_string(),
+                            },
+                        );
                     }
-                    return Ok(None);
                 }
-                _ => {}
-            };
+                return Ok(None);
+            }
         }
         Ok(Some(candidate))
     }
@@ -1162,7 +1218,7 @@ fn filter_impls(
     fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
         debug!("is_knowable(intercrate={:?})", self.intercrate);
 
-        if !self.intercrate {
+        if !self.intercrate || stack.obligation.polarity() == ty::ImplPolarity::Negative {
             return None;
         }
 
@@ -1219,14 +1275,14 @@ fn check_candidate_cache(
         if self.can_use_global_caches(param_env) {
             if let Some(res) = tcx
                 .selection_cache
-                .get(&param_env.and(trait_ref).with_constness(pred.constness), tcx)
+                .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
             {
                 return Some(res);
             }
         }
         self.infcx
             .selection_cache
-            .get(&param_env.and(trait_ref).with_constness(pred.constness), tcx)
+            .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
     }
 
     /// Determines whether can we safely cache the result
@@ -1286,7 +1342,7 @@ fn insert_candidate_cache(
                     debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
                     // This may overwrite the cache with the same value.
                     tcx.selection_cache.insert(
-                        param_env.and(trait_ref).with_constness(pred.constness),
+                        (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
                         dep_node,
                         candidate,
                     );
@@ -1297,7 +1353,7 @@ fn insert_candidate_cache(
 
         debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
         self.infcx.selection_cache.insert(
-            param_env.and(trait_ref).with_constness(pred.constness),
+            (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
             dep_node,
             candidate,
         );
@@ -1491,8 +1547,9 @@ fn candidate_should_be_dropped_in_favor_of(
         // Check if a bound would previously have been removed when normalizing
         // the param_env so that it can be given the lowest priority. See
         // #50825 for the motivation for this.
-        let is_global =
-            |cand: &ty::PolyTraitRef<'_>| cand.is_known_global() && !cand.has_late_bound_regions();
+        let is_global = |cand: &ty::PolyTraitRef<'tcx>| {
+            cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions()
+        };
 
         // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
         // and `DiscriminantKindCandidate` to anything else.
@@ -1523,10 +1580,14 @@ fn candidate_should_be_dropped_in_favor_of(
                 | ConstDropCandidate,
             ) => false,
 
-            (ParamCandidate(other), ParamCandidate(victim)) => {
+            (
+                ParamCandidate((other, other_polarity)),
+                ParamCandidate((victim, victim_polarity)),
+            ) => {
                 let same_except_bound_vars = other.value.skip_binder()
                     == victim.value.skip_binder()
                     && other.constness == victim.constness
+                    && other_polarity == victim_polarity
                     && !other.value.skip_binder().has_escaping_bound_vars();
                 if same_except_bound_vars {
                     // See issue #84398. In short, we can generate multiple ParamCandidates which are
@@ -1537,6 +1598,7 @@ fn candidate_should_be_dropped_in_favor_of(
                     other.value.bound_vars().len() <= victim.value.bound_vars().len()
                 } else if other.value == victim.value
                     && victim.constness == ty::BoundConstness::NotConst
+                    && other_polarity == victim_polarity
                 {
                     // Drop otherwise equivalent non-const candidates in favor of const candidates.
                     true
@@ -1566,11 +1628,11 @@ fn candidate_should_be_dropped_in_favor_of(
                 | TraitAliasCandidate(..)
                 | ObjectCandidate(_)
                 | ProjectionCandidate(_),
-            ) => !is_global(&cand.value),
+            ) => !is_global(&cand.0.value),
             (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
                 // Prefer these to a global where-clause bound
                 // (see issue #50825).
-                is_global(&cand.value)
+                is_global(&cand.0.value)
             }
             (
                 ImplCandidate(_)
@@ -1586,7 +1648,7 @@ fn candidate_should_be_dropped_in_favor_of(
             ) => {
                 // Prefer these to a global where-clause bound
                 // (see issue #50825).
-                is_global(&cand.value) && other.evaluation.must_apply_modulo_regions()
+                is_global(&cand.0.value) && other.evaluation.must_apply_modulo_regions()
             }
 
             (ProjectionCandidate(i), ProjectionCandidate(j))
index 88aca794a6be6971ea4d7bfcb2b1bfb431fe5393..f9867f0671e59fbd7478629fcd114f4dfea652de 100644 (file)
@@ -464,7 +464,7 @@ fn report_conflicting_impls(
 
 /// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
 /// string.
-fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
+crate fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
     use std::fmt::Write;
 
     let trait_ref = tcx.impl_trait_ref(impl_def_id)?;
index ac8bab0cf36a77913ab3c5a5cd57de7e6ac9b478..a398e847b935458a003fab06e30ed423802e255c 100644 (file)
@@ -17,6 +17,7 @@ pub enum NonStructuralMatchTy<'tcx> {
     Dynamic,
     Foreign,
     Opaque,
+    Closure,
     Generator,
     Projection,
 }
@@ -154,6 +155,9 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             ty::Projection(..) => {
                 return ControlFlow::Break(NonStructuralMatchTy::Projection);
             }
+            ty::Closure(..) => {
+                return ControlFlow::Break(NonStructuralMatchTy::Closure);
+            }
             ty::Generator(..) | ty::GeneratorWitness(..) => {
                 return ControlFlow::Break(NonStructuralMatchTy::Generator);
             }
@@ -197,7 +201,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 // First check all contained types and then tell the caller to continue searching.
                 return ty.super_visit_with(self);
             }
-            ty::Closure(..) | ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
+            ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
                 bug!("unexpected type during structural-match checking: {:?}", ty);
             }
             ty::Error(_) => {
index 98415a84c569bc0191dadf2bf06e08f7788a5dae..3f66e5b4ebfbeb80c2894201bd3d153e2c58f974 100644 (file)
 type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>;
 
 fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
-    let adt_components =
-        move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
-
     // If we don't know a type doesn't need drop, for example if it's a type
     // parameter without a `Copy` bound, then we conservatively return that it
     // needs drop.
-    let res =
-        NeedsDropTypes::new(tcx, query.param_env, query.value, adt_components).next().is_some();
+    let adt_has_dtor =
+        |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
+    let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor).next().is_some();
 
     debug!("needs_drop_raw({:?}) = {:?}", query, res);
     res
@@ -29,12 +27,10 @@ fn has_significant_drop_raw<'tcx>(
     tcx: TyCtxt<'tcx>,
     query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
 ) -> bool {
-    let significant_drop_fields = move |adt_def: &ty::AdtDef, _| {
-        tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter())
-    };
-    let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields)
-        .next()
-        .is_some();
+    let res =
+        drop_tys_helper(tcx, query.value, query.param_env, adt_consider_insignificant_dtor(tcx))
+            .next()
+            .is_some();
     debug!("has_significant_drop_raw({:?}) = {:?}", query, res);
     res
 }
@@ -145,10 +141,8 @@ fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
                             Ok(tys) => tys,
                         };
                         for required_ty in tys {
-                            let subst_ty = tcx.normalize_erasing_regions(
-                                self.param_env,
-                                required_ty.subst(tcx, substs),
-                            );
+                            let subst_ty =
+                                tcx.normalize_erasing_regions(self.param_env, required_ty);
                             queue_type(self, subst_ty);
                         }
                     }
@@ -187,23 +181,24 @@ enum DtorType {
 // Depending on the implentation of `adt_has_dtor`, it is used to check if the
 // ADT has a destructor or if the ADT only has a significant destructor. For
 // understanding significant destructor look at `adt_significant_drop_tys`.
-fn adt_drop_tys_helper<'tcx>(
+fn drop_tys_helper<'tcx>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
+    ty: Ty<'tcx>,
+    param_env: rustc_middle::ty::ParamEnv<'tcx>,
     adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
-) -> Result<&ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
+) -> impl Iterator<Item = NeedsDropResult<Ty<'tcx>>> {
     let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| {
         if adt_def.is_manually_drop() {
-            debug!("adt_drop_tys: `{:?}` is manually drop", adt_def);
+            debug!("drop_tys_helper: `{:?}` is manually drop", adt_def);
             return Ok(Vec::new().into_iter());
         } else if let Some(dtor_info) = adt_has_dtor(adt_def) {
             match dtor_info {
                 DtorType::Significant => {
-                    debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
+                    debug!("drop_tys_helper: `{:?}` implements `Drop`", adt_def);
                     return Err(AlwaysRequiresDrop);
                 }
                 DtorType::Insignificant => {
-                    debug!("adt_drop_tys: `{:?}` drop is insignificant", adt_def);
+                    debug!("drop_tys_helper: `{:?}` drop is insignificant", adt_def);
 
                     // Since the destructor is insignificant, we just want to make sure all of
                     // the passed in type parameters are also insignificant.
@@ -212,34 +207,27 @@ fn adt_drop_tys_helper<'tcx>(
                 }
             }
         } else if adt_def.is_union() {
-            debug!("adt_drop_tys: `{:?}` is a union", adt_def);
+            debug!("drop_tys_helper: `{:?}` is a union", adt_def);
             return Ok(Vec::new().into_iter());
         }
-        Ok(adt_def.all_fields().map(|field| tcx.type_of(field.did)).collect::<Vec<_>>().into_iter())
+        Ok(adt_def
+            .all_fields()
+            .map(|field| {
+                let r = tcx.type_of(field.did).subst(tcx, substs);
+                debug!("drop_tys_helper: Subst into {:?} with {:?} gettng {:?}", field, substs, r);
+                r
+            })
+            .collect::<Vec<_>>()
+            .into_iter())
     };
 
-    let adt_ty = tcx.type_of(def_id);
-    let param_env = tcx.param_env(def_id);
-    let res: Result<Vec<_>, _> =
-        NeedsDropTypes::new(tcx, param_env, adt_ty, adt_components).collect();
-
-    debug!("adt_drop_tys(`{}`) = `{:?}`", tcx.def_path_str(def_id), res);
-    res.map(|components| tcx.intern_type_list(&components))
+    NeedsDropTypes::new(tcx, param_env, ty, adt_components)
 }
 
-fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
-    // This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are
-    // significant.
-    let adt_has_dtor =
-        |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
-    adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
-}
-
-fn adt_significant_drop_tys(
-    tcx: TyCtxt<'_>,
-    def_id: DefId,
-) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
-    let adt_has_dtor = |adt_def: &ty::AdtDef| {
+fn adt_consider_insignificant_dtor<'tcx>(
+    tcx: TyCtxt<'tcx>,
+) -> impl Fn(&ty::AdtDef) -> Option<DtorType> + 'tcx {
+    move |adt_def: &ty::AdtDef| {
         let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor);
         if is_marked_insig {
             // In some cases like `std::collections::HashMap` where the struct is a wrapper around
@@ -256,8 +244,31 @@ fn adt_significant_drop_tys(
             // treat this as the simple case of Drop impl for type.
             None
         }
-    };
-    adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
+    }
+}
+
+fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
+    // This is for the "adt_drop_tys" query, that considers all `Drop` impls, therefore all dtors are
+    // significant.
+    let adt_has_dtor =
+        |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
+    drop_tys_helper(tcx, tcx.type_of(def_id), tcx.param_env(def_id), adt_has_dtor)
+        .collect::<Result<Vec<_>, _>>()
+        .map(|components| tcx.intern_type_list(&components))
+}
+
+fn adt_significant_drop_tys(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
+    drop_tys_helper(
+        tcx,
+        tcx.type_of(def_id),
+        tcx.param_env(def_id),
+        adt_consider_insignificant_dtor(tcx),
+    )
+    .collect::<Result<Vec<_>, _>>()
+    .map(|components| tcx.intern_type_list(&components))
 }
 
 pub(crate) fn provide(providers: &mut ty::query::Providers) {
index 3d3b2743700917090e208f651426d5b3d5d3e79a..af3706f886e9cbce53fb4e6be54c5ee1872432e4 100644 (file)
@@ -1,7 +1,6 @@
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::hir::map as hir_map;
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{
     self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
@@ -248,6 +247,7 @@ fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
 }
 
 /// See `ParamEnv` struct definition for details.
+#[instrument(level = "debug", skip(tcx))]
 fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     // The param_env of an impl Trait type is its defining function's param_env
     if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
@@ -275,9 +275,20 @@ 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 unnormalized_env =
         ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing);
 
+    debug!("unnormalized_env caller bounds: {:?}", unnormalized_env.caller_bounds());
     let body_id = def_id
         .as_local()
         .map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
@@ -478,11 +489,11 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
 
     let node = tcx.hir().get(hir_id);
 
-    let fn_like = hir_map::blocks::FnLikeNode::from_node(node).unwrap_or_else(|| {
+    let fn_kind = node.fn_kind().unwrap_or_else(|| {
         bug!("asyncness: expected fn-like node but got `{:?}`", def_id);
     });
 
-    fn_like.asyncness()
+    fn_kind.asyncness()
 }
 
 /// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead.
index 5befe44802f54a1341e140109ffb92625fffd426..84327a2880e18c6499eb4eaa82c41beaae735124 100644 (file)
@@ -344,7 +344,7 @@ pub fn create_substs_for_generic_args<'a>(
                                             "reorder the arguments: {}: `<{}>`",
                                             param_types_present
                                                 .into_iter()
-                                                .map(|ord| format!("{}s", ord.to_string()))
+                                                .map(|ord| format!("{}s", ord))
                                                 .collect::<Vec<String>>()
                                                 .join(", then "),
                                             ordered_params
index 889b68773c27b1eaeba74e462ea02d7fc4cc2bd9..da751f2075399cef877e49ae73c661a34c2a03a6 100644 (file)
@@ -1916,9 +1916,7 @@ fn qpath_to_ty(
 
         debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id);
 
-        let self_ty = if let Some(ty) = opt_self_ty {
-            ty
-        } else {
+        let Some(self_ty) = opt_self_ty else {
             let path_str = tcx.def_path_str(trait_def_id);
 
             let def_id = self.item_def_id();
index ff04e07acc4f6bd90faf56ad02e7ef0b7ac81c68..24474e163b9daf23586c3d24e2efb063f652c596 100644 (file)
@@ -64,16 +64,16 @@ pub fn predicates(
             })
         });
 
-        self.region_bounds
-            .iter()
-            .map(|&(region_bound, span)| {
+        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 predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
                 (predicate, span)
@@ -83,7 +83,6 @@ pub fn predicates(
                     .iter()
                     .map(|&(projection, span)| (projection.to_predicate(tcx), span)),
             )
-            .chain(sized_predicate.into_iter())
             .collect()
     }
 }
index 6a231e719e66462a9751bd69392442e3648a124a..a8160313228b6381b02f6e1633fce45ae07e639b 100644 (file)
@@ -6,7 +6,6 @@
 use rustc_infer::traits::Obligation;
 use rustc_middle::ty::{self, ToPredicate, Ty, TyS};
 use rustc_span::{MultiSpan, Span};
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
@@ -531,6 +530,7 @@ pub(crate) fn opt_suggest_box_span(
                                         substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
                                     },
                                     constness: t.constness,
+                                    polarity: t.polarity,
                                 }));
                             let obl = Obligation::new(
                                 o.cause.clone(),
index 06c42098791ef1ad47872572c12014fc690e4bef..5d22e300774d3b624d31a6029ddf99751280705c 100644 (file)
@@ -300,7 +300,7 @@ fn identify_bad_closure_def_and_call(
             let end = callee_span.shrink_to_hi();
             err.multipart_suggestion(
                 "if you meant to create this closure and immediately call it, surround the \
-                closure with parenthesis",
+                closure with parentheses",
                 vec![(start, "(".to_string()), (end, ")".to_string())],
                 Applicability::MaybeIncorrect,
             );
@@ -383,7 +383,7 @@ fn confirm_builtin_call(
                         call_expr.span,
                         &format!(
                             "`{}` is a unit variant, you need to write it \
-                                 without the parenthesis",
+                                 without the parentheses",
                             path
                         ),
                         path.to_string(),
index 66316214e5e6644d58cfcae46557e4c6a0e432d0..5040c4db95163a48473aace18608b6d7a7d55623 100644 (file)
@@ -21,7 +21,6 @@
 use rustc_span::symbol::sym;
 use rustc_span::{self, MultiSpan, Span};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_ty_utils::representability::{self, Representability};
index a87318ff34e6dc0a20d1e8718e6d262350a15c94..ad65a0ba62a8cc8b0372214abbc2da99f575a96c 100644 (file)
@@ -185,9 +185,10 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
                 debug!("coerce: unsize not object safe");
                 return Err(TypeError::ObjectUnsafeCoercion(did));
             }
-            Err(_) => {}
+            Err(error) => {
+                debug!(?error, "coerce: unsize failed");
+            }
         }
-        debug!("coerce: unsize failed");
 
         // Examine the supertype and consider auto-borrowing.
         match *b.kind() {
@@ -521,9 +522,7 @@ fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceRe
 
         let traits =
             (self.tcx.lang_items().unsize_trait(), self.tcx.lang_items().coerce_unsized_trait());
-        let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits {
-            (u, cu)
-        } else {
+        let (Some(unsize_did), Some(coerce_unsized_did)) = traits else {
             debug!("missing Unsize or CoerceUnsized traits");
             return Err(TypeError::Mismatch);
         };
index 540365956a8fb793ef5bc39380463c2f9eaf25c6..2b3672211e4f582e951922e2ff2c555c4b36866f 100644 (file)
@@ -743,9 +743,7 @@ pub fn check_for_cast(
             return false;
         }
 
-        let src = if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
-            src
-        } else {
+        let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) else {
             return false;
         };
 
index ac4bb652244864e3e1b873f289afdf08766f54fa..5308126f2524b2468078d0c6e1db96efebd86506 100644 (file)
@@ -35,7 +35,6 @@
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{self, BytePos, MultiSpan, Span};
 use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
     self, ObligationCause, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt,
index 551522334aa00a7d9d328bdeb7a361c0f0e36854..b3e18dab363692e303e13e4977355579d1967c68 100644 (file)
@@ -370,6 +370,8 @@ pub(in super::super) fn check_argument_types(
                 //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
                 let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
 
+                final_arg_types.push((i, checked_ty, coerce_ty));
+
                 // Cause selection errors caused by resolving a single argument to point at the
                 // argument and not the call. This is otherwise redundant with the `demand_coerce`
                 // call immediately after, but it lets us customize the span pointed to in the
@@ -377,38 +379,20 @@ pub(in super::super) fn check_argument_types(
                 let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment(
                     coerce_ty,
                     |errors| {
-                        // This is not coming from a macro or a `derive`.
-                        if sp.desugaring_kind().is_none()
-                        && !arg.span.from_expansion()
-                        // Do not change the spans of `async fn`s.
-                        && !matches!(
-                            expr.kind,
-                            hir::ExprKind::Call(
-                                hir::Expr {
-                                    kind: hir::ExprKind::Path(hir::QPath::LangItem(_, _)),
-                                    ..
-                                },
-                                _
-                            )
-                        ) {
-                            for error in errors {
-                                error.obligation.cause.make_mut().span = arg.span;
-                                let code = error.obligation.cause.code.clone();
-                                error.obligation.cause.make_mut().code =
-                                    ObligationCauseCode::FunctionArgumentObligation {
-                                        arg_hir_id: arg.hir_id,
-                                        call_hir_id: expr.hir_id,
-                                        parent_code: Lrc::new(code),
-                                    };
-                            }
-                        }
+                        self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
+                        self.point_at_arg_instead_of_call_if_possible(
+                            errors,
+                            &final_arg_types,
+                            expr,
+                            sp,
+                            args,
+                        );
                     },
                 );
 
                 // We're processing function arguments so we definitely want to use
                 // two-phase borrows.
                 self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
-                final_arg_types.push((i, checked_ty, coerce_ty));
 
                 // 3. Relate the expected type and the formal one,
                 //    if the expected type was used for the coercion.
@@ -973,45 +957,79 @@ fn point_at_arg_instead_of_call_if_possible(
                 continue;
             }
 
-            if let ty::PredicateKind::Trait(predicate) =
-                error.obligation.predicate.kind().skip_binder()
-            {
-                // Collect the argument position for all arguments that could have caused this
-                // `FulfillmentError`.
-                let mut referenced_in = final_arg_types
-                    .iter()
-                    .map(|&(i, checked_ty, _)| (i, checked_ty))
-                    .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
-                    .flat_map(|(i, ty)| {
-                        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 == predicate.self_ty().into()) {
-                            Some(i)
-                        } else {
-                            None
-                        }
-                    })
-                    .collect::<Vec<usize>>();
-
-                // Both checked and coerced types could have matched, thus we need to remove
-                // duplicates.
-
-                // We sort primitive type usize here and can use unstable sort
-                referenced_in.sort_unstable();
-                referenced_in.dedup();
-
-                if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
-                    // We make sure that only *one* argument matches the obligation failure
-                    // and we assign the obligation's span to its expression's.
-                    error.obligation.cause.make_mut().span = args[ref_in].span;
-                    let code = error.obligation.cause.code.clone();
-                    error.obligation.cause.make_mut().code =
-                        ObligationCauseCode::FunctionArgumentObligation {
-                            arg_hir_id: args[ref_in].hir_id,
-                            call_hir_id: expr.hir_id,
-                            parent_code: Lrc::new(code),
-                        };
+            // Peel derived obligation, because it's the type that originally
+            // started this inference chain that matters, not the one we wound
+            // up with at the end.
+            fn unpeel_to_top(
+                mut code: Lrc<ObligationCauseCode<'_>>,
+            ) -> Lrc<ObligationCauseCode<'_>> {
+                let mut result_code = code.clone();
+                loop {
+                    let parent = match &*code {
+                        ObligationCauseCode::BuiltinDerivedObligation(c)
+                        | ObligationCauseCode::ImplDerivedObligation(c)
+                        | ObligationCauseCode::DerivedObligation(c) => c.parent_code.clone(),
+                        _ => break,
+                    };
+                    result_code = std::mem::replace(&mut code, parent);
+                }
+                result_code
+            }
+            let self_: ty::subst::GenericArg<'_> = match &*unpeel_to_top(Lrc::new(error.obligation.cause.code.clone())) {
+                ObligationCauseCode::BuiltinDerivedObligation(code) |
+                ObligationCauseCode::ImplDerivedObligation(code) |
+                ObligationCauseCode::DerivedObligation(code) => {
+                    code.parent_trait_ref.self_ty().skip_binder().into()
+                }
+                _ if let ty::PredicateKind::Trait(predicate) =
+                    error.obligation.predicate.kind().skip_binder() => {
+                        predicate.self_ty().into()
+                    }
+                _ =>  continue,
+            };
+            let self_ = self.resolve_vars_if_possible(self_);
+
+            // Collect the argument position for all arguments that could have caused this
+            // `FulfillmentError`.
+            let mut referenced_in = final_arg_types
+                .iter()
+                .map(|&(i, checked_ty, _)| (i, checked_ty))
+                .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
+                .flat_map(|(i, ty)| {
+                    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 }
+                })
+                .collect::<Vec<usize>>();
+
+            // Both checked and coerced types could have matched, thus we need to remove
+            // duplicates.
+
+            // We sort primitive type usize here and can use unstable sort
+            referenced_in.sort_unstable();
+            referenced_in.dedup();
+
+            if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
+                // Do not point at the inside of a macro.
+                // That would often result in poor error messages.
+                if args[ref_in].span.from_expansion() {
+                    return;
+                }
+                // We make sure that only *one* argument matches the obligation failure
+                // and we assign the obligation's span to its expression's.
+                error.obligation.cause.make_mut().span = args[ref_in].span;
+                let code = error.obligation.cause.code.clone();
+                error.obligation.cause.make_mut().code =
+                    ObligationCauseCode::FunctionArgumentObligation {
+                        arg_hir_id: args[ref_in].hir_id,
+                        call_hir_id: expr.hir_id,
+                        parent_code: Lrc::new(code),
+                    };
+            } else if error.obligation.cause.make_mut().span == call_sp {
+                // Make function calls point at the callee, not the whole thing.
+                if let hir::ExprKind::Call(callee, _) = expr.kind {
+                    error.obligation.cause.make_mut().span = callee.span;
                 }
             }
         }
index babc06822ac529baa6b4a3b8b59d2afe1e94b2cc..dcc635a1f00b19ecbbd63e19b1a9f19807719d5a 100644 (file)
@@ -420,7 +420,7 @@ pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
                             ..
                         },
                         method,
-                    )) if Some(recv_ty.def_id()) == pin_did && method.ident.name == sym::new => {
+                    )) if recv_ty.opt_def_id() == pin_did && method.ident.name == sym::new => {
                         err.span_suggestion(
                             fn_name.span,
                             "use `Box::pin` to pin and box this expression",
index 183ebc559ae42ba0cd1a978349246c882fca57e9..8007b9f23776a169f141afa3d63ca7f61617839a 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_span::lev_distance;
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{source_map, FileName, MultiSpan, Span};
+use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{FulfillmentError, Obligation};
 
@@ -1203,6 +1203,13 @@ fn suggest_valid_traits(
             let mut candidates = valid_out_of_scope_traits;
             candidates.sort();
             candidates.dedup();
+
+            // `TryFrom` and `FromIterator` have no methods
+            let edition_fix = candidates
+                .iter()
+                .find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
+                .map(|&d| d);
+
             err.help("items from traits can only be used if the trait is in scope");
             let msg = format!(
                 "the following {traits_are} implemented but not in scope; \
@@ -1212,6 +1219,13 @@ fn suggest_valid_traits(
             );
 
             self.suggest_use_candidates(err, msg, candidates);
+            if let Some(did) = edition_fix {
+                err.note(&format!(
+                    "'{}' is included in the prelude starting in Edition 2021",
+                    with_crate_prefix(|| self.tcx.def_path_str(did))
+                ));
+            }
+
             true
         } else {
             false
@@ -1237,6 +1251,7 @@ fn suggest_traits_to_import(
                 self.tcx.lang_items().deref_trait(),
                 self.tcx.lang_items().deref_mut_trait(),
                 self.tcx.lang_items().drop_trait(),
+                self.tcx.get_diagnostic_item(sym::AsRef),
             ];
             // Try alternative arbitrary self types that could fulfill this call.
             // FIXME: probe for all types that *could* be arbitrary self-types, not
@@ -1286,7 +1301,11 @@ fn suggest_traits_to_import(
                             // We don't want to suggest a container type when the missing
                             // method is `.clone()` or `.deref()` otherwise we'd suggest
                             // `Arc::new(foo).clone()`, which is far from what the user wants.
-                            let skip = skippable.contains(&did);
+                            // 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));
                             // 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`
index 79e004a47db53484d7d76ba2f212f58c591a4b6c..aea1bcd95df21a63504981b9e25075a54882d89f 100644 (file)
@@ -492,7 +492,7 @@ fn add_type_neq_err_label(
         other_ty: Ty<'tcx>,
         op: hir::BinOp,
         is_assign: IsAssign,
-    ) -> bool /* did we suggest to call a function because of missing parenthesis? */ {
+    ) -> bool /* did we suggest to call a function because of missing parentheses? */ {
         err.span_label(span, ty.to_string());
         if let FnDef(def_id, _) = *ty.kind() {
             let source_map = self.tcx.sess.source_map();
@@ -502,9 +502,7 @@ fn add_type_neq_err_label(
             // FIXME: Instead of exiting early when encountering bound vars in
             // the function signature, consider keeping the binder here and
             // propagating it downwards.
-            let fn_sig = if let Some(fn_sig) = self.tcx.fn_sig(def_id).no_bound_vars() {
-                fn_sig
-            } else {
+            let Some(fn_sig) = self.tcx.fn_sig(def_id).no_bound_vars() else {
                 return false;
             };
 
index 635219146d0f5ee344670b467e1f76a97ecc7f79..5aa11cce25fb6d5247d38f9757f3bea37c5d6487 100644 (file)
@@ -718,10 +718,7 @@ fn check_pat_struct(
         ti: TopInfo<'tcx>,
     ) -> Ty<'tcx> {
         // Resolve the path and check the definition for errors.
-        let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.hir_id)
-        {
-            variant_ty
-        } else {
+        let Some((variant, pat_ty)) = self.check_struct_path(qpath, pat.hir_id) else {
             let err = self.tcx.ty_error();
             for field in fields {
                 let ti = TopInfo { parent_pat: Some(pat), ..ti };
index 849bf1e455cbf3153ac2a9f5085b57c52de45c3a..5d9e6ebd50c85582c32eee27843c66753503d55b 100644 (file)
@@ -411,9 +411,7 @@ fn convert_place_op_to_mutable(
         debug!("convert_place_op_to_mutable: method={:?}", method);
         self.write_method_call(expr.hir_id, method);
 
-        let region = if let ty::Ref(r, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind() {
-            r
-        } else {
+        let ty::Ref(region, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind() else {
             span_bug!(expr.span, "input to mutable place op is not a mut ref?");
         };
 
index 4ed149e1fe792782f8e2bc23b589dc08dcfcdcdb..86d4e4d2b115b5857959bd115066bc850a5a8543 100644 (file)
@@ -88,7 +88,6 @@
 use rustc_middle::ty::adjustment;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
 use std::ops::Deref;
 
 // a variation on try that just returns unit
@@ -340,8 +339,6 @@ fn visit_fn_body(
         self.link_fn_params(body.params);
         self.visit_body(body);
         self.visit_region_obligations(body_id.hir_id);
-
-        self.constrain_opaque_types(self.outlives_environment.free_region_map());
     }
 
     fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
index 3a10988bba0b9db381587f40fcd0bd39cb33f91d..774d8078e52ca31171213b8070848902040aae07 100644 (file)
@@ -86,18 +86,55 @@ pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) {
 /// Intermediate format to store the hir_id pointing to the use that resulted in the
 /// corresponding place being captured and a String which contains the captured value's
 /// name (i.e: a.b.c)
-type CapturesInfo = (Option<hir::HirId>, String);
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+enum UpvarMigrationInfo {
+    /// We previously captured all of `x`, but now we capture some sub-path.
+    CapturingPrecise { source_expr: Option<hir::HirId>, var_name: String },
+    CapturingNothing {
+        // where the variable appears in the closure (but is not captured)
+        use_span: Span,
+    },
+}
+
+/// Reasons that we might issue a migration warning.
+#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+struct MigrationWarningReason {
+    /// When we used to capture `x` in its entirety, we implemented the auto-trait(s)
+    /// in this vec, but now we don't.
+    auto_traits: Vec<&'static str>,
+
+    /// When we used to capture `x` in its entirety, we would execute some destructors
+    /// at a different time.
+    drop_order: bool,
+}
+
+impl MigrationWarningReason {
+    fn migration_message(&self) -> String {
+        let base = "changes to closure capture in Rust 2021 will affect";
+        if !self.auto_traits.is_empty() && self.drop_order {
+            format!("{} drop order and which traits the closure implements", base)
+        } else if self.drop_order {
+            format!("{} drop order", base)
+        } else {
+            format!("{} which traits the closure implements", base)
+        }
+    }
+}
+
+/// Intermediate format to store information needed to generate a note in the migration lint.
+struct MigrationLintNote {
+    captures_info: UpvarMigrationInfo,
 
-/// Intermediate format to store information needed to generate migration lint. The tuple
-/// contains the hir_id pointing to the use that resulted in the
-/// corresponding place being captured, a String which contains the captured value's
-/// name (i.e: a.b.c) and a String which contains the reason why migration is needed for that
-/// capture
-type MigrationNeededForCapture = (Option<hir::HirId>, String, String);
+    /// reasons why migration is needed for this capture
+    reason: MigrationWarningReason,
+}
 
 /// Intermediate format to store the hir id of the root variable and a HashSet containing
 /// information on why the root variable should be fully captured
-type MigrationDiagnosticInfo = (hir::HirId, Vec<MigrationNeededForCapture>);
+struct NeededMigration {
+    var_hir_id: hir::HirId,
+    diagnostics_info: Vec<MigrationLintNote>,
+}
 
 struct InferBorrowKindVisitor<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
@@ -707,47 +744,66 @@ fn perform_2229_migration_anaysis(
                  closure_head_span,
                 |lint| {
                     let mut diagnostics_builder = lint.build(
-                        format!(
-                            "changes to closure capture in Rust 2021 will affect {}",
-                            reasons
-                        )
-                        .as_str(),
+                        &reasons.migration_message(),
                     );
-                    for (var_hir_id, diagnostics_info) in need_migrations.iter() {
+                    for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations {
                         // Labels all the usage of the captured variable and why they are responsible
                         // for migration being needed
-                        for (captured_hir_id, captured_name, reasons) in diagnostics_info.iter() {
-                            if let Some(captured_hir_id) = captured_hir_id {
-                                let cause_span = self.tcx.hir().span(*captured_hir_id);
-                                diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
-                                    self.tcx.hir().name(*var_hir_id),
-                                    captured_name,
-                                ));
+                        for lint_note in diagnostics_info.iter() {
+                            match &lint_note.captures_info {
+                                UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => {
+                                    let cause_span = self.tcx.hir().span(*capture_expr_id);
+                                    diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
+                                        self.tcx.hir().name(*var_hir_id),
+                                        captured_name,
+                                    ));
+                                }
+                                UpvarMigrationInfo::CapturingNothing { use_span } => {
+                                    diagnostics_builder.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
+                                        self.tcx.hir().name(*var_hir_id),
+                                    ));
+                                }
+
+                                _ => { }
                             }
 
                             // Add a label pointing to where a captured variable affected by drop order
                             // is dropped
-                            if reasons.contains("drop order") {
+                            if lint_note.reason.drop_order {
                                 let drop_location_span = drop_location_span(self.tcx, &closure_hir_id);
 
-                                diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
-                                    self.tcx.hir().name(*var_hir_id),
-                                    captured_name,
-                                ));
+                                match &lint_note.captures_info {
+                                    UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
+                                        diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
+                                            self.tcx.hir().name(*var_hir_id),
+                                            captured_name,
+                                        ));
+                                    }
+                                    UpvarMigrationInfo::CapturingNothing { use_span: _ } => {
+                                        diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
+                                            v = self.tcx.hir().name(*var_hir_id),
+                                        ));
+                                    }
+                                }
                             }
 
                             // Add a label explaining why a closure no longer implements a trait
-                            if reasons.contains("trait implementation") {
-                                let missing_trait = &reasons[..reasons.find("trait implementation").unwrap() - 1];
-
-                                diagnostics_builder.span_label(closure_head_span, format!("in Rust 2018, this closure implements {} as `{}` implements {}, but in Rust 2021, this closure will no longer implement {} as `{}` does not implement {}",
-                                    missing_trait,
-                                    self.tcx.hir().name(*var_hir_id),
-                                    missing_trait,
-                                    missing_trait,
-                                    captured_name,
-                                    missing_trait,
-                                ));
+                            for &missing_trait in &lint_note.reason.auto_traits {
+                                // not capturing something anymore cannot cause a trait to fail to be implemented:
+                                match &lint_note.captures_info {
+                                    UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
+                                        let var_name = self.tcx.hir().name(*var_hir_id);
+                                        diagnostics_builder.span_label(closure_head_span, format!("\
+                                        in Rust 2018, this closure implements {missing_trait} \
+                                        as `{var_name}` implements {missing_trait}, but in Rust 2021, \
+                                        this closure will no longer implement {missing_trait} \
+                                        because `{var_name}` is not fully captured \
+                                        and `{captured_name}` does not implement {missing_trait}"));
+                                    }
+
+                                    // Cannot happen: if we don't capture a variable, we impl strictly more traits
+                                    UpvarMigrationInfo::CapturingNothing { use_span } => span_bug!(*use_span, "missing trait from not capturing something"),
+                                }
                             }
                         }
                     }
@@ -840,25 +896,16 @@ fn perform_2229_migration_anaysis(
     /// Combines all the reasons for 2229 migrations
     fn compute_2229_migrations_reasons(
         &self,
-        auto_trait_reasons: FxHashSet<&str>,
-        drop_reason: bool,
-    ) -> String {
-        let mut reasons = String::new();
-
-        if !auto_trait_reasons.is_empty() {
-            reasons = format!(
-                "{} trait implementation for closure",
-                auto_trait_reasons.clone().into_iter().collect::<Vec<&str>>().join(", ")
-            );
-        }
+        auto_trait_reasons: FxHashSet<&'static str>,
+        drop_order: bool,
+    ) -> MigrationWarningReason {
+        let mut reasons = MigrationWarningReason::default();
 
-        if !auto_trait_reasons.is_empty() && drop_reason {
-            reasons = format!("{} and ", reasons);
+        for auto_trait in auto_trait_reasons {
+            reasons.auto_traits.push(auto_trait);
         }
 
-        if drop_reason {
-            reasons = format!("{}drop order", reasons);
-        }
+        reasons.drop_order = drop_order;
 
         reasons
     }
@@ -874,7 +921,7 @@ fn compute_2229_migrations_for_trait(
         min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
         var_hir_id: hir::HirId,
         closure_clause: hir::CaptureBy,
-    ) -> Option<FxHashMap<CapturesInfo, FxHashSet<&str>>> {
+    ) -> Option<FxHashMap<UpvarMigrationInfo, FxHashSet<&'static str>>> {
         let auto_traits_def_id = vec![
             self.tcx.lang_items().clone_trait(),
             self.tcx.lang_items().sync_trait(),
@@ -883,8 +930,8 @@ fn compute_2229_migrations_for_trait(
             self.tcx.get_diagnostic_item(sym::unwind_safe_trait),
             self.tcx.get_diagnostic_item(sym::ref_unwind_safe_trait),
         ];
-        let auto_traits =
-            vec!["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"];
+        const AUTO_TRAITS: [&str; 6] =
+            ["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"];
 
         let root_var_min_capture_list = min_captures.and_then(|m| m.get(&var_hir_id))?;
 
@@ -957,13 +1004,16 @@ fn compute_2229_migrations_for_trait(
             // by the root variable but not by the capture
             for (idx, _) in obligations_should_hold.iter().enumerate() {
                 if !obligations_holds_for_capture[idx] && obligations_should_hold[idx] {
-                    capture_problems.insert(auto_traits[idx]);
+                    capture_problems.insert(AUTO_TRAITS[idx]);
                 }
             }
 
             if !capture_problems.is_empty() {
                 problematic_captures.insert(
-                    (capture.info.path_expr_id, capture.to_string(self.tcx)),
+                    UpvarMigrationInfo::CapturingPrecise {
+                        source_expr: capture.info.path_expr_id,
+                        var_name: capture.to_string(self.tcx),
+                    },
                     capture_problems,
                 );
             }
@@ -986,6 +1036,7 @@ fn compute_2229_migrations_for_trait(
     ///
     /// This function only returns a HashSet of CapturesInfo for significant drops. If there
     /// are no significant drops than None is returned
+    #[instrument(level = "debug", skip(self))]
     fn compute_2229_migrations_for_drop(
         &self,
         closure_def_id: DefId,
@@ -993,29 +1044,41 @@ fn compute_2229_migrations_for_drop(
         min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
         closure_clause: hir::CaptureBy,
         var_hir_id: hir::HirId,
-    ) -> Option<FxHashSet<CapturesInfo>> {
+    ) -> Option<FxHashSet<UpvarMigrationInfo>> {
         let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id));
 
         if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) {
+            debug!("does not have significant drop");
             return None;
         }
 
-        let root_var_min_capture_list = if let Some(root_var_min_capture_list) =
-            min_captures.and_then(|m| m.get(&var_hir_id))
-        {
-            root_var_min_capture_list
-        } else {
+        let Some(root_var_min_capture_list) = min_captures.and_then(|m| m.get(&var_hir_id)) else {
             // The upvar is mentioned within the closure but no path starting from it is
-            // used.
+            // used. This occurs when you have (e.g.)
+            //
+            // ```
+            // let x = move || {
+            //     let _ = y;
+            // });
+            // ```
+            debug!("no path starting from it is used");
+
 
             match closure_clause {
                 // Only migrate if closure is a move closure
-                hir::CaptureBy::Value => return Some(FxHashSet::default()),
+                hir::CaptureBy::Value => {
+                    let mut diagnostics_info = FxHashSet::default();
+                    let upvars = self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar");
+                    let upvar = upvars[&var_hir_id];
+                    diagnostics_info.insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span });
+                    return Some(diagnostics_info);
+                }
                 hir::CaptureBy::Ref => {}
             }
 
             return None;
         };
+        debug!(?root_var_min_capture_list);
 
         let mut projections_list = Vec::new();
         let mut diagnostics_info = FxHashSet::default();
@@ -1025,19 +1088,24 @@ fn compute_2229_migrations_for_drop(
                 // Only care about captures that are moved into the closure
                 ty::UpvarCapture::ByValue(..) => {
                     projections_list.push(captured_place.place.projections.as_slice());
-                    diagnostics_info.insert((
-                        captured_place.info.path_expr_id,
-                        captured_place.to_string(self.tcx),
-                    ));
+                    diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise {
+                        source_expr: captured_place.info.path_expr_id,
+                        var_name: captured_place.to_string(self.tcx),
+                    });
                 }
                 ty::UpvarCapture::ByRef(..) => {}
             }
         }
 
+        debug!(?projections_list);
+        debug!(?diagnostics_info);
+
         let is_moved = !projections_list.is_empty();
+        debug!(?is_moved);
 
         let is_not_completely_captured =
             root_var_min_capture_list.iter().any(|capture| !capture.place.projections.is_empty());
+        debug!(?is_not_completely_captured);
 
         if is_moved
             && is_not_completely_captured
@@ -1070,17 +1138,16 @@ fn compute_2229_migrations_for_drop(
     /// Returns a tuple containing a vector of MigrationDiagnosticInfo, as well as a String
     /// containing the reason why root variables whose HirId is contained in the vector should
     /// be captured
+    #[instrument(level = "debug", skip(self))]
     fn compute_2229_migrations(
         &self,
         closure_def_id: DefId,
         closure_span: Span,
         closure_clause: hir::CaptureBy,
         min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
-    ) -> (Vec<MigrationDiagnosticInfo>, String) {
-        let upvars = if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
-            upvars
-        } else {
-            return (Vec::new(), format!(""));
+    ) -> (Vec<NeededMigration>, MigrationWarningReason) {
+        let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) else {
+            return (Vec::new(), MigrationWarningReason::default());
         };
 
         let mut need_migrations = Vec::new();
@@ -1089,7 +1156,7 @@ fn compute_2229_migrations(
 
         // Perform auto-trait analysis
         for (&var_hir_id, _) in upvars.iter() {
-            let mut responsible_captured_hir_ids = Vec::new();
+            let mut diagnostics_info = Vec::new();
 
             let auto_trait_diagnostic = if let Some(diagnostics_info) =
                 self.compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause)
@@ -1121,34 +1188,33 @@ fn compute_2229_migrations(
 
             let mut capture_diagnostic = capture_diagnostic.into_iter().collect::<Vec<_>>();
             capture_diagnostic.sort();
-            for captured_info in capture_diagnostic.iter() {
+            for captures_info in capture_diagnostic {
                 // Get the auto trait reasons of why migration is needed because of that capture, if there are any
                 let capture_trait_reasons =
-                    if let Some(reasons) = auto_trait_diagnostic.get(captured_info) {
+                    if let Some(reasons) = auto_trait_diagnostic.get(&captures_info) {
                         reasons.clone()
                     } else {
                         FxHashSet::default()
                     };
 
                 // Check if migration is needed because of drop reorder as a result of that capture
-                let capture_drop_reorder_reason = drop_reorder_diagnostic.contains(captured_info);
+                let capture_drop_reorder_reason = drop_reorder_diagnostic.contains(&captures_info);
 
                 // Combine all the reasons of why the root variable should be captured as a result of
                 // auto trait implementation issues
                 auto_trait_migration_reasons.extend(capture_trait_reasons.clone());
 
-                responsible_captured_hir_ids.push((
-                    captured_info.0,
-                    captured_info.1.clone(),
-                    self.compute_2229_migrations_reasons(
+                diagnostics_info.push(MigrationLintNote {
+                    captures_info,
+                    reason: self.compute_2229_migrations_reasons(
                         capture_trait_reasons,
                         capture_drop_reorder_reason,
                     ),
-                ));
+                });
             }
 
-            if !capture_diagnostic.is_empty() {
-                need_migrations.push((var_hir_id, responsible_captured_hir_ids));
+            if !diagnostics_info.is_empty() {
+                need_migrations.push(NeededMigration { var_hir_id, diagnostics_info });
             }
         }
         (
@@ -1684,9 +1750,7 @@ fn adjust_upvar_borrow_kind_for_consume(
         diag_expr_id: hir::HirId,
     ) {
         let tcx = self.fcx.tcx;
-        let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
-            upvar_id
-        } else {
+        let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else {
             return;
         };
 
@@ -2095,6 +2159,7 @@ fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol {
     tcx.hir().name(var_hir_id)
 }
 
+#[instrument(level = "debug", skip(tcx))]
 fn should_do_rust_2021_incompatible_closure_captures_analysis(
     tcx: TyCtxt<'_>,
     closure_id: hir::HirId,
@@ -2110,10 +2175,12 @@ fn should_do_rust_2021_incompatible_closure_captures_analysis(
 /// - s2: Comma separated names of the variables being migrated.
 fn migration_suggestion_for_2229(
     tcx: TyCtxt<'_>,
-    need_migrations: &Vec<MigrationDiagnosticInfo>,
+    need_migrations: &Vec<NeededMigration>,
 ) -> (String, String) {
-    let need_migrations_variables =
-        need_migrations.iter().map(|(v, _)| var_name(tcx, *v)).collect::<Vec<_>>();
+    let need_migrations_variables = need_migrations
+        .iter()
+        .map(|NeededMigration { var_hir_id: v, .. }| var_name(tcx, *v))
+        .collect::<Vec<_>>();
 
     let migration_ref_concat =
         need_migrations_variables.iter().map(|v| format!("&{}", v)).collect::<Vec<_>>().join(", ");
index df7f2aea9c3ac08ec51b1dc406ff1065d8a091ea..18e8ed394e81409615a9de263fd05626cb46cac5 100644 (file)
@@ -2879,6 +2879,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 for item in list.iter() {
                     if item.has_name(sym::address) {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
+                    } else if item.has_name(sym::cfi) {
+                        codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
                     } else if item.has_name(sym::memory) {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
                     } else if item.has_name(sym::thread) {
index cee3679d0a052207e79ba3f14e72c81dd190771a..a6ea8abdf3fa6af554918f4a4aeceb51101a1d9d 100644 (file)
@@ -292,7 +292,8 @@ pub(super) fn default_anon_const_substs(tcx: TyCtxt<'_>, def_id: DefId) -> Subst
     // 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::STILL_FURTHER_SPECIALIZABLE
+            | ty::TypeFlags::HAS_ERROR;
         assert!(!arg.has_type_flags(!allowed_flags));
     }
     substs
@@ -771,7 +772,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                 } else {
                     err.span_note(
                         tcx.hir().body(body_id).value.span,
-                        &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
+                        &format!("however, the inferred type `{}` cannot be named", ty),
                     );
                 }
             }
@@ -795,7 +796,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                 } else {
                     diag.span_note(
                         tcx.hir().body(body_id).value.span,
-                        &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
+                        &format!("however, the inferred type `{}` cannot be named", ty),
                     );
                 }
             }
index f4bb5761c19bdbb944a4e88602786178ce9c49a5..4fb422c801b1def85f9c2ae9609eed393584704b 100644 (file)
@@ -382,6 +382,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
         ty::PredicateKind::Trait(ty::TraitPredicate {
             trait_ref,
             constness: ty::BoundConstness::NotConst,
+            polarity: _,
         }) => {
             if !matches!(
                 trait_predicate_kind(tcx, predicate),
@@ -413,6 +414,7 @@ fn trait_predicate_kind<'tcx>(
         ty::PredicateKind::Trait(ty::TraitPredicate {
             trait_ref,
             constness: ty::BoundConstness::NotConst,
+            polarity: _,
         }) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
         ty::PredicateKind::Trait(_)
         | ty::PredicateKind::RegionOutlives(_)
index 50afdc23631b9d4874d24ffb1fb5e043f53c18f4..f90cfb8849160055ab7fce45bd5f7ddfd4867123 100644 (file)
@@ -63,6 +63,7 @@
 #![feature(in_band_lifetimes)]
 #![feature(is_sorted)]
 #![feature(iter_zip)]
+#![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(nll)]
 #![feature(try_blocks)]
index 1c8ac10818c0319940bb4b8eb0716acda272895e..33c27ce86ddb5f8357f2a42a763b9559afbb3932 100644 (file)
@@ -223,8 +223,8 @@ fn add_constraints_from_invariant_substs(
                     self.add_constraints_from_region(current, lt, variance_i)
                 }
                 GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i),
-                GenericArgKind::Const(_) => {
-                    // Consts impose no constraints.
+                GenericArgKind::Const(val) => {
+                    self.add_constraints_from_const(current, val, variance_i)
                 }
             }
         }
@@ -263,7 +263,8 @@ fn add_constraints_from_ty(
                 self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
             }
 
-            ty::Array(typ, _) => {
+            ty::Array(typ, len) => {
+                self.add_constraints_from_const(current, len, variance);
                 self.add_constraints_from_ty(current, typ, variance);
             }
 
@@ -385,13 +386,32 @@ fn add_constraints_from_substs(
                     self.add_constraints_from_region(current, lt, variance_i)
                 }
                 GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i),
-                GenericArgKind::Const(_) => {
-                    // Consts impose no constraints.
+                GenericArgKind::Const(val) => {
+                    self.add_constraints_from_const(current, val, variance)
                 }
             }
         }
     }
 
+    /// Adds constraints appropriate for a const expression `val`
+    /// in a context with ambient variance `variance`
+    fn add_constraints_from_const(
+        &mut self,
+        current: &CurrentItem,
+        val: &ty::Const<'tcx>,
+        variance: VarianceTermPtr<'a>,
+    ) {
+        debug!("add_constraints_from_const(val={:?}, variance={:?})", val, variance);
+
+        match &val.val {
+            ty::ConstKind::Unevaluated(uv) => {
+                let substs = uv.substs(self.tcx());
+                self.add_constraints_from_invariant_substs(current, substs, variance);
+            }
+            _ => {}
+        }
+    }
+
     /// Adds constraints appropriate for a function with signature
     /// `sig` appearing in a context with ambient variance `variance`
     fn add_constraints_from_sig(
index 61e57eee782b8f3d68ad7891b06f4a3a0efb536c..4dd953a495d675a0499149dbfc3537a881dfb9d8 100644 (file)
@@ -68,6 +68,12 @@ changelog-seen = 2
 # Indicates whether the LLVM assertions are enabled or not
 #assertions = false
 
+# Indicates whether the LLVM testsuite is enabled in the build or not. Does
+# not execute the tests as part of the build as part of x.py build et al,
+# just makes it possible to do `ninja check-llvm` in the staged LLVM build
+# directory when doing LLVM development as part of Rust development.
+#tests = false
+
 # Indicates whether the LLVM plugin is enabled or not
 #plugins = false
 
@@ -603,7 +609,11 @@ changelog-seen = 2
 
 # Enable symbol-mangling-version v0. This can be helpful when profiling rustc,
 # as generics will be preserved in symbols (rather than erased into opaque T).
-#new-symbol-mangling = false
+# When no setting is given, the new scheme will be used when compiling the
+# compiler and its tools and the legacy scheme will be used when compiling the
+# standard library.
+# If an explicit setting is given, it will be used for all parts of the codebase.
+#new-symbol-mangling = true|false (see comment)
 
 # =============================================================================
 # Options for specific targets
index c304f74884721a60d976eef7abe200e00999f68e..89c21929dbcda121f7e1183515775682a492e472 100644 (file)
@@ -290,7 +290,7 @@ fn bench_range<F, R>(b: &mut Bencher, f: F)
         let mut c = 0;
         for i in 0..BENCH_RANGE_SIZE {
             for j in i + 1..BENCH_RANGE_SIZE {
-                black_box(map.range(f(i, j)));
+                let _ = black_box(map.range(f(i, j)));
                 c += 1;
             }
         }
@@ -322,7 +322,7 @@ fn bench_iter(b: &mut Bencher, repeats: i32, size: i32) {
     let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect();
     b.iter(|| {
         for _ in 0..repeats {
-            black_box(map.iter());
+            let _ = black_box(map.iter());
         }
     });
 }
index 4a5b0fcf03709ff944fe4e612327bbeaee3cb70e..66ef92558d8b563c4d149fe5966c54ad60a657ad 100644 (file)
@@ -81,6 +81,7 @@
 /// }
 /// ```
 #[stable(feature = "global_alloc", since = "1.28.0")]
+#[must_use = "losing the pointer will leak memory"]
 #[inline]
 pub unsafe fn alloc(layout: Layout) -> *mut u8 {
     unsafe { __rust_alloc(layout.size(), layout.align()) }
@@ -117,6 +118,7 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
 ///
 /// See [`GlobalAlloc::realloc`].
 #[stable(feature = "global_alloc", since = "1.28.0")]
+#[must_use = "losing the pointer will leak memory"]
 #[inline]
 pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
     unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) }
@@ -150,6 +152,7 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8
 /// }
 /// ```
 #[stable(feature = "global_alloc", since = "1.28.0")]
+#[must_use = "losing the pointer will leak memory"]
 #[inline]
 pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
     unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) }
index 9bded6c0f1cf213f5212c6a426f5614da9598277..7fb7686a6e29790a5320cddb774adcf73e92d91a 100644 (file)
 /// item's ordering relative to any other item, as determined by the [`Ord`]
 /// trait, changes while it is in the heap. This is normally only possible
 /// through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. The
-/// behavior resulting from such a logic error is not specified, but will
-/// not result in undefined behavior. This could include panics, incorrect
-/// results, aborts, memory leaks, and non-termination.
+/// behavior resulting from such a logic error is not specified (it
+/// could include panics, incorrect results, aborts, memory leaks, or
+/// non-termination) but will not be undefined behavior.
 ///
 /// # Examples
 ///
@@ -512,6 +512,7 @@ pub fn push(&mut self, item: T) {
     /// let vec = heap.into_sorted_vec();
     /// assert_eq!(vec, [1, 2, 3, 4, 5, 6, 7]);
     /// ```
+    #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
     pub fn into_sorted_vec(mut self) -> Vec<T> {
         let mut end = self.len();
@@ -850,7 +851,6 @@ pub fn iter(&self) -> Iter<'_, T> {
     ///
     /// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), vec![5, 4]);
     /// ```
-    #[must_use = "`self` will be dropped if the result is not used"]
     #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
     pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
         IntoIterSorted { inner: self }
@@ -877,6 +877,7 @@ pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
     /// # Time complexity
     ///
     /// Cost is *O*(1) in the worst case.
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn peek(&self) -> Option<&T> {
         self.data.get(0)
@@ -894,6 +895,7 @@ pub fn peek(&self) -> Option<&T> {
     /// assert!(heap.capacity() >= 100);
     /// heap.push(4);
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn capacity(&self) -> usize {
         self.data.capacity()
@@ -1050,6 +1052,7 @@ pub fn into_vec(self) -> Vec<T> {
     ///
     /// assert_eq!(heap.len(), 2);
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn len(&self) -> usize {
         self.data.len()
@@ -1073,6 +1076,7 @@ pub fn len(&self) -> usize {
     ///
     /// assert!(!heap.is_empty());
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_empty(&self) -> bool {
         self.len() == 0
@@ -1203,6 +1207,7 @@ fn drop(&mut self) {
 /// documentation for more.
 ///
 /// [`iter`]: BinaryHeap::iter
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, T: 'a> {
     iter: slice::Iter<'a, T>,
@@ -1337,6 +1342,7 @@ fn as_into_iter(&mut self) -> &mut vec::IntoIter<Self::Item> {
     }
 }
 
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
 #[derive(Clone, Debug)]
 pub struct IntoIterSorted<T> {
index fa86e611565e64b0b7ab0a5cb7099bd385c3fa5c..2ff7b0fbb759c0c64cbb46210b749bc142afc94f 100644 (file)
 /// performance on *small* nodes of elements which are cheap to compare. However in the future we
 /// would like to further explore choosing the optimal search strategy based on the choice of B,
 /// and possibly other factors. Using linear search, searching for a random element is expected
-/// to take O(B * log(n)) comparisons, which is generally worse than a BST. In practice,
+/// to take B * log(n) comparisons, which is generally worse than a BST. In practice,
 /// however, performance is excellent.
 ///
 /// It is a logic error for a key to be modified in such a way that the key's ordering relative to
 /// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is
 /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
-/// The behavior resulting from such a logic error is not specified, but will not result in
-/// undefined behavior. This could include panics, incorrect results, aborts, memory leaks, and
-/// non-termination.
+/// The behavior resulting from such a logic error is not specified (it could include panics,
+/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
+/// behavior.
 ///
 /// [B-Tree]: https://en.wikipedia.org/wiki/B-tree
 /// [`Cell`]: core::cell::Cell
@@ -288,6 +288,7 @@ fn replace(&mut self, key: K) -> Option<K> {
 /// documentation for more.
 ///
 /// [`iter`]: BTreeMap::iter
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, K: 'a, V: 'a> {
     range: LazyLeafRange<marker::Immut<'a>, K, V>,
@@ -316,6 +317,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> {
     _marker: PhantomData<&'a mut (K, V)>,
 }
 
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "collection_debug", since = "1.17.0")]
 impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IterMut<'_, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -359,6 +361,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// documentation for more.
 ///
 /// [`keys`]: BTreeMap::keys
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Keys<'a, K: 'a, V: 'a> {
     inner: Iter<'a, K, V>,
@@ -377,6 +380,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// documentation for more.
 ///
 /// [`values`]: BTreeMap::values
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Values<'a, K: 'a, V: 'a> {
     inner: Iter<'a, K, V>,
@@ -395,6 +399,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// documentation for more.
 ///
 /// [`values_mut`]: BTreeMap::values_mut
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "map_values_mut", since = "1.10.0")]
 pub struct ValuesMut<'a, K: 'a, V: 'a> {
     inner: IterMut<'a, K, V>,
@@ -413,6 +418,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// See its documentation for more.
 ///
 /// [`into_keys`]: BTreeMap::into_keys
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "map_into_keys_values", since = "1.54.0")]
 pub struct IntoKeys<K, V> {
     inner: IntoIter<K, V>,
@@ -431,6 +437,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// See its documentation for more.
 ///
 /// [`into_values`]: BTreeMap::into_values
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "map_into_keys_values", since = "1.54.0")]
 pub struct IntoValues<K, V> {
     inner: IntoIter<K, V>,
@@ -449,6 +456,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// documentation for more.
 ///
 /// [`range`]: BTreeMap::range
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "btree_range", since = "1.17.0")]
 pub struct Range<'a, K: 'a, V: 'a> {
     inner: LeafRange<marker::Immut<'a>, K, V>,
@@ -467,6 +475,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// documentation for more.
 ///
 /// [`range_mut`]: BTreeMap::range_mut
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "btree_range", since = "1.17.0")]
 pub struct RangeMut<'a, K: 'a, V: 'a> {
     inner: LeafRange<marker::ValMut<'a>, K, V>,
@@ -1265,7 +1274,6 @@ pub(super) fn drain_filter_inner(&mut self) -> DrainFilterInner<'_, K, V>
     /// assert_eq!(keys, [1, 2]);
     /// ```
     #[inline]
-    #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "map_into_keys_values", since = "1.54.0")]
     pub fn into_keys(self) -> IntoKeys<K, V> {
         IntoKeys { inner: self.into_iter() }
@@ -1288,7 +1296,6 @@ pub fn into_keys(self) -> IntoKeys<K, V> {
     /// assert_eq!(values, ["hello", "goodbye"]);
     /// ```
     #[inline]
-    #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "map_into_keys_values", since = "1.54.0")]
     pub fn into_values(self) -> IntoValues<K, V> {
         IntoValues { inner: self.into_iter() }
@@ -2205,6 +2212,7 @@ pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
     /// a.insert(1, "a");
     /// assert_eq!(a.len(), 1);
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
     pub const fn len(&self) -> usize {
@@ -2225,6 +2233,7 @@ pub const fn len(&self) -> usize {
     /// a.insert(1, "a");
     /// assert!(!a.is_empty());
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
     pub const fn is_empty(&self) -> bool {
index 3e9048b17688fb78f7d589c0dac2ba352a773415..5cef007a46f0d1ea9d725fd87c3b8f703288426c 100644 (file)
@@ -347,6 +347,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
     /// map.entry("poneyland").or_insert(12);
     /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
     /// ```
+    #[must_use]
     #[stable(feature = "map_entry_keys", since = "1.10.0")]
     pub fn key(&self) -> &K {
         self.handle.reborrow().into_kv().0
@@ -391,6 +392,7 @@ pub fn remove_entry(self) -> (K, V) {
     ///     assert_eq!(o.get(), &12);
     /// }
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get(&self) -> &V {
         self.handle.reborrow().into_kv().1
index 173960341f859b5acab3b8b8f094de9c6b1ee36e..17389657afb92564e0371865ff1f5a43f707446a 100644 (file)
@@ -744,35 +744,35 @@ fn test_range_equal_empty_cases() {
 #[should_panic]
 fn test_range_equal_excluded() {
     let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
-    map.range((Excluded(2), Excluded(2)));
+    let _ = map.range((Excluded(2), Excluded(2)));
 }
 
 #[test]
 #[should_panic]
 fn test_range_backwards_1() {
     let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
-    map.range((Included(3), Included(2)));
+    let _ = map.range((Included(3), Included(2)));
 }
 
 #[test]
 #[should_panic]
 fn test_range_backwards_2() {
     let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
-    map.range((Included(3), Excluded(2)));
+    let _ = map.range((Included(3), Excluded(2)));
 }
 
 #[test]
 #[should_panic]
 fn test_range_backwards_3() {
     let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
-    map.range((Excluded(3), Included(2)));
+    let _ = map.range((Excluded(3), Included(2)));
 }
 
 #[test]
 #[should_panic]
 fn test_range_backwards_4() {
     let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
-    map.range((Excluded(3), Excluded(2)));
+    let _ = map.range((Excluded(3), Excluded(2)));
 }
 
 #[test]
@@ -783,7 +783,7 @@ fn test_range_finding_ill_order_in_map() {
     // we cause a different panic than `test_range_backwards_1` does.
     // A more refined `should_panic` would be welcome.
     if Cyclic3::C < Cyclic3::A {
-        map.range(Cyclic3::C..=Cyclic3::A);
+        let _ = map.range(Cyclic3::C..=Cyclic3::A);
     }
 }
 
@@ -824,7 +824,7 @@ fn borrow(&self) -> &EvilTwin {
     }
 
     let map = (0..12).map(|i| (CompositeKey(i, EvilTwin(i)), ())).collect::<BTreeMap<_, _>>();
-    map.range(EvilTwin(5)..=EvilTwin(7));
+    let _ = map.range(EvilTwin(5)..=EvilTwin(7));
 }
 
 #[test]
@@ -1239,32 +1239,32 @@ fn test_borrow() {
 
     #[allow(dead_code)]
     fn get<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: &T) {
-        v.get(t);
+        let _ = v.get(t);
     }
 
     #[allow(dead_code)]
     fn get_mut<T: Ord>(v: &mut BTreeMap<Box<T>, ()>, t: &T) {
-        v.get_mut(t);
+        let _ = v.get_mut(t);
     }
 
     #[allow(dead_code)]
     fn get_key_value<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: &T) {
-        v.get_key_value(t);
+        let _ = v.get_key_value(t);
     }
 
     #[allow(dead_code)]
     fn contains_key<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: &T) {
-        v.contains_key(t);
+        let _ = v.contains_key(t);
     }
 
     #[allow(dead_code)]
     fn range<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: T) {
-        v.range(t..);
+        let _ = v.range(t..);
     }
 
     #[allow(dead_code)]
     fn range_mut<T: Ord>(v: &mut BTreeMap<Box<T>, ()>, t: T) {
-        v.range_mut(t..);
+        let _ = v.range_mut(t..);
     }
 
     #[allow(dead_code)]
index d732f65b0d05f152174ab10f005a2acc6b7c5b35..0322cabccde4b0f830acaf9f423de435cc36f9db 100644 (file)
@@ -23,9 +23,9 @@
 /// It is a logic error for an item to be modified in such a way that the item's ordering relative
 /// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is
 /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
-/// The behavior resulting from such a logic error is not specified, but will not result in
-/// undefined behavior. This could include panics, incorrect results, aborts, memory leaks, and
-/// non-termination.
+/// The behavior resulting from such a logic error is not specified (it could include panics,
+/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
+/// behavior.
 ///
 /// [`Ord`]: core::cmp::Ord
 /// [`Cell`]: core::cell::Cell
@@ -92,6 +92,7 @@ fn clone_from(&mut self, other: &Self) {
 /// See its documentation for more.
 ///
 /// [`iter`]: BTreeSet::iter
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, T: 'a> {
     iter: Keys<'a, T, ()>,
@@ -123,6 +124,7 @@ pub struct IntoIter<T> {
 /// See its documentation for more.
 ///
 /// [`range`]: BTreeSet::range
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[derive(Debug)]
 #[stable(feature = "btree_range", since = "1.17.0")]
 pub struct Range<'a, T: 'a> {
@@ -135,6 +137,8 @@ pub struct Range<'a, T: 'a> {
 /// See its documentation for more.
 ///
 /// [`difference`]: BTreeSet::difference
+#[must_use = "this returns the difference as an iterator, \
+              without modifying either input set"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Difference<'a, T: 'a> {
     inner: DifferenceInner<'a, T>,
@@ -167,6 +171,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// [`BTreeSet`]. See its documentation for more.
 ///
 /// [`symmetric_difference`]: BTreeSet::symmetric_difference
+#[must_use = "this returns the difference as an iterator, \
+              without modifying either input set"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SymmetricDifference<'a, T: 'a>(MergeIterInner<Iter<'a, T>>);
 
@@ -183,6 +189,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// See its documentation for more.
 ///
 /// [`intersection`]: BTreeSet::intersection
+#[must_use = "this returns the intersection as an iterator, \
+              without modifying either input set"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Intersection<'a, T: 'a> {
     inner: IntersectionInner<'a, T>,
@@ -215,6 +223,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// See its documentation for more.
 ///
 /// [`union`]: BTreeSet::union
+#[must_use = "this returns the union as an iterator, \
+              without modifying either input set"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Union<'a, T: 'a>(MergeIterInner<Iter<'a, T>>);
 
@@ -668,6 +678,7 @@ pub fn is_superset(&self, other: &BTreeSet<T>) -> bool
     /// set.insert(2);
     /// assert_eq!(set.first(), Some(&1));
     /// ```
+    #[must_use]
     #[unstable(feature = "map_first_last", issue = "62924")]
     pub fn first(&self) -> Option<&T>
     where
@@ -694,6 +705,7 @@ pub fn first(&self) -> Option<&T>
     /// set.insert(2);
     /// assert_eq!(set.last(), Some(&2));
     /// ```
+    #[must_use]
     #[unstable(feature = "map_first_last", issue = "62924")]
     pub fn last(&self) -> Option<&T>
     where
@@ -1034,6 +1046,7 @@ pub fn iter(&self) -> Iter<'_, T> {
     /// v.insert(1);
     /// assert_eq!(v.len(), 1);
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
     pub const fn len(&self) -> usize {
@@ -1052,6 +1065,7 @@ pub const fn len(&self) -> usize {
     /// v.insert(1);
     /// assert!(!v.is_empty());
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
     pub const fn is_empty(&self) -> bool {
index 0a87ae12d61a59a34f957903aef3d0958010b9e6..2fc17a7c8603fc0b32afab1a79058d9043554d95 100644 (file)
@@ -610,11 +610,11 @@ fn union<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
 #[test]
 fn test_ord_absence() {
     fn set<K>(mut set: BTreeSet<K>) {
-        set.is_empty();
-        set.len();
+        let _ = set.is_empty();
+        let _ = set.len();
         set.clear();
-        set.iter();
-        set.into_iter();
+        let _ = set.iter();
+        let _ = set.into_iter();
     }
 
     fn set_debug<K: Debug>(set: BTreeSet<K>) {
index ea010c1f89d24ee1d9820933860cf340d4b9f488..e4913b16adbe7722b14e755f25e5954ecda47168 100644 (file)
@@ -64,6 +64,7 @@ struct Node<T> {
 ///
 /// This `struct` is created by [`LinkedList::iter()`]. See its
 /// documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, T: 'a> {
     head: Option<NonNull<Node<T>>>,
@@ -99,6 +100,7 @@ fn clone(&self) -> Self {
 ///
 /// This `struct` is created by [`LinkedList::iter_mut()`]. See its
 /// documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IterMut<'a, T: 'a> {
     head: Option<NonNull<Node<T>>>,
@@ -529,6 +531,7 @@ pub fn iter_mut(&mut self) -> IterMut<'_, T> {
     ///
     /// The cursor is pointing to the "ghost" non-element if the list is empty.
     #[inline]
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn cursor_front(&self) -> Cursor<'_, T> {
         Cursor { index: 0, current: self.head, list: self }
@@ -538,6 +541,7 @@ pub fn cursor_front(&self) -> Cursor<'_, T> {
     ///
     /// The cursor is pointing to the "ghost" non-element if the list is empty.
     #[inline]
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T> {
         CursorMut { index: 0, current: self.head, list: self }
@@ -547,6 +551,7 @@ pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T> {
     ///
     /// The cursor is pointing to the "ghost" non-element if the list is empty.
     #[inline]
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn cursor_back(&self) -> Cursor<'_, T> {
         Cursor { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self }
@@ -556,6 +561,7 @@ pub fn cursor_back(&self) -> Cursor<'_, T> {
     ///
     /// The cursor is pointing to the "ghost" non-element if the list is empty.
     #[inline]
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T> {
         CursorMut { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self }
@@ -577,6 +583,7 @@ pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T> {
     /// assert!(!dl.is_empty());
     /// ```
     #[inline]
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_empty(&self) -> bool {
         self.head.is_none()
@@ -603,6 +610,7 @@ pub fn is_empty(&self) -> bool {
     /// assert_eq!(dl.len(), 3);
     /// ```
     #[inline]
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn len(&self) -> usize {
         self.len
@@ -678,6 +686,7 @@ pub fn contains(&self, x: &T) -> bool
     /// assert_eq!(dl.front(), Some(&1));
     /// ```
     #[inline]
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn front(&self) -> Option<&T> {
         unsafe { self.head.as_ref().map(|node| &node.as_ref().element) }
@@ -706,6 +715,7 @@ pub fn front(&self) -> Option<&T> {
     /// assert_eq!(dl.front(), Some(&5));
     /// ```
     #[inline]
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn front_mut(&mut self) -> Option<&mut T> {
         unsafe { self.head.as_mut().map(|node| &mut node.as_mut().element) }
@@ -728,6 +738,7 @@ pub fn front_mut(&mut self) -> Option<&mut T> {
     /// assert_eq!(dl.back(), Some(&1));
     /// ```
     #[inline]
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn back(&self) -> Option<&T> {
         unsafe { self.tail.as_ref().map(|node| &node.as_ref().element) }
@@ -1178,6 +1189,7 @@ impl<'a, T> Cursor<'a, T> {
     ///
     /// This returns `None` if the cursor is currently pointing to the
     /// "ghost" non-element.
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn index(&self) -> Option<usize> {
         let _ = self.current?;
@@ -1232,6 +1244,7 @@ pub fn move_prev(&mut self) {
     ///
     /// This returns `None` if the cursor is currently pointing to the
     /// "ghost" non-element.
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn current(&self) -> Option<&'a T> {
         unsafe { self.current.map(|current| &(*current.as_ptr()).element) }
@@ -1242,6 +1255,7 @@ pub fn current(&self) -> Option<&'a T> {
     /// If the cursor is pointing to the "ghost" non-element then this returns
     /// the first element of the `LinkedList`. If it is pointing to the last
     /// element of the `LinkedList` then this returns `None`.
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn peek_next(&self) -> Option<&'a T> {
         unsafe {
@@ -1258,6 +1272,7 @@ pub fn peek_next(&self) -> Option<&'a T> {
     /// If the cursor is pointing to the "ghost" non-element then this returns
     /// the last element of the `LinkedList`. If it is pointing to the first
     /// element of the `LinkedList` then this returns `None`.
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn peek_prev(&self) -> Option<&'a T> {
         unsafe {
@@ -1271,6 +1286,7 @@ pub fn peek_prev(&self) -> Option<&'a T> {
 
     /// Provides a reference to the front element of the cursor's parent list,
     /// or None if the list is empty.
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn front(&self) -> Option<&'a T> {
         self.list.front()
@@ -1278,6 +1294,7 @@ pub fn front(&self) -> Option<&'a T> {
 
     /// Provides a reference to the back element of the cursor's parent list,
     /// or None if the list is empty.
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn back(&self) -> Option<&'a T> {
         self.list.back()
@@ -1289,6 +1306,7 @@ impl<'a, T> CursorMut<'a, T> {
     ///
     /// This returns `None` if the cursor is currently pointing to the
     /// "ghost" non-element.
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn index(&self) -> Option<usize> {
         let _ = self.current?;
@@ -1343,6 +1361,7 @@ pub fn move_prev(&mut self) {
     ///
     /// This returns `None` if the cursor is currently pointing to the
     /// "ghost" non-element.
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn current(&mut self) -> Option<&mut T> {
         unsafe { self.current.map(|current| &mut (*current.as_ptr()).element) }
@@ -1631,6 +1650,7 @@ pub fn pop_back(&mut self) -> Option<T> {
 
     /// Provides a reference to the front element of the cursor's parent list,
     /// or None if the list is empty.
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn front(&self) -> Option<&T> {
         self.list.front()
@@ -1638,6 +1658,7 @@ pub fn front(&self) -> Option<&T> {
 
     /// Provides a mutable reference to the front element of the cursor's
     /// parent list, or None if the list is empty.
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn front_mut(&mut self) -> Option<&mut T> {
         self.list.front_mut()
@@ -1645,6 +1666,7 @@ pub fn front_mut(&mut self) -> Option<&mut T> {
 
     /// Provides a reference to the back element of the cursor's parent list,
     /// or None if the list is empty.
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn back(&self) -> Option<&T> {
         self.list.back()
@@ -1671,6 +1693,7 @@ pub fn back(&self) -> Option<&T> {
     /// assert_eq!(contents.next(), Some(0));
     /// assert_eq!(contents.next(), None);
     /// ```
+    #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
     pub fn back_mut(&mut self) -> Option<&mut T> {
         self.list.back_mut()
index 77d28bdfe647598892f9da5a3f44fb2df0504270..1ea135a2aed82aaa12d71598a977e7737eda0277 100644 (file)
@@ -65,6 +65,7 @@ pub struct TryReserveError {
 impl TryReserveError {
     /// Details about the allocation that caused the error
     #[inline]
+    #[must_use]
     #[unstable(
         feature = "try_reserve_kind",
         reason = "Uncertain how much info should be exposed",
index c890ff4ac5e2b7bff45511a0c80d3f00bcaff865..de607c8fdab31dd098a5ee88c1f76dd81f41ac85 100644 (file)
@@ -543,9 +543,9 @@ pub fn new_in(alloc: A) -> VecDeque<T, A> {
     /// ```
     #[unstable(feature = "allocator_api", issue = "32838")]
     pub fn with_capacity_in(capacity: usize, alloc: A) -> VecDeque<T, A> {
+        assert!(capacity < 1_usize << usize::BITS - 1, "capacity overflow");
         // +1 since the ringbuffer always leaves one space empty
         let cap = cmp::max(capacity + 1, MINIMUM_CAPACITY + 1).next_power_of_two();
-        assert!(cap > capacity, "capacity overflow");
 
         VecDeque { tail: 0, head: 0, buf: RawVec::with_capacity_in(cap, alloc) }
     }
index 878d8dc5502df8d552dc4bed84165ad592876d33..50e789d76b7f3b951bf2f581f8d74e3f7ebdc633 100644 (file)
 /// [`format_args!`]: core::format_args
 /// [`format!`]: crate::format
 #[cfg(not(no_global_oom_handling))]
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn format(args: Arguments<'_>) -> string::String {
     let capacity = args.estimated_capacity();
index 635708fd4cf6e71a0ba6975068e7c1c34807ac32..5dda7bfa37c71ea94aabb6a68bd95f6781472fbd 100644 (file)
 )]
 #![no_std]
 #![needs_allocator]
+//
+// Lints:
+#![deny(unsafe_op_in_unsafe_fn)]
 #![warn(deprecated_in_future)]
-#![warn(missing_docs)]
 #![warn(missing_debug_implementations)]
+#![warn(missing_docs)]
 #![allow(explicit_outlives_requirements)]
-#![deny(unsafe_op_in_unsafe_fn)]
-#![feature(rustc_allow_const_fn_unstable)]
-#![cfg_attr(not(test), feature(generator_trait))]
-#![cfg_attr(test, feature(test))]
-#![cfg_attr(test, feature(new_uninit))]
+//
+// Library features:
+#![feature(alloc_layout_extra)]
 #![feature(allocator_api)]
 #![feature(array_chunks)]
 #![feature(array_methods)]
 #![feature(array_windows)]
-#![feature(allow_internal_unstable)]
-#![feature(arbitrary_self_types)]
 #![feature(async_stream)]
-#![feature(box_patterns)]
-#![feature(box_syntax)]
-#![feature(cfg_sanitize)]
-#![feature(cfg_target_has_atomic)]
 #![feature(coerce_unsized)]
 #![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))]
-#![feature(const_fn_trait_bound)]
-#![feature(cow_is_borrowed)]
 #![feature(const_cow_is_borrowed)]
-#![feature(const_trait_impl)]
-#![feature(destructuring_assignment)]
-#![feature(dispatch_from_dyn)]
 #![feature(core_intrinsics)]
-#![feature(dropck_eyepatch)]
+#![feature(dispatch_from_dyn)]
 #![feature(exact_size_is_empty)]
-#![feature(exclusive_range_pattern)]
 #![feature(extend_one)]
 #![feature(fmt_internals)]
 #![feature(fn_traits)]
-#![feature(fundamental)]
+#![feature(inherent_ascii_escape)]
 #![feature(inplace_iteration)]
-// Technically, this is a bug in rustdoc: rustdoc sees the documentation on `#[lang = slice_alloc]`
-// blocks is for `&[T]`, which also has documentation using this feature in `core`, and gets mad
-// that the feature-gate isn't enabled. Ideally, it wouldn't check for the feature gate for docs
-// from other crates, but since this can only appear for lang items, it doesn't seem worth fixing.
-#![feature(intra_doc_pointers)]
 #![feature(iter_advance_by)]
 #![feature(iter_zip)]
-#![feature(lang_items)]
 #![feature(layout_for_ptr)]
-#![feature(negative_impls)]
-#![feature(never_type)]
-#![feature(nll)]
+#![feature(maybe_uninit_extra)]
+#![feature(maybe_uninit_slice)]
+#![cfg_attr(test, feature(new_uninit))]
 #![feature(nonnull_slice_from_raw_parts)]
-#![feature(auto_traits)]
-#![feature(option_result_unwrap_unchecked)]
 #![feature(pattern)]
 #![feature(ptr_internals)]
-#![feature(rustc_attrs)]
 #![feature(receiver_trait)]
-#![feature(min_specialization)]
 #![feature(set_ptr_value)]
+#![feature(slice_group_by)]
 #![feature(slice_ptr_get)]
 #![feature(slice_ptr_len)]
 #![feature(slice_range)]
-#![feature(staged_api)]
 #![feature(str_internals)]
 #![feature(trusted_len)]
-#![feature(unboxed_closures)]
+#![feature(trusted_random_access)]
+#![feature(try_trait_v2)]
 #![feature(unicode_internals)]
 #![feature(unsize)]
-#![feature(unsized_fn_params)]
+//
+// Language features:
 #![feature(allocator_internals)]
-#![feature(slice_partition_dedup)]
-#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)]
-#![feature(alloc_layout_extra)]
-#![feature(trusted_random_access)]
-#![feature(try_trait_v2)]
+#![feature(allow_internal_unstable)]
 #![feature(associated_type_bounds)]
-#![feature(slice_group_by)]
-#![feature(decl_macro)]
+#![feature(box_syntax)]
+#![feature(cfg_sanitize)]
+#![feature(cfg_target_has_atomic)]
+#![feature(const_fn_trait_bound)]
+#![feature(const_trait_impl)]
+#![feature(destructuring_assignment)]
+#![feature(dropck_eyepatch)]
+#![feature(exclusive_range_pattern)]
+#![feature(fundamental)]
+#![cfg_attr(not(test), feature(generator_trait))]
+#![feature(lang_items)]
+#![feature(min_specialization)]
+#![feature(negative_impls)]
+#![feature(never_type)]
+#![feature(nll)] // Not necessary, but here to test the `nll` feature.
+#![feature(rustc_allow_const_fn_unstable)]
+#![feature(rustc_attrs)]
+#![feature(staged_api)]
+#![cfg_attr(test, feature(test))]
+#![feature(unboxed_closures)]
+#![feature(unsized_fn_params)]
+//
+// Rustdoc features:
 #![feature(doc_cfg)]
-#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))]
-// Allow testing this library
+#![feature(doc_cfg_hide)]
+// Technically, this is a bug in rustdoc: rustdoc sees the documentation on `#[lang = slice_alloc]`
+// blocks is for `&[T]`, which also has documentation using this feature in `core`, and gets mad
+// that the feature-gate isn't enabled. Ideally, it wouldn't check for the feature gate for docs
+// from other crates, but since this can only appear for lang items, it doesn't seem worth fixing.
+#![feature(intra_doc_pointers)]
 
+// Allow testing this library
 #[cfg(test)]
 #[macro_use]
 extern crate std;
index 493cf3117edf6a8b113f3772900c644c23facb47..4fb2f0c8530d7e983aad7e7dc57c8071d5589f30 100644 (file)
@@ -41,7 +41,7 @@
 //! use std::rc::Rc;
 //!
 //! let my_rc = Rc::new(());
-//! Rc::downgrade(&my_rc);
+//! let my_weak = Rc::downgrade(&my_rc);
 //! ```
 //!
 //! `Rc<T>`'s implementations of traits like `Clone` may also be called using
@@ -318,6 +318,8 @@ impl<T: ?Sized> !marker::Sync for Rc<T> {}
 
 #[stable(feature = "catch_unwind", since = "1.9.0")]
 impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Rc<T> {}
+#[stable(feature = "rc_ref_unwind_safe", since = "1.58.0")]
+impl<T: RefUnwindSafe + ?Sized> RefUnwindSafe for Rc<T> {}
 
 #[unstable(feature = "coerce_unsized", issue = "27732")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
@@ -889,6 +891,8 @@ pub unsafe fn from_raw(ptr: *const T) -> Self {
     ///
     /// let weak_five = Rc::downgrade(&five);
     /// ```
+    #[must_use = "this returns a new `Weak` pointer, \
+                  without modifying the original `Rc`"]
     #[stable(feature = "rc_weak", since = "1.4.0")]
     pub fn downgrade(this: &Self) -> Weak<T> {
         this.inner().inc_weak();
@@ -2246,6 +2250,7 @@ pub fn upgrade(&self) -> Option<Rc<T>> {
     /// Gets the number of strong (`Rc`) pointers pointing to this allocation.
     ///
     /// If `self` was created using [`Weak::new`], this will return 0.
+    #[must_use]
     #[stable(feature = "weak_counts", since = "1.41.0")]
     pub fn strong_count(&self) -> usize {
         if let Some(inner) = self.inner() { inner.strong() } else { 0 }
@@ -2254,6 +2259,7 @@ pub fn strong_count(&self) -> usize {
     /// Gets the number of `Weak` pointers pointing to this allocation.
     ///
     /// If no strong pointers remain, this will return zero.
+    #[must_use]
     #[stable(feature = "weak_counts", since = "1.41.0")]
     pub fn weak_count(&self) -> usize {
         self.inner()
@@ -2324,6 +2330,7 @@ fn inner(&self) -> Option<WeakInner<'_>> {
     /// assert!(!first.ptr_eq(&third));
     /// ```
     #[inline]
+    #[must_use]
     #[stable(feature = "weak_ptr_eq", since = "1.39.0")]
     pub fn ptr_eq(&self, other: &Self) -> bool {
         self.ptr.as_ptr() == other.ptr.as_ptr()
index 860f21085f32542ffc1854ba2dfe55bea5ee2106..ae730be0d25a57155e6e2cc8cf99bec1e9d902ae 100644 (file)
 pub use core::slice::ArrayChunksMut;
 #[unstable(feature = "array_windows", issue = "75027")]
 pub use core::slice::ArrayWindows;
+#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+pub use core::slice::EscapeAscii;
 #[stable(feature = "slice_get_slice", since = "1.28.0")]
 pub use core::slice::SliceIndex;
 #[stable(feature = "from_ref", since = "1.28.0")]
 pub use core::slice::{RSplit, RSplitMut};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut};
+#[stable(feature = "split_inclusive", since = "1.51.0")]
+pub use core::slice::{SplitInclusive, SplitInclusiveMut};
 
 ////////////////////////////////////////////////////////////////////////////////
 // Basic slice extension methods
index e1d0ee42f4e901a8c7839c80f6f6fb0b25475b28..104f5556566f4e5370c6dde8d0c9654b6bffc406 100644 (file)
@@ -46,7 +46,7 @@
 pub use core::str::EncodeUtf16;
 #[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
 pub use core::str::SplitAsciiWhitespace;
-#[stable(feature = "split_inclusive", since = "1.53.0")]
+#[stable(feature = "split_inclusive", since = "1.51.0")]
 pub use core::str::SplitInclusive;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::str::SplitWhitespace;
@@ -243,6 +243,7 @@ impl str {
     /// assert_eq!(*boxed_bytes, *s.as_bytes());
     /// ```
     #[stable(feature = "str_box_extras", since = "1.20.0")]
+    #[must_use = "`self` will be dropped if the result is not used"]
     #[inline]
     pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]> {
         self.into()
@@ -484,6 +485,7 @@ pub fn to_uppercase(&self) -> String {
     /// assert_eq!(boxed_str.into_string(), string);
     /// ```
     #[stable(feature = "box_str", since = "1.4.0")]
+    #[must_use = "`self` will be dropped if the result is not used"]
     #[inline]
     pub fn into_string(self: Box<str>) -> String {
         let slice = Box::<[u8]>::from(self);
@@ -508,9 +510,10 @@ pub fn into_string(self: Box<str>) -> String {
     ///
     /// ```should_panic
     /// // this will panic at runtime
-    /// "0123456789abcdef".repeat(usize::MAX);
+    /// let huge = "0123456789abcdef".repeat(usize::MAX);
     /// ```
     #[cfg(not(no_global_oom_handling))]
+    #[must_use]
     #[stable(feature = "repeat_str", since = "1.16.0")]
     pub fn repeat(&self, n: usize) -> String {
         unsafe { String::from_utf8_unchecked(self.as_bytes().repeat(n)) }
index f479bf231b37681402bfb410926c81ec6d835716..906b0187f7babf540932b2cd408f71b88b308782 100644 (file)
@@ -552,6 +552,7 @@ pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
     ///
     /// assert_eq!("Hello �World", output);
     /// ```
+    #[must_use]
     #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> {
@@ -646,6 +647,7 @@ pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error> {
     ///            String::from_utf16_lossy(v));
     /// ```
     #[cfg(not(no_global_oom_handling))]
+    #[must_use]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn from_utf16_lossy(v: &[u16]) -> String {
@@ -898,6 +900,7 @@ pub fn extend_from_within<R>(&mut self, src: R)
     /// assert!(s.capacity() >= 10);
     /// ```
     #[inline]
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn capacity(&self) -> usize {
         self.vec.capacity()
@@ -1500,10 +1503,11 @@ pub fn insert_str(&mut self, idx: usize, string: &str) {
     ///
     /// # Safety
     ///
-    /// This function is unsafe because it does not check that the bytes passed
-    /// to it are valid UTF-8. If this constraint is violated, it may cause
-    /// memory unsafety issues with future users of the `String`, as the rest of
-    /// the standard library assumes that `String`s are valid UTF-8.
+    /// This function is unsafe because the returned `&mut Vec` allows writing
+    /// bytes which are not valid UTF-8. If this constraint is violated, using
+    /// the original `String` after dropping the `&mut Vec` may violate memory
+    /// safety, as the rest of the standard library assumes that `String`s are
+    /// valid UTF-8.
     ///
     /// # Examples
     ///
@@ -1543,6 +1547,7 @@ pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
     /// assert_eq!(fancy_f.chars().count(), 3);
     /// ```
     #[inline]
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn len(&self) -> usize {
         self.vec.len()
@@ -1562,6 +1567,7 @@ pub fn len(&self) -> usize {
     /// assert!(!v.is_empty());
     /// ```
     #[inline]
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_empty(&self) -> bool {
         self.len() == 0
@@ -1822,6 +1828,7 @@ pub fn into_bytes(self) -> Vec<u8> {
     /// // the first byte is invalid here
     /// assert_eq!(1, error.valid_up_to());
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn utf8_error(&self) -> Utf8Error {
         self.error
index b75e9a2f3c71ea77b0c1cd1ac717020317e79d45..b738337a2ddd19805fc0d623f6570077f6991a22 100644 (file)
@@ -804,6 +804,7 @@ impl<T: ?Sized> Arc<T> {
     /// let x_ptr = Arc::into_raw(x);
     /// assert_eq!(unsafe { &*x_ptr }, "hello");
     /// ```
+    #[must_use = "losing the pointer will leak memory"]
     #[stable(feature = "rc_raw", since = "1.17.0")]
     pub fn into_raw(this: Self) -> *const T {
         let ptr = Self::as_ptr(&this);
@@ -953,6 +954,7 @@ pub fn downgrade(this: &Self) -> Weak<T> {
     /// assert_eq!(1, Arc::weak_count(&five));
     /// ```
     #[inline]
+    #[must_use]
     #[stable(feature = "arc_counts", since = "1.15.0")]
     pub fn weak_count(this: &Self) -> usize {
         let cnt = this.inner().weak.load(SeqCst);
@@ -982,6 +984,7 @@ pub fn weak_count(this: &Self) -> usize {
     /// assert_eq!(2, Arc::strong_count(&five));
     /// ```
     #[inline]
+    #[must_use]
     #[stable(feature = "arc_counts", since = "1.15.0")]
     pub fn strong_count(this: &Self) -> usize {
         this.inner().strong.load(SeqCst)
@@ -1079,8 +1082,6 @@ unsafe fn drop_slow(&mut self) {
         drop(Weak { ptr: self.ptr });
     }
 
-    #[inline]
-    #[stable(feature = "ptr_eq", since = "1.17.0")]
     /// Returns `true` if the two `Arc`s point to the same allocation
     /// (in a vein similar to [`ptr::eq`]).
     ///
@@ -1098,6 +1099,9 @@ unsafe fn drop_slow(&mut self) {
     /// ```
     ///
     /// [`ptr::eq`]: core::ptr::eq "ptr::eq"
+    #[inline]
+    #[must_use]
+    #[stable(feature = "ptr_eq", since = "1.17.0")]
     pub fn ptr_eq(this: &Self, other: &Self) -> bool {
         this.ptr.as_ptr() == other.ptr.as_ptr()
     }
@@ -1904,6 +1908,7 @@ pub fn upgrade(&self) -> Option<Arc<T>> {
     /// Gets the number of strong (`Arc`) pointers pointing to this allocation.
     ///
     /// If `self` was created using [`Weak::new`], this will return 0.
+    #[must_use]
     #[stable(feature = "weak_counts", since = "1.41.0")]
     pub fn strong_count(&self) -> usize {
         if let Some(inner) = self.inner() { inner.strong.load(SeqCst) } else { 0 }
@@ -1920,6 +1925,7 @@ pub fn strong_count(&self) -> usize {
     /// Due to implementation details, the returned value can be off by 1 in
     /// either direction when other threads are manipulating any `Arc`s or
     /// `Weak`s pointing to the same allocation.
+    #[must_use]
     #[stable(feature = "weak_counts", since = "1.41.0")]
     pub fn weak_count(&self) -> usize {
         self.inner()
@@ -1999,6 +2005,7 @@ fn inner(&self) -> Option<WeakInner<'_>> {
     ///
     /// [`ptr::eq`]: core::ptr::eq "ptr::eq"
     #[inline]
+    #[must_use]
     #[stable(feature = "weak_ptr_eq", since = "1.39.0")]
     pub fn ptr_eq(&self, other: &Self) -> bool {
         self.ptr.as_ptr() == other.ptr.as_ptr()
index e643940d017ba690b5873a84ac36de9d86e47a95..ff98091a0d2abf18924b663e78634c827fce6e38 100644 (file)
@@ -60,6 +60,7 @@ pub fn as_slice(&self) -> &[T] {
 
     /// Returns a reference to the underlying allocator.
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[must_use]
     #[inline]
     pub fn allocator(&self) -> &A {
         unsafe { self.vec.as_ref().allocator() }
index 20a16869cb3f8bfd06966a9fc2053ca57daa43a6..d52c78eedf3fad28836477edd8dbc74489a609aa 100644 (file)
@@ -1305,10 +1305,11 @@ fn assert_failed(index: usize, len: usize) -> ! {
             // We replace self[index] with the last element. Note that if the
             // bounds check above succeeds there must be a last element (which
             // can be self[index] itself).
-            let last = ptr::read(self.as_ptr().add(len - 1));
-            let hole = self.as_mut_ptr().add(index);
+            let value = ptr::read(self.as_ptr().add(index));
+            let base_ptr = self.as_mut_ptr();
+            ptr::copy(base_ptr.add(len - 1), base_ptr.add(index), 1);
             self.set_len(len - 1);
-            ptr::replace(hole, last)
+            value
         }
     }
 
index d3a87c056cfb1867b588ad58fd33892a23de3587..dc7d0bff9a404ba8ec417b4ecfd17c3445e4c92d 100644 (file)
@@ -1031,7 +1031,7 @@ fn test_split_at_mut() {
 #[should_panic]
 fn test_split_at_boundscheck() {
     let s = "ศไทย中华Việt Nam";
-    s.split_at(1);
+    let _ = s.split_at(1);
 }
 
 #[test]
index cc89bb66f91b2b4a640b0b525ca5d753e3346d7e..7f14f76c8ba6945c052fab77022e6e768b58e0b4 160000 (submodule)
@@ -1 +1 @@
-Subproject commit cc89bb66f91b2b4a640b0b525ca5d753e3346d7e
+Subproject commit 7f14f76c8ba6945c052fab77022e6e768b58e0b4
index 780f82d8afaee1fbd50b0944123a5fd976aede17..cc32d5223b49f655f691017d675c0d363b5de444 100644 (file)
@@ -104,6 +104,7 @@ pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutEr
     /// The minimum size in bytes for a memory block of this layout.
     #[stable(feature = "alloc_layout", since = "1.28.0")]
     #[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")]
+    #[must_use]
     #[inline]
     pub const fn size(&self) -> usize {
         self.size_
@@ -137,6 +138,7 @@ pub const fn new<T>() -> Self {
     /// allocate backing structure for `T` (which could be a trait
     /// or other unsized type like a slice).
     #[stable(feature = "alloc_layout", since = "1.28.0")]
+    #[must_use]
     #[inline]
     pub fn for_value<T: ?Sized>(t: &T) -> Self {
         let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
@@ -171,6 +173,7 @@ pub fn for_value<T: ?Sized>(t: &T) -> Self {
     /// [trait object]: ../../book/ch17-02-trait-objects.html
     /// [extern type]: ../../unstable-book/language-features/extern-types.html
     #[unstable(feature = "layout_for_ptr", issue = "69835")]
+    #[must_use]
     pub unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
         // SAFETY: we pass along the prerequisites of these functions to the caller
         let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) };
@@ -187,6 +190,7 @@ pub unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
     /// some other means.
     #[unstable(feature = "alloc_layout_extra", issue = "55724")]
     #[rustc_const_unstable(feature = "alloc_layout_extra", issue = "55724")]
+    #[must_use]
     #[inline]
     pub const fn dangling(&self) -> NonNull<u8> {
         // SAFETY: align is guaranteed to be non-zero
index 19652106b3d01325f5f9f9266b7932447e594cd1..1fd5aa27fce46562c51ddc6d3b80a7bfc9b45464 100644 (file)
@@ -458,6 +458,7 @@ impl TypeId {
     /// assert_eq!(is_string(&0), false);
     /// assert_eq!(is_string(&"cookie monster".to_string()), true);
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
     pub const fn of<T: ?Sized + 'static>() -> TypeId {
@@ -492,6 +493,7 @@ pub const fn of<T: ?Sized + 'static>() -> TypeId {
 ///     "core::option::Option<alloc::string::String>",
 /// );
 /// ```
+#[must_use]
 #[stable(feature = "type_name", since = "1.38.0")]
 #[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
 pub const fn type_name<T: ?Sized>() -> &'static str {
@@ -534,6 +536,7 @@ pub const fn type_name<T: ?Sized>() -> &'static str {
 /// let y = 1.0;
 /// println!("{}", type_name_of_val(&y));
 /// ```
+#[must_use]
 #[unstable(feature = "type_name_of_val", issue = "66359")]
 #[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
 pub const fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str {
index 8d5c0510404fb2d7743b8c547895acc5b5b1e2cd..811850af3678d08480b6678f84a4f683759d6e66 100644 (file)
 
 /// Converts a reference to `T` into a reference to an array of length 1 (without copying).
 #[stable(feature = "array_from_ref", since = "1.53.0")]
-pub fn from_ref<T>(s: &T) -> &[T; 1] {
+#[rustc_const_unstable(feature = "const_array_from_ref", issue = "90206")]
+pub const fn from_ref<T>(s: &T) -> &[T; 1] {
     // SAFETY: Converting `&T` to `&[T; 1]` is sound.
     unsafe { &*(s as *const T).cast::<[T; 1]>() }
 }
 
 /// Converts a mutable reference to `T` into a mutable reference to an array of length 1 (without copying).
 #[stable(feature = "array_from_ref", since = "1.53.0")]
-pub fn from_mut<T>(s: &mut T) -> &mut [T; 1] {
+#[rustc_const_unstable(feature = "const_array_from_ref", issue = "90206")]
+pub const fn from_mut<T>(s: &mut T) -> &mut [T; 1] {
     // SAFETY: Converting `&mut T` to `&mut [T; 1]` is sound.
     unsafe { &mut *(s as *mut T).cast::<[T; 1]>() }
 }
@@ -125,7 +127,8 @@ pub fn __description(&self) -> &str {
 }
 
 #[stable(feature = "try_from_slice_error", since = "1.36.0")]
-impl From<Infallible> for TryFromSliceError {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<Infallible> for TryFromSliceError {
     fn from(x: Infallible) -> TryFromSliceError {
         match x {}
     }
@@ -499,6 +502,84 @@ pub fn as_mut_slice(&mut self) -> &mut [T] {
         // items.
         unsafe { collect_into_array_unchecked(&mut self.iter_mut()) }
     }
+
+    /// Divides one array reference into two at an index.
+    ///
+    /// The first will contain all indices from `[0, M)` (excluding
+    /// the index `M` itself) and the second will contain all
+    /// indices from `[M, N)` (excluding the index `N` itself).
+    ///
+    /// # Panics
+    ///
+    /// Panics if `M > N`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(split_array)]
+    ///
+    /// let v = [1, 2, 3, 4, 5, 6];
+    ///
+    /// {
+    ///    let (left, right) = v.split_array_ref::<0>();
+    ///    assert_eq!(left, &[]);
+    ///    assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
+    /// }
+    ///
+    /// {
+    ///     let (left, right) = v.split_array_ref::<2>();
+    ///     assert_eq!(left, &[1, 2]);
+    ///     assert_eq!(right, &[3, 4, 5, 6]);
+    /// }
+    ///
+    /// {
+    ///     let (left, right) = v.split_array_ref::<6>();
+    ///     assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
+    ///     assert_eq!(right, &[]);
+    /// }
+    /// ```
+    #[unstable(
+        feature = "split_array",
+        reason = "return type should have array as 2nd element",
+        issue = "90091"
+    )]
+    #[inline]
+    pub fn split_array_ref<const M: usize>(&self) -> (&[T; M], &[T]) {
+        (&self[..]).split_array_ref::<M>()
+    }
+
+    /// Divides one mutable array reference into two at an index.
+    ///
+    /// The first will contain all indices from `[0, M)` (excluding
+    /// the index `M` itself) and the second will contain all
+    /// indices from `[M, N)` (excluding the index `N` itself).
+    ///
+    /// # Panics
+    ///
+    /// Panics if `M > N`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(split_array)]
+    ///
+    /// let mut v = [1, 0, 3, 0, 5, 6];
+    /// let (left, right) = v.split_array_mut::<2>();
+    /// assert_eq!(left, &mut [1, 0][..]);
+    /// assert_eq!(right, &mut [3, 0, 5, 6]);
+    /// left[1] = 2;
+    /// right[1] = 4;
+    /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+    /// ```
+    #[unstable(
+        feature = "split_array",
+        reason = "return type should have array as 2nd element",
+        issue = "90091"
+    )]
+    #[inline]
+    pub fn split_array_mut<const M: usize>(&mut self) -> (&mut [T; M], &mut [T]) {
+        (&mut self[..]).split_array_mut::<M>()
+    }
 }
 
 /// Pulls `N` items from `iter` and returns them as an array. If the iterator
index 0a456ee1eb2d59fde0ac9d7c2b56382ee0a1da1a..532208e41afa2ba2b01169da64c061d0d5587347 100644 (file)
@@ -18,6 +18,7 @@
 ///
 /// This `struct` is created by the [`escape_default`] function. See its
 /// documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Clone)]
 pub struct EscapeDefault {
index 2ca077a98f8dc7500d4569274eb7143a80aee59c..d154bb3583c2d387d0757a0acb0fddc47ddbf63b 100644 (file)
@@ -308,7 +308,8 @@ fn cmp(&self, other: &Cell<T>) -> Ordering {
 }
 
 #[stable(feature = "cell_from", since = "1.12.0")]
-impl<T> From<T> for Cell<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<T> for Cell<T> {
     fn from(t: T) -> Cell<T> {
         Cell::new(t)
     }
@@ -1236,7 +1237,8 @@ fn cmp(&self, other: &RefCell<T>) -> Ordering {
 }
 
 #[stable(feature = "cell_from", since = "1.12.0")]
-impl<T> From<T> for RefCell<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<T> for RefCell<T> {
     fn from(t: T) -> RefCell<T> {
         RefCell::new(t)
     }
@@ -1333,6 +1335,7 @@ impl<'b, T: ?Sized> Ref<'b, T> {
     /// with the widespread use of `r.borrow().clone()` to clone the contents of
     /// a `RefCell`.
     #[stable(feature = "cell_extras", since = "1.15.0")]
+    #[must_use]
     #[inline]
     pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
         Ref { value: orig.value, borrow: orig.borrow.clone() }
@@ -1976,7 +1979,8 @@ fn default() -> UnsafeCell<T> {
 }
 
 #[stable(feature = "cell_from", since = "1.12.0")]
-impl<T> From<T> for UnsafeCell<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<T> for UnsafeCell<T> {
     fn from(t: T) -> UnsafeCell<T> {
         UnsafeCell::new(t)
     }
index 72921414fb3f29aa37905382b2751e41ff87eece..8fc6b1af92452919824a518383133eee11a30876 100644 (file)
@@ -97,7 +97,8 @@ pub unsafe fn from_u32_unchecked(i: u32) -> char {
 }
 
 #[stable(feature = "char_convert", since = "1.13.0")]
-impl From<char> for u32 {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<char> for u32 {
     /// Converts a [`char`] into a [`u32`].
     ///
     /// # Examples
@@ -116,7 +117,8 @@ fn from(c: char) -> Self {
 }
 
 #[stable(feature = "more_char_conversions", since = "1.51.0")]
-impl From<char> for u64 {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<char> for u64 {
     /// Converts a [`char`] into a [`u64`].
     ///
     /// # Examples
@@ -137,7 +139,8 @@ fn from(c: char) -> Self {
 }
 
 #[stable(feature = "more_char_conversions", since = "1.51.0")]
-impl From<char> for u128 {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<char> for u128 {
     /// Converts a [`char`] into a [`u128`].
     ///
     /// # Examples
@@ -176,7 +179,8 @@ fn from(c: char) -> Self {
 /// for a superset of Windows-1252 that fills the remaining blanks with corresponding
 /// C0 and C1 control codes.
 #[stable(feature = "char_convert", since = "1.13.0")]
-impl From<u8> for char {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<u8> for char {
     /// Converts a [`u8`] into a [`char`].
     ///
     /// # Examples
index 4784418f98c507d0313a14c314ac90191b1ce640..5dd8c5ef78941835b3619b63636e2214d00c4620 100644 (file)
@@ -128,6 +128,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 
 impl DecodeUtf16Error {
     /// Returns the unpaired surrogate which caused this error.
+    #[must_use]
     #[stable(feature = "decode_utf16", since = "1.9.0")]
     pub fn unpaired_surrogate(&self) -> u16 {
         self.code
index b02333b028850fd7a831adeb811e3bd6c7b37e61..281ff3badfbd8de32fc47e83cfeec042890dbd67 100644 (file)
 #[stable(feature = "rust1", since = "1.0.0")]
 #[lang = "clone"]
 #[rustc_diagnostic_item = "Clone"]
-#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)]
+#[rustc_trivial_field_reads]
 pub trait Clone: Sized {
     /// Returns a copy of the value.
     ///
index 5ac9fdec0cf58f9a1618b8eda53d32ab52fd3da6..7456f886ea5d8c41555b83d52afdf5fa141bfff1 100644 (file)
@@ -323,6 +323,7 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> {
 /// ```
 #[derive(Clone, Copy, PartialEq, Debug, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[repr(i8)]
 pub enum Ordering {
     /// An ordering where a compared value is less than another.
     #[stable(feature = "rust1", since = "1.0.0")]
index fb8305273a83cbb3740d32fbef0c4f8b26fc320d..5aa53deee343d55820c19526dfe76d081184ece0 100644 (file)
@@ -545,7 +545,8 @@ fn into(self) -> U {
 
 // From (and thus Into) is reflexive
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> From<T> for T {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<T> for T {
     fn from(t: T) -> T {
         t
     }
@@ -560,7 +561,8 @@ fn from(t: T) -> T {
 #[allow(unused_attributes)] // FIXME(#58633): do a principled fix instead.
 #[rustc_reservation_impl = "permitting this impl would forbid us from adding \
                             `impl<T> From<!> for T` later; see rust-lang/rust#64715 for details"]
-impl<T> From<!> for T {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<!> for T {
     fn from(t: !) -> T {
         t
     }
@@ -726,7 +728,8 @@ fn cmp(&self, _other: &Self) -> crate::cmp::Ordering {
 }
 
 #[stable(feature = "convert_infallible", since = "1.34.0")]
-impl From<!> for Infallible {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<!> for Infallible {
     fn from(x: !) -> Self {
         x
     }
index 75ef873abc965f40f2bf53258d1e4ab352de5565..2b6ea90bf043019dd9f177fcb313716e8ab42d88 100644 (file)
@@ -390,7 +390,8 @@ mod ptr_try_from_impls {
 macro_rules! nzint_impl_from {
     ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => {
         #[$attr]
-        impl From<$Small> for $Large {
+        #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
+        impl const From<$Small> for $Large {
             // Rustdocs on the impl block show a "[+] show undocumented items" toggle.
             // Rustdocs on functions do not.
             #[doc = $doc]
@@ -398,7 +399,7 @@ impl From<$Small> for $Large {
             fn from(small: $Small) -> Self {
                 // SAFETY: input type guarantees the value is non-zero
                 unsafe {
-                    Self::new_unchecked(small.get().into())
+                    Self::new_unchecked(From::from(small.get()))
                 }
             }
         }
index 0ee8cd59ba4ff8c500356d7a407ae315f46c4d61..fb862f7df947bc5d688cf1bb46446a8de968ffee 100644 (file)
@@ -155,6 +155,7 @@ pub trait Default: Sized {
 /// }
 /// ```
 #[unstable(feature = "default_free_fn", issue = "73014")]
+#[must_use]
 #[inline]
 pub fn default<T: Default>() -> T {
     Default::default()
index ba65f0fadbd9d88a38ff35fb8c4fa2e1d5154b74..89d5fac30d3576bc347c25a2e73f2a578b54aec1 100644 (file)
@@ -3,6 +3,26 @@
 use crate::num::flt2dec;
 use crate::num::fmt as numfmt;
 
+#[doc(hidden)]
+trait GeneralFormat: PartialOrd {
+    /// Determines if a value should use exponential based on its magnitude, given the precondition
+    /// that it will not be rounded any further before it is displayed.
+    fn already_rounded_value_should_use_exponential(&self) -> bool;
+}
+
+macro_rules! impl_general_format {
+    ($($t:ident)*) => {
+        $(impl GeneralFormat for $t {
+            fn already_rounded_value_should_use_exponential(&self) -> bool {
+                let abs = $t::abs_private(*self);
+                (abs != 0.0 && abs < 1e-4) || abs >= 1e+16
+            }
+        })*
+    }
+}
+
+impl_general_format! { f32 f64 }
+
 // Don't inline this so callers don't use the stack space this function
 // requires unless they have to.
 #[inline(never)]
@@ -54,8 +74,7 @@ fn float_to_decimal_common_shortest<T>(
     fmt.pad_formatted_parts(&formatted)
 }
 
-// Common code of floating point Debug and Display.
-fn float_to_decimal_common<T>(fmt: &mut Formatter<'_>, num: &T, min_precision: usize) -> Result
+fn float_to_decimal_display<T>(fmt: &mut Formatter<'_>, num: &T) -> Result
 where
     T: flt2dec::DecodableFloat,
 {
@@ -68,6 +87,7 @@ fn float_to_decimal_common<T>(fmt: &mut Formatter<'_>, num: &T, min_precision: u
     if let Some(precision) = fmt.precision {
         float_to_decimal_common_exact(fmt, num, sign, precision)
     } else {
+        let min_precision = 0;
         float_to_decimal_common_shortest(fmt, num, sign, min_precision)
     }
 }
@@ -145,19 +165,44 @@ fn float_to_exponential_common<T>(fmt: &mut Formatter<'_>, num: &T, upper: bool)
     }
 }
 
+fn float_to_general_debug<T>(fmt: &mut Formatter<'_>, num: &T) -> Result
+where
+    T: flt2dec::DecodableFloat + GeneralFormat,
+{
+    let force_sign = fmt.sign_plus();
+    let sign = match force_sign {
+        false => flt2dec::Sign::Minus,
+        true => flt2dec::Sign::MinusPlus,
+    };
+
+    if let Some(precision) = fmt.precision {
+        // this behavior of {:.PREC?} predates exponential formatting for {:?}
+        float_to_decimal_common_exact(fmt, num, sign, precision)
+    } else {
+        // since there is no precision, there will be no rounding
+        if num.already_rounded_value_should_use_exponential() {
+            let upper = false;
+            float_to_exponential_common_shortest(fmt, num, sign, upper)
+        } else {
+            let min_precision = 1;
+            float_to_decimal_common_shortest(fmt, num, sign, min_precision)
+        }
+    }
+}
+
 macro_rules! floating {
     ($ty:ident) => {
         #[stable(feature = "rust1", since = "1.0.0")]
         impl Debug for $ty {
             fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
-                float_to_decimal_common(fmt, self, 1)
+                float_to_general_debug(fmt, self)
             }
         }
 
         #[stable(feature = "rust1", since = "1.0.0")]
         impl Display for $ty {
             fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
-                float_to_decimal_common(fmt, self, 0)
+                float_to_decimal_display(fmt, self)
             }
         }
 
index b8ad7720e0c554590226f08f3d3da7dcbc4b307e..80d3270d73cc824a80759b328ac5dd3eb4fecfe3 100644 (file)
@@ -374,7 +374,6 @@ pub const fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> A
     ///    valid index of `args`.
     /// 3. Every [`Count::Param`] within `fmt` must contain a valid index of
     ///    `args`.
-    #[cfg(not(bootstrap))]
     #[doc(hidden)]
     #[inline]
     #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
@@ -388,19 +387,6 @@ pub const fn new_v1_formatted(
         Arguments { pieces, fmt: Some(fmt), args }
     }
 
-    #[cfg(bootstrap)]
-    #[doc(hidden)]
-    #[inline]
-    #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
-    #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
-    pub const unsafe fn new_v1_formatted(
-        pieces: &'a [&'static str],
-        args: &'a [ArgumentV1<'a>],
-        fmt: &'a [rt::v1::Argument],
-    ) -> Arguments<'a> {
-        Arguments { pieces, fmt: Some(fmt), args }
-    }
-
     /// Estimates the length of the formatted text.
     ///
     /// This is intended to be used for setting initial `String` capacity
@@ -619,7 +605,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
 )]
 #[doc(alias = "{:?}")]
 #[rustc_diagnostic_item = "Debug"]
-#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)]
+#[rustc_trivial_field_reads]
 pub trait Debug {
     /// Formats the value using the given formatter.
     ///
@@ -1618,6 +1604,7 @@ pub fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result {
     }
 
     /// Flags for formatting
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_deprecated(
         since = "1.24.0",
@@ -1655,6 +1642,7 @@ pub fn flags(&self) -> u32 {
     /// assert_eq!(&format!("{:G>3}", Foo), "GGG");
     /// assert_eq!(&format!("{:t>6}", Foo), "tttttt");
     /// ```
+    #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
     pub fn fill(&self) -> char {
         self.fill
@@ -1691,6 +1679,7 @@ pub fn fill(&self) -> char {
     /// assert_eq!(&format!("{:^}", Foo), "center");
     /// assert_eq!(&format!("{}", Foo), "into the void");
     /// ```
+    #[must_use]
     #[stable(feature = "fmt_flags_align", since = "1.28.0")]
     pub fn align(&self) -> Option<Alignment> {
         match self.align {
@@ -1725,6 +1714,7 @@ pub fn align(&self) -> Option<Alignment> {
     /// assert_eq!(&format!("{:10}", Foo(23)), "Foo(23)   ");
     /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
     /// ```
+    #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
     pub fn width(&self) -> Option<usize> {
         self.width
@@ -1755,6 +1745,7 @@ pub fn width(&self) -> Option<usize> {
     /// assert_eq!(&format!("{:.4}", Foo(23.2)), "Foo(23.2000)");
     /// assert_eq!(&format!("{}", Foo(23.2)), "Foo(23.20)");
     /// ```
+    #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
     pub fn precision(&self) -> Option<usize> {
         self.precision
@@ -1785,6 +1776,7 @@ pub fn precision(&self) -> Option<usize> {
     /// assert_eq!(&format!("{:+}", Foo(23)), "Foo(+23)");
     /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
     /// ```
+    #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
     pub fn sign_plus(&self) -> bool {
         self.flags & (1 << FlagV1::SignPlus as u32) != 0
@@ -1813,6 +1805,7 @@ pub fn sign_plus(&self) -> bool {
     /// assert_eq!(&format!("{:-}", Foo(23)), "-Foo(23)");
     /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
     /// ```
+    #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
     pub fn sign_minus(&self) -> bool {
         self.flags & (1 << FlagV1::SignMinus as u32) != 0
@@ -1840,6 +1833,7 @@ pub fn sign_minus(&self) -> bool {
     /// assert_eq!(&format!("{:#}", Foo(23)), "Foo(23)");
     /// assert_eq!(&format!("{}", Foo(23)), "23");
     /// ```
+    #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
     pub fn alternate(&self) -> bool {
         self.flags & (1 << FlagV1::Alternate as u32) != 0
@@ -1865,6 +1859,7 @@ pub fn alternate(&self) -> bool {
     ///
     /// assert_eq!(&format!("{:04}", Foo(23)), "23");
     /// ```
+    #[must_use]
     #[stable(feature = "fmt_flags", since = "1.5.0")]
     pub fn sign_aware_zero_pad(&self) -> bool {
         self.flags & (1 << FlagV1::SignAwareZeroPad as u32) != 0
index cdde0941470121cd172bc0f9d8497bee772bc498..7a3af70d6d97c3fa6533199960b94087ec83e3ce 100644 (file)
@@ -90,6 +90,7 @@ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
 #[lang = "get_context"]
 #[doc(hidden)]
 #[unstable(feature = "gen_future", issue = "50547")]
+#[must_use]
 #[inline]
 pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
     // SAFETY: the caller must guarantee that `cx.0` is a valid pointer
index be12f90464084306b2b1b8beaba0984936b16320..9c6acfb1e8c94f823ef1cb864dc62541074f9da1 100644 (file)
@@ -5,6 +5,23 @@ macro_rules! forward_ref_unop {
         forward_ref_unop!(impl $imp, $method for $t,
                 #[stable(feature = "rust1", since = "1.0.0")]);
     };
+    (impl const $imp:ident, $method:ident for $t:ty) => {
+        forward_ref_unop!(impl const $imp, $method for $t,
+                #[stable(feature = "rust1", since = "1.0.0")]);
+    };
+    // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
+    (impl const $imp:ident, $method:ident for $t:ty, #[$attr:meta]) => {
+        #[$attr]
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const $imp for &$t {
+            type Output = <$t as $imp>::Output;
+
+            #[inline]
+            fn $method(self) -> <$t as $imp>::Output {
+                $imp::$method(*self)
+            }
+        }
+    };
     (impl $imp:ident, $method:ident for $t:ty, #[$attr:meta]) => {
         #[$attr]
         impl $imp for &$t {
@@ -25,6 +42,45 @@ macro_rules! forward_ref_binop {
         forward_ref_binop!(impl $imp, $method for $t, $u,
                 #[stable(feature = "rust1", since = "1.0.0")]);
     };
+    (impl const $imp:ident, $method:ident for $t:ty, $u:ty) => {
+        forward_ref_binop!(impl const $imp, $method for $t, $u,
+                #[stable(feature = "rust1", since = "1.0.0")]);
+    };
+    // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
+    (impl const $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
+        #[$attr]
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl<'a> const $imp<$u> for &'a $t {
+            type Output = <$t as $imp<$u>>::Output;
+
+            #[inline]
+            fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
+                $imp::$method(*self, other)
+            }
+        }
+
+        #[$attr]
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const $imp<&$u> for $t {
+            type Output = <$t as $imp<$u>>::Output;
+
+            #[inline]
+            fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
+                $imp::$method(self, *other)
+            }
+        }
+
+        #[$attr]
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const $imp<&$u> for &$t {
+            type Output = <$t as $imp<$u>>::Output;
+
+            #[inline]
+            fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
+                $imp::$method(*self, *other)
+            }
+        }
+    };
     (impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
         #[$attr]
         impl<'a> $imp<$u> for &'a $t {
@@ -65,6 +121,21 @@ macro_rules! forward_ref_op_assign {
         forward_ref_op_assign!(impl $imp, $method for $t, $u,
                 #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]);
     };
+    (impl const $imp:ident, $method:ident for $t:ty, $u:ty) => {
+        forward_ref_op_assign!(impl const $imp, $method for $t, $u,
+                #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]);
+    };
+    // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
+    (impl const $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
+        #[$attr]
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const $imp<&$u> for $t {
+            #[inline]
+            fn $method(&mut self, other: &$u) {
+                $imp::$method(self, *other);
+            }
+        }
+    };
     (impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
         #[$attr]
         impl $imp<&$u> for $t {
index 1aeb83931e5aa52fa90a53673ade1958fc01bd7e..91230c027c2d2f6e91031b1af3c397e01c1a00dd 100644 (file)
@@ -2252,7 +2252,6 @@ pub unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
 /// or have any other observable side-effects, the behavior is undefined.
 ///
 /// [referential transparency]: https://en.wikipedia.org/wiki/Referential_transparency
-#[cfg(not(bootstrap))]
 #[unstable(
     feature = "const_eval_select",
     issue = "none",
@@ -2273,7 +2272,6 @@ pub unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
     called_at_rt.call_once(arg)
 }
 
-#[cfg(not(bootstrap))]
 #[unstable(
     feature = "const_eval_select",
     issue = "none",
index 2b7287a413376bf53e2796cc8b25b0dcb1a8722a..4b89bc363268dd82f99c90233ca4e88dbc48f072 100644 (file)
@@ -427,13 +427,9 @@ unsafe fn as_inner(&mut self) -> &mut A::Source {
     }
 }
 
+// Since SourceIter forwards the left hand side we do the same here
 #[unstable(issue = "none", feature = "inplace_iteration")]
-// Limited to Item: Copy since interaction between Zip's use of TrustedRandomAccess
-// and Drop implementation of the source is unclear.
-//
-// An additional method returning the number of times the source has been logically advanced
-// (without calling next()) would be needed to properly drop the remainder of the source.
-unsafe impl<A: InPlaceIterable, B: Iterator> InPlaceIterable for Zip<A, B> where A::Item: Copy {}
+unsafe impl<A: InPlaceIterable, B: Iterator> InPlaceIterable for Zip<A, B> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A: Debug, B: Debug> Debug for Zip<A, B> {
index a7d4646f5c5973e63c291142191a519782b2eb38..7abe01d17c90bd46668d87fcb437f8d35b113a25 100644 (file)
@@ -25,6 +25,7 @@ pub const fn empty<T>() -> Empty<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>);
 
index f53d6cac7ed98221782ae68c1741c48f1664cdb4..d957a7527cf58d7902bed1da9465935277de49d4 100644 (file)
@@ -2837,12 +2837,12 @@ fn rev(self) -> Rev<Self>
     /// Basic usage:
     ///
     /// ```
-    /// let a = [(1, 2), (3, 4)];
+    /// let a = [(1, 2), (3, 4), (5, 6)];
     ///
     /// let (left, right): (Vec<_>, Vec<_>) = a.iter().cloned().unzip();
     ///
-    /// assert_eq!(left, [1, 3]);
-    /// assert_eq!(right, [2, 4]);
+    /// assert_eq!(left, [1, 3, 5]);
+    /// assert_eq!(right, [2, 4, 6]);
     ///
     /// // you can also unzip multiple nested tuples at once
     /// let a = [(1, (2, 3)), (4, (5, 6))];
index d109141216aefb90a498acf146e4e9b25fe04cf6..2b8a5f3cbf34528912eb9f0c98f81bf302909824 100644 (file)
@@ -74,7 +74,7 @@ fn eq(&self, other: &Self) -> bool {
 impl<T: Eq> Eq for OnceCell<T> {}
 
 #[unstable(feature = "once_cell", issue = "74465")]
-impl<T> From<T> for OnceCell<T> {
+impl<T> const From<T> for OnceCell<T> {
     fn from(value: T) -> Self {
         OnceCell { inner: UnsafeCell::new(Some(value)) }
     }
index 13b80c05dbb30eb756a541450055caf7c78a656f..5f44087cabbbc7e5eec8cc57eacca8543280c306 100644 (file)
 #![feature(const_caller_location)]
 #![feature(const_cell_into_inner)]
 #![feature(const_discriminant)]
+#![cfg_attr(not(bootstrap), feature(const_eval_select))]
 #![feature(const_float_bits_conv)]
 #![feature(const_float_classify)]
+#![feature(const_fmt_arguments_new)]
 #![feature(const_heap)]
 #![feature(const_inherent_unchecked_arith)]
 #![feature(const_int_unchecked_arith)]
 #![feature(const_likely)]
 #![feature(const_maybe_uninit_as_ptr)]
 #![feature(const_maybe_uninit_assume_init)]
+#![feature(const_num_from_num)]
+#![feature(const_ops)]
 #![feature(const_option)]
 #![feature(const_pin)]
 #![feature(const_replace)]
 #![feature(ptr_metadata)]
 #![feature(slice_ptr_get)]
 #![feature(variant_count)]
+#![feature(const_array_from_ref)]
+#![feature(const_slice_from_ref)]
 //
 // Language features:
 #![feature(abi_unadjusted)]
 #![feature(const_fn_trait_bound)]
 #![feature(const_impl_trait)]
 #![feature(const_mut_refs)]
-#![cfg_attr(bootstrap, feature(const_panic))]
 #![feature(const_precise_live_drops)]
 #![feature(const_raw_ptr_deref)]
 #![feature(const_refs_to_cell)]
 #![feature(doc_notable_trait)]
 #![feature(doc_primitive)]
 #![feature(exhaustive_patterns)]
-#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))]
+#![feature(doc_cfg_hide)]
 #![feature(extern_types)]
 #![feature(fundamental)]
 #![feature(if_let_guard)]
 #![feature(llvm_asm)]
 #![feature(min_specialization)]
 #![feature(mixed_integer_ops)]
-#![cfg_attr(not(bootstrap), feature(must_not_suspend))]
+#![feature(must_not_suspend)]
 #![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(no_core)]
index e5c3fafe5f1f0a1b097eecc34af57f8ee92430d9..37446bafacb240740873234b3f51dce261457b67 100644 (file)
@@ -30,8 +30,7 @@
 /// [arc]: ../../std/sync/struct.Arc.html
 /// [ub]: ../../reference/behavior-considered-undefined.html
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(all(not(test), bootstrap), rustc_diagnostic_item = "send_trait")]
-#[cfg_attr(all(not(test), not(bootstrap)), rustc_diagnostic_item = "Send")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Send")]
 #[rustc_on_unimplemented(
     message = "`{Self}` cannot be sent between threads safely",
     label = "`{Self}` cannot be sent between threads safely"
index 894ae10e1b4bae80af9b05996d8e6aa04e10c2c2..7d005666a74a6514e32bd7b55e15e00f87236c74 100644 (file)
@@ -296,6 +296,7 @@ pub fn forget_unsized<T: ?Sized>(t: T) {
 ///
 /// [alignment]: align_of
 #[inline(always)]
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
 #[rustc_const_stable(feature = "const_size_of", since = "1.24.0")]
@@ -324,6 +325,7 @@ pub const fn size_of<T>() -> usize {
 /// assert_eq!(13, mem::size_of_val(y));
 /// ```
 #[inline]
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "mem_size_of_val")]
@@ -373,6 +375,7 @@ pub const fn size_of_val<T: ?Sized>(val: &T) -> usize {
 /// assert_eq!(13, unsafe { mem::size_of_val_raw(y) });
 /// ```
 #[inline]
+#[must_use]
 #[unstable(feature = "layout_for_ptr", issue = "69835")]
 #[rustc_const_unstable(feature = "const_size_of_val_raw", issue = "46571")]
 pub const unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize {
@@ -397,6 +400,7 @@ pub const fn size_of_val<T: ?Sized>(val: &T) -> usize {
 /// assert_eq!(4, mem::min_align_of::<i32>());
 /// ```
 #[inline]
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
 pub fn min_align_of<T>() -> usize {
@@ -418,6 +422,7 @@ pub fn min_align_of<T>() -> usize {
 /// assert_eq!(4, mem::min_align_of_val(&5i32));
 /// ```
 #[inline]
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_deprecated(reason = "use `align_of_val` instead", since = "1.2.0")]
 pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
@@ -441,6 +446,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
 /// assert_eq!(4, mem::align_of::<i32>());
 /// ```
 #[inline(always)]
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
 #[rustc_const_stable(feature = "const_align_of", since = "1.24.0")]
@@ -462,6 +468,7 @@ pub const fn align_of<T>() -> usize {
 /// assert_eq!(4, mem::align_of_val(&5i32));
 /// ```
 #[inline]
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")]
 #[allow(deprecated)]
@@ -507,6 +514,7 @@ pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
 /// assert_eq!(4, unsafe { mem::align_of_val_raw(&5i32) });
 /// ```
 #[inline]
+#[must_use]
 #[unstable(feature = "layout_for_ptr", issue = "69835")]
 #[rustc_const_unstable(feature = "const_align_of_val_raw", issue = "46571")]
 pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
@@ -571,6 +579,7 @@ pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
 /// }
 /// ```
 #[inline]
+#[must_use]
 #[stable(feature = "needs_drop", since = "1.21.0")]
 #[rustc_const_stable(feature = "const_needs_drop", since = "1.36.0")]
 #[rustc_diagnostic_item = "needs_drop"]
@@ -618,6 +627,7 @@ pub const fn needs_drop<T>() -> bool {
 /// let _y: fn() = unsafe { mem::zeroed() }; // And again!
 /// ```
 #[inline(always)]
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated_in_future)]
 #[allow(deprecated)]
@@ -653,6 +663,7 @@ pub unsafe fn zeroed<T>() -> T {
 /// [assume_init]: MaybeUninit::assume_init
 /// [inv]: MaybeUninit#initialization-invariant
 #[inline(always)]
+#[must_use]
 #[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated_in_future)]
@@ -938,6 +949,7 @@ pub fn drop<T>(_x: T) {}
 /// assert_eq!(foo_array, [10]);
 /// ```
 #[inline]
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")]
 pub const unsafe fn transmute_copy<T, U>(src: &T) -> U {
@@ -1051,6 +1063,7 @@ pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
 /// assert_eq!(mem::variant_count::<Result<!, !>>(), 2);
 /// ```
 #[inline(always)]
+#[must_use]
 #[unstable(feature = "variant_count", issue = "73662")]
 #[rustc_const_unstable(feature = "variant_count", issue = "73662")]
 #[rustc_diagnostic_item = "mem_variant_count"]
index cdeba9c0792738be5fb55ebe76cf8f9f604172f5..8a9ecbe98dff604a3bc158005236aa66e8dda68e 100644 (file)
@@ -29,14 +29,15 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 #[stable(feature = "try_from", since = "1.34.0")]
-impl From<Infallible> for TryFromIntError {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<Infallible> for TryFromIntError {
     fn from(x: Infallible) -> TryFromIntError {
         match x {}
     }
 }
 
 #[unstable(feature = "never_type", issue = "35121")]
-impl From<!> for TryFromIntError {
+impl const From<!> for TryFromIntError {
     fn from(never: !) -> TryFromIntError {
         // Match rather than coerce to make sure that code like
         // `From<Infallible> for TryFromIntError` above will keep working
@@ -114,6 +115,7 @@ pub enum IntErrorKind {
 
 impl ParseIntError {
     /// Outputs the detailed cause of parsing an integer failing.
+    #[must_use]
     #[stable(feature = "int_error_matching", since = "1.55.0")]
     pub fn kind(&self) -> &IntErrorKind {
         &self.kind
index ad8106df198da3005c3b4e0692aef6e259b86213..905b0c4245801e87c4be00d2684ab3f51cf34564 100644 (file)
@@ -449,7 +449,7 @@ pub const fn is_nan(self) -> bool {
     // private use internally.
     #[inline]
     #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
-    const fn abs_private(self) -> f32 {
+    pub(crate) const fn abs_private(self) -> f32 {
         f32::from_bits(self.to_bits() & 0x7fff_ffff)
     }
 
@@ -980,6 +980,7 @@ pub const fn from_bits(v: u32) -> Self {
     /// #     .all(|(a, b)| a.to_bits() == b.to_bits()))
     /// ```
     #[unstable(feature = "total_cmp", issue = "72599")]
+    #[must_use]
     #[inline]
     pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
         let mut left = self.to_bits() as i32;
index 6a48101e04fdac695166d174e2484cbc73d60946..112a239a145f6ea374c8c2365157364b512dc3a0 100644 (file)
@@ -448,7 +448,7 @@ pub const fn is_nan(self) -> bool {
     // private use internally.
     #[inline]
     #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
-    const fn abs_private(self) -> f64 {
+    pub(crate) const fn abs_private(self) -> f64 {
         f64::from_bits(self.to_bits() & 0x7fff_ffff_ffff_ffff)
     }
 
@@ -996,6 +996,7 @@ pub const fn from_bits(v: u64) -> Self {
     /// #     .all(|(a, b)| a.to_bits() == b.to_bits()))
     /// ```
     #[unstable(feature = "total_cmp", issue = "72599")]
+    #[must_use]
     #[inline]
     pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
         let mut left = self.to_bits() as i64;
index 8cff266642fef674f715e6f8f6cafd99df4dac92..578288bda259545d199e7586609855d232ff997d 100644 (file)
@@ -31,10 +31,8 @@ pub fn len(&self) -> usize {
                     } else {
                         3
                     }
-                } else if v < 10_000 {
-                    4
                 } else {
-                    5
+                    if v < 10_000 { 4 } else { 5 }
                 }
             }
             Part::Copy(buf) => buf.len(),
index 0bdc933013791b2c017ae20a4f0c3f48b61b0f4d..052e1a21b32cbd0379424aae6672ac6bed183856 100644 (file)
@@ -608,8 +608,7 @@ pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
                       without modifying the original"]
         #[inline]
         pub const fn checked_div(self, rhs: Self) -> Option<Self> {
-            // Using `&` helps LLVM see that it is the same check made in division.
-            if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
+            if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
                 None
             } else {
                 // SAFETY: div by zero and by INT_MIN have been checked above
@@ -662,8 +661,7 @@ pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
                       without modifying the original"]
         #[inline]
         pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
-            // Using `&` helps LLVM see that it is the same check made in division.
-            if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
+            if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
                 None
             } else {
                 // SAFETY: div by zero and by INT_MIN have been checked above
@@ -1055,8 +1053,6 @@ pub const fn saturating_mul(self, rhs: Self) -> Self {
         /// Basic usage:
         ///
         /// ```
-        /// #![feature(saturating_div)]
-        ///
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".saturating_div(2), 2);")]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_div(-1), ", stringify!($SelfT), "::MIN + 1);")]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_div(-1), ", stringify!($SelfT), "::MAX);")]
@@ -1064,13 +1060,10 @@ pub const fn saturating_mul(self, rhs: Self) -> Self {
         /// ```
         ///
         /// ```should_panic
-        /// #![feature(saturating_div)]
-        ///
         #[doc = concat!("let _ = 1", stringify!($SelfT), ".saturating_div(0);")]
         ///
         /// ```
-        #[unstable(feature = "saturating_div", issue = "87920")]
-        #[rustc_const_unstable(feature = "saturating_div", issue = "87920")]
+        #[stable(feature = "saturating_div", since = "1.58.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
index 18ebf1cbb1063e51fe3a9970612054d075f2f390..0c00db5fdf37aa38142116eeb970919bb320fda3 100644 (file)
@@ -94,7 +94,13 @@ macro_rules! usize_isize_from_xe_bytes_doc {
 }
 
 macro_rules! widening_impl {
-    ($SelfT:ty, $WideT:ty, $BITS:literal) => {
+    ($SelfT:ty, $WideT:ty, $BITS:literal, unsigned) => {
+        widening_impl!($SelfT, $WideT, $BITS, "");
+    };
+    ($SelfT:ty, $WideT:ty, $BITS:literal, signed) => {
+        widening_impl!($SelfT, $WideT, $BITS, "# //");
+    };
+    ($SelfT:ty, $WideT:ty, $BITS:literal, $AdaptiveTestPrefix:literal) => {
         /// Calculates the complete product `self * rhs` without the possibility to overflow.
         ///
         /// This returns the low-order (wrapping) bits and the high-order (overflow) bits
@@ -148,6 +154,33 @@ pub const fn widening_mul(self, rhs: Self) -> (Self, Self) {
         /// assert_eq!(5u32.carrying_mul(2, 10), (20, 0));
         /// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2));
         /// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2));
+        #[doc = concat!($AdaptiveTestPrefix, "assert_eq!(",
+            stringify!($SelfT), "::MAX.carrying_mul(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ",
+            "(0, ", stringify!($SelfT), "::MAX));"
+        )]
+        /// ```
+        ///
+        /// If `carry` is zero, this is similar to [`overflowing_mul`](Self::overflowing_mul),
+        /// except that it gives the value of the overflow instead of just whether one happened:
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        /// let r = u8::carrying_mul(7, 13, 0);
+        /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(7, 13));
+        /// let r = u8::carrying_mul(13, 42, 0);
+        /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(13, 42));
+        /// ```
+        ///
+        /// The value of the first field in the returned tuple matches what you'd get
+        /// by combining the [`wrapping_mul`](Self::wrapping_mul) and
+        /// [`wrapping_add`](Self::wrapping_add) methods:
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        /// assert_eq!(
+        ///     789_u16.carrying_mul(456, 123).0,
+        ///     789_u16.wrapping_mul(456).wrapping_add(123),
+        /// );
         /// ```
         #[unstable(feature = "bigint_helper_methods", issue = "85532")]
         #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")]
@@ -168,33 +201,33 @@ pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) {
 
 #[lang = "i8"]
 impl i8 {
-    widening_impl! { i8, i16, 8 }
     int_impl! { i8, i8, u8, 8, 7, -128, 127, 2, "-0x7e", "0xa", "0x12", "0x12", "0x48",
     "[0x12]", "[0x12]", "", "" }
+    widening_impl! { i8, i16, 8, signed }
 }
 
 #[lang = "i16"]
 impl i16 {
-    widening_impl! { i16, i32, 16 }
     int_impl! { i16, i16, u16, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412",
     "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
+    widening_impl! { i16, i32, 16, signed }
 }
 
 #[lang = "i32"]
 impl i32 {
-    widening_impl! { i32, i64, 32 }
     int_impl! { i32, i32, u32, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
     "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78]", "", "" }
+    widening_impl! { i32, i64, 32, signed }
 }
 
 #[lang = "i64"]
 impl i64 {
-    widening_impl! { i64, i128, 64 }
     int_impl! { i64, i64, u64, 64, 63, -9223372036854775808, 9223372036854775807, 12,
     "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
     "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" }
+    widening_impl! { i64, i128, 64, signed }
 }
 
 #[lang = "i128"]
@@ -212,31 +245,31 @@ impl i128 {
 #[cfg(target_pointer_width = "16")]
 #[lang = "isize"]
 impl isize {
-    widening_impl! { isize, i32, 16 }
     int_impl! { isize, i16, usize, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234",
     "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+    widening_impl! { isize, i32, 16, signed }
 }
 
 #[cfg(target_pointer_width = "32")]
 #[lang = "isize"]
 impl isize {
-    widening_impl! { isize, i64, 32 }
     int_impl! { isize, i32, usize, 32, 31, -2147483648, 2147483647, 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! { isize, i64, 32, signed }
 }
 
 #[cfg(target_pointer_width = "64")]
 #[lang = "isize"]
 impl isize {
-    widening_impl! { isize, i128, 64 }
     int_impl! { isize, i64, usize, 64, 63, -9223372036854775808, 9223372036854775807,
     12, "0xaa00000000006e1", "0x6e10aa",  "0x1234567890123456", "0x5634129078563412",
-     "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
-     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
-     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+    "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
+    "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
+    usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+    widening_impl! { isize, i128, 64, signed }
 }
 
 /// If 6th bit set ascii is upper case.
@@ -244,9 +277,9 @@ impl isize {
 
 #[lang = "u8"]
 impl u8 {
-    widening_impl! { u8, u16, 8 }
     uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
     "[0x12]", "", "" }
+    widening_impl! { u8, u16, 8, unsigned }
 
     /// Checks if the value is within the ASCII range.
     ///
@@ -793,26 +826,26 @@ pub fn escape_ascii(&self) -> ascii::EscapeDefault {
 
 #[lang = "u16"]
 impl u16 {
-    widening_impl! { u16, u32, 16 }
     uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
     "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
+    widening_impl! { u16, u32, 16, unsigned }
 }
 
 #[lang = "u32"]
 impl u32 {
-    widening_impl! { u32, u64, 32 }
     uint_impl! { u32, u32, i32, 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 {
-    widening_impl! { u64, u128, 64 }
     uint_impl! { u64, u64, i64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
     "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
     "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
     "", ""}
+    widening_impl! { u64, u128, 64, unsigned }
 }
 
 #[lang = "u128"]
@@ -830,29 +863,29 @@ impl u128 {
 #[cfg(target_pointer_width = "16")]
 #[lang = "usize"]
 impl usize {
-    widening_impl! { usize, u32, 16 }
     uint_impl! { usize, u16, isize, 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 }
 }
 #[cfg(target_pointer_width = "32")]
 #[lang = "usize"]
 impl usize {
-    widening_impl! { usize, u64, 32 }
     uint_impl! { usize, u32, isize, 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 }
 }
 
 #[cfg(target_pointer_width = "64")]
 #[lang = "usize"]
 impl usize {
-    widening_impl! { usize, u128, 64 }
     uint_impl! { usize, u64, isize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
     "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
     "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
-     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
+    "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+    widening_impl! { usize, u128, 64, unsigned }
 }
 
 /// A classification of floating point numbers.
index 89fd9fbaf455d6b3f2cfc3f0ea8bd32e7d3a68cf..7708094e1fceab656457dbd297339a35f914319e 100644 (file)
@@ -82,7 +82,8 @@ pub const fn get(self) -> $Int {
             }
 
             #[stable(feature = "from_nonzero", since = "1.31.0")]
-            impl From<$Ty> for $Int {
+            #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
+            impl const From<$Ty> for $Int {
                 #[doc = concat!("Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`")]
                 #[inline]
                 fn from(nonzero: $Ty) -> Self {
@@ -91,7 +92,8 @@ fn from(nonzero: $Ty) -> Self {
             }
 
             #[stable(feature = "nonzero_bitor", since = "1.45.0")]
-            impl BitOr for $Ty {
+            #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+            impl const BitOr for $Ty {
                 type Output = Self;
                 #[inline]
                 fn bitor(self, rhs: Self) -> Self::Output {
@@ -102,7 +104,8 @@ fn bitor(self, rhs: Self) -> Self::Output {
             }
 
             #[stable(feature = "nonzero_bitor", since = "1.45.0")]
-            impl BitOr<$Int> for $Ty {
+            #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+            impl const BitOr<$Int> for $Ty {
                 type Output = Self;
                 #[inline]
                 fn bitor(self, rhs: $Int) -> Self::Output {
@@ -114,7 +117,8 @@ fn bitor(self, rhs: $Int) -> Self::Output {
             }
 
             #[stable(feature = "nonzero_bitor", since = "1.45.0")]
-            impl BitOr<$Ty> for $Int {
+            #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+            impl const BitOr<$Ty> for $Int {
                 type Output = $Ty;
                 #[inline]
                 fn bitor(self, rhs: $Ty) -> Self::Output {
@@ -126,7 +130,8 @@ fn bitor(self, rhs: $Ty) -> Self::Output {
             }
 
             #[stable(feature = "nonzero_bitor", since = "1.45.0")]
-            impl BitOrAssign for $Ty {
+            #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+            impl const BitOrAssign for $Ty {
                 #[inline]
                 fn bitor_assign(&mut self, rhs: Self) {
                     *self = *self | rhs;
@@ -134,7 +139,8 @@ fn bitor_assign(&mut self, rhs: Self) {
             }
 
             #[stable(feature = "nonzero_bitor", since = "1.45.0")]
-            impl BitOrAssign<$Int> for $Ty {
+            #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+            impl const BitOrAssign<$Int> for $Ty {
                 #[inline]
                 fn bitor_assign(&mut self, rhs: $Int) {
                     *self = *self | rhs;
@@ -256,7 +262,8 @@ macro_rules! nonzero_integers_div {
     ( $( $Ty: ident($Int: ty); )+ ) => {
         $(
             #[stable(feature = "nonzero_div", since = "1.51.0")]
-            impl Div<$Ty> for $Int {
+            #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+            impl const Div<$Ty> for $Int {
                 type Output = $Int;
                 /// This operation rounds towards zero,
                 /// truncating any fractional part of the exact result, and cannot panic.
@@ -269,7 +276,8 @@ fn div(self, other: $Ty) -> $Int {
             }
 
             #[stable(feature = "nonzero_div", since = "1.51.0")]
-            impl Rem<$Ty> for $Int {
+            #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+            impl const Rem<$Ty> for $Int {
                 type Output = $Int;
                 /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic.
                 #[inline]
index c764f420e27399d3a343fb974ec8d94086efad98..ba81f3f9fd6a0158b00262d5dfb7ad168080f13b 100644 (file)
@@ -273,7 +273,7 @@ fn mul_assign(&mut self, other: Saturating<$t>) {
         /// Basic usage:
         ///
         /// ```
-        /// #![feature(saturating_int_impl, saturating_div)]
+        /// #![feature(saturating_int_impl)]
         /// use std::num::Saturating;
         ///
         #[doc = concat!("assert_eq!(Saturating(2", stringify!($t), "), Saturating(5", stringify!($t), ") / Saturating(2));")]
@@ -282,7 +282,7 @@ fn mul_assign(&mut self, other: Saturating<$t>) {
         /// ```
         ///
         /// ```should_panic
-        /// #![feature(saturating_int_impl, saturating_div)]
+        /// #![feature(saturating_int_impl)]
         /// use std::num::Saturating;
         ///
         #[doc = concat!("let _ = Saturating(0", stringify!($t), ") / Saturating(0);")]
index c3b2ecdb30f5b9c2fbc4365acea8ca80d34401fc..a15eabf7966d8ab2fd7cdc18ea7c6a535b7c7354 100644 (file)
@@ -1120,20 +1120,15 @@ pub const fn saturating_mul(self, rhs: Self) -> Self {
         /// Basic usage:
         ///
         /// ```
-        /// #![feature(saturating_div)]
-        ///
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".saturating_div(2), 2);")]
         ///
         /// ```
         ///
         /// ```should_panic
-        /// #![feature(saturating_div)]
-        ///
         #[doc = concat!("let _ = 1", stringify!($SelfT), ".saturating_div(0);")]
         ///
         /// ```
-        #[unstable(feature = "saturating_div", issue = "87920")]
-        #[rustc_const_unstable(feature = "saturating_div", issue = "87920")]
+        #[stable(feature = "saturating_div", since = "1.58.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1509,6 +1504,8 @@ pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
         /// additional bit of overflow. This allows for chaining together multiple additions
         /// to create "big integers" which represent larger values.
         ///
+        #[doc = concat!("This can be thought of as a ", stringify!($BITS), "-bit \"full adder\", in the electronics sense.")]
+        ///
         /// # Examples
         ///
         /// Basic usage
@@ -1518,7 +1515,20 @@ pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")]
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (0, true));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(0, true), (0, true));")]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (1, true));")]
+        #[doc = concat!("assert_eq!(",
+            stringify!($SelfT), "::MAX.carrying_add(", stringify!($SelfT), "::MAX, true), ",
+            "(", stringify!($SelfT), "::MAX, true));"
+        )]
+        /// ```
+        ///
+        /// If `carry` is false, this method is equivalent to [`overflowing_add`](Self::overflowing_add):
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        #[doc = concat!("assert_eq!(5_", stringify!($SelfT), ".carrying_add(2, false), 5_", stringify!($SelfT), ".overflowing_add(2));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), ", stringify!($SelfT), "::MAX.overflowing_add(1));")]
         /// ```
         #[unstable(feature = "bigint_helper_methods", issue = "85532")]
         #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
@@ -1530,7 +1540,7 @@ pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
             //   to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic
             let (a, b) = self.overflowing_add(rhs);
             let (c, d) = a.overflowing_add(carry as $SelfT);
-            (c, b | d)
+            (c, b || d)
         }
 
         /// Calculates `self` + `rhs` with a signed `rhs`
@@ -1611,7 +1621,7 @@ pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
             //   to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic
             let (a, b) = self.overflowing_sub(rhs);
             let (c, d) = a.overflowing_sub(borrow as $SelfT);
-            (c, b | d)
+            (c, b || d)
         }
 
         /// Computes the absolute difference between `self` and `other`.
index f387bd5b41cc453ef9cd956af7f5e65341ff06bc..a0e42c51e4517a8091baa59893d90752983cac9b 100644 (file)
@@ -87,7 +87,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 macro_rules! sh_impl_signed {
     ($t:ident, $f:ident) => {
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Shl<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Shl<$f> for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -99,20 +100,22 @@ fn shl(self, other: $f) -> Wrapping<$t> {
                 }
             }
         }
-        forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f,
+        forward_ref_binop! { impl const Shl, shl for Wrapping<$t>, $f,
         #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl ShlAssign<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const ShlAssign<$f> for Wrapping<$t> {
             #[inline]
             fn shl_assign(&mut self, other: $f) {
                 *self = *self << other;
             }
         }
-        forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f }
+        forward_ref_op_assign! { impl const ShlAssign, shl_assign for Wrapping<$t>, $f }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Shr<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Shr<$f> for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -124,24 +127,26 @@ fn shr(self, other: $f) -> Wrapping<$t> {
                 }
             }
         }
-        forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f,
+        forward_ref_binop! { impl const Shr, shr for Wrapping<$t>, $f,
         #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl ShrAssign<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const ShrAssign<$f> for Wrapping<$t> {
             #[inline]
             fn shr_assign(&mut self, other: $f) {
                 *self = *self >> other;
             }
         }
-        forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f }
+        forward_ref_op_assign! { impl const ShrAssign, shr_assign for Wrapping<$t>, $f }
     };
 }
 
 macro_rules! sh_impl_unsigned {
     ($t:ident, $f:ident) => {
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Shl<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Shl<$f> for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -149,20 +154,22 @@ fn shl(self, other: $f) -> Wrapping<$t> {
                 Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32))
             }
         }
-        forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f,
+        forward_ref_binop! { impl const Shl, shl for Wrapping<$t>, $f,
         #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl ShlAssign<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const ShlAssign<$f> for Wrapping<$t> {
             #[inline]
             fn shl_assign(&mut self, other: $f) {
                 *self = *self << other;
             }
         }
-        forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f }
+        forward_ref_op_assign! { impl const ShlAssign, shl_assign for Wrapping<$t>, $f }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Shr<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Shr<$f> for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -170,17 +177,18 @@ fn shr(self, other: $f) -> Wrapping<$t> {
                 Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32))
             }
         }
-        forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f,
+        forward_ref_binop! { impl const Shr, shr for Wrapping<$t>, $f,
         #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl ShrAssign<$f> for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const ShrAssign<$f> for Wrapping<$t> {
             #[inline]
             fn shr_assign(&mut self, other: $f) {
                 *self = *self >> other;
             }
         }
-        forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f }
+        forward_ref_op_assign! { impl const ShrAssign, shr_assign for Wrapping<$t>, $f }
     };
 }
 
@@ -209,7 +217,8 @@ macro_rules! sh_impl_all {
 macro_rules! wrapping_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Add for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Add for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -217,20 +226,22 @@ fn add(self, other: Wrapping<$t>) -> Wrapping<$t> {
                 Wrapping(self.0.wrapping_add(other.0))
             }
         }
-        forward_ref_binop! { impl Add, add for Wrapping<$t>, Wrapping<$t>,
+        forward_ref_binop! { impl const Add, add for Wrapping<$t>, Wrapping<$t>,
                 #[stable(feature = "wrapping_ref", since = "1.14.0")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl AddAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const AddAssign for Wrapping<$t> {
             #[inline]
             fn add_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self + other;
             }
         }
-        forward_ref_op_assign! { impl AddAssign, add_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl const AddAssign, add_assign for Wrapping<$t>, Wrapping<$t> }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Sub for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Sub for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -238,20 +249,22 @@ fn sub(self, other: Wrapping<$t>) -> Wrapping<$t> {
                 Wrapping(self.0.wrapping_sub(other.0))
             }
         }
-        forward_ref_binop! { impl Sub, sub for Wrapping<$t>, Wrapping<$t>,
+        forward_ref_binop! { impl const Sub, sub for Wrapping<$t>, Wrapping<$t>,
                 #[stable(feature = "wrapping_ref", since = "1.14.0")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl SubAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const SubAssign for Wrapping<$t> {
             #[inline]
             fn sub_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self - other;
             }
         }
-        forward_ref_op_assign! { impl SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl const SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t> }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Mul for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Mul for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -263,16 +276,18 @@ fn mul(self, other: Wrapping<$t>) -> Wrapping<$t> {
                 #[stable(feature = "wrapping_ref", since = "1.14.0")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl MulAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const MulAssign for Wrapping<$t> {
             #[inline]
             fn mul_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self * other;
             }
         }
-        forward_ref_op_assign! { impl MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl const MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t> }
 
         #[stable(feature = "wrapping_div", since = "1.3.0")]
-        impl Div for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Div for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -280,20 +295,22 @@ fn div(self, other: Wrapping<$t>) -> Wrapping<$t> {
                 Wrapping(self.0.wrapping_div(other.0))
             }
         }
-        forward_ref_binop! { impl Div, div for Wrapping<$t>, Wrapping<$t>,
+        forward_ref_binop! { impl const Div, div for Wrapping<$t>, Wrapping<$t>,
                 #[stable(feature = "wrapping_ref", since = "1.14.0")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl DivAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const DivAssign for Wrapping<$t> {
             #[inline]
             fn div_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self / other;
             }
         }
-        forward_ref_op_assign! { impl DivAssign, div_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl const DivAssign, div_assign for Wrapping<$t>, Wrapping<$t> }
 
         #[stable(feature = "wrapping_impls", since = "1.7.0")]
-        impl Rem for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Rem for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -301,20 +318,22 @@ fn rem(self, other: Wrapping<$t>) -> Wrapping<$t> {
                 Wrapping(self.0.wrapping_rem(other.0))
             }
         }
-        forward_ref_binop! { impl Rem, rem for Wrapping<$t>, Wrapping<$t>,
+        forward_ref_binop! { impl const Rem, rem for Wrapping<$t>, Wrapping<$t>,
                 #[stable(feature = "wrapping_ref", since = "1.14.0")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl RemAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const RemAssign for Wrapping<$t> {
             #[inline]
             fn rem_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self % other;
             }
         }
-        forward_ref_op_assign! { impl RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl const RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t> }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Not for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Not for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -322,11 +341,12 @@ fn not(self) -> Wrapping<$t> {
                 Wrapping(!self.0)
             }
         }
-        forward_ref_unop! { impl Not, not for Wrapping<$t>,
+        forward_ref_unop! { impl const Not, not for Wrapping<$t>,
                 #[stable(feature = "wrapping_ref", since = "1.14.0")] }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl BitXor for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitXor for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -334,20 +354,22 @@ fn bitxor(self, other: Wrapping<$t>) -> Wrapping<$t> {
                 Wrapping(self.0 ^ other.0)
             }
         }
-        forward_ref_binop! { impl BitXor, bitxor for Wrapping<$t>, Wrapping<$t>,
+        forward_ref_binop! { impl const BitXor, bitxor for Wrapping<$t>, Wrapping<$t>,
                 #[stable(feature = "wrapping_ref", since = "1.14.0")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl BitXorAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitXorAssign for Wrapping<$t> {
             #[inline]
             fn bitxor_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self ^ other;
             }
         }
-        forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t> }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl BitOr for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitOr for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -355,20 +377,22 @@ fn bitor(self, other: Wrapping<$t>) -> Wrapping<$t> {
                 Wrapping(self.0 | other.0)
             }
         }
-        forward_ref_binop! { impl BitOr, bitor for Wrapping<$t>, Wrapping<$t>,
+        forward_ref_binop! { impl const BitOr, bitor for Wrapping<$t>, Wrapping<$t>,
                 #[stable(feature = "wrapping_ref", since = "1.14.0")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl BitOrAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitOrAssign for Wrapping<$t> {
             #[inline]
             fn bitor_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self | other;
             }
         }
-        forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t> }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl BitAnd for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitAnd for Wrapping<$t> {
             type Output = Wrapping<$t>;
 
             #[inline]
@@ -376,27 +400,29 @@ fn bitand(self, other: Wrapping<$t>) -> Wrapping<$t> {
                 Wrapping(self.0 & other.0)
             }
         }
-        forward_ref_binop! { impl BitAnd, bitand for Wrapping<$t>, Wrapping<$t>,
+        forward_ref_binop! { impl const BitAnd, bitand for Wrapping<$t>, Wrapping<$t>,
                 #[stable(feature = "wrapping_ref", since = "1.14.0")] }
 
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl BitAndAssign for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitAndAssign for Wrapping<$t> {
             #[inline]
             fn bitand_assign(&mut self, other: Wrapping<$t>) {
                 *self = *self & other;
             }
         }
-        forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t> }
+        forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t> }
 
         #[stable(feature = "wrapping_neg", since = "1.10.0")]
-        impl Neg for Wrapping<$t> {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Neg for Wrapping<$t> {
             type Output = Self;
             #[inline]
             fn neg(self) -> Self {
                 Wrapping(0) - self
             }
         }
-        forward_ref_unop! { impl Neg, neg for Wrapping<$t>,
+        forward_ref_unop! { impl const Neg, neg for Wrapping<$t>,
                 #[stable(feature = "wrapping_ref", since = "1.14.0")] }
 
     )*)
index a0577b287ce24fa886e715298111b082e128f880..e954742938910cc4f36ea5f2432e7fe761a7a851 100644 (file)
@@ -92,7 +92,8 @@ pub trait Add<Rhs = Self> {
 macro_rules! add_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Add for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Add for $t {
             type Output = $t;
 
             #[inline]
@@ -100,7 +101,7 @@ impl Add for $t {
             fn add(self, other: $t) -> $t { self + other }
         }
 
-        forward_ref_binop! { impl Add, add for $t, $t }
+        forward_ref_binop! { impl const Add, add for $t, $t }
     )*)
 }
 
@@ -198,7 +199,8 @@ pub trait Sub<Rhs = Self> {
 macro_rules! sub_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Sub for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Sub for $t {
             type Output = $t;
 
             #[inline]
@@ -206,7 +208,7 @@ impl Sub for $t {
             fn sub(self, other: $t) -> $t { self - other }
         }
 
-        forward_ref_binop! { impl Sub, sub for $t, $t }
+        forward_ref_binop! { impl const Sub, sub for $t, $t }
     )*)
 }
 
@@ -326,7 +328,8 @@ pub trait Mul<Rhs = Self> {
 macro_rules! mul_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Mul for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Mul for $t {
             type Output = $t;
 
             #[inline]
@@ -334,7 +337,7 @@ impl Mul for $t {
             fn mul(self, other: $t) -> $t { self * other }
         }
 
-        forward_ref_binop! { impl Mul, mul for $t, $t }
+        forward_ref_binop! { impl const Mul, mul for $t, $t }
     )*)
 }
 
@@ -464,14 +467,15 @@ macro_rules! div_impl_integer {
         ///
         #[doc = $panic]
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Div for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Div for $t {
             type Output = $t;
 
             #[inline]
             fn div(self, other: $t) -> $t { self / other }
         }
 
-        forward_ref_binop! { impl Div, div for $t, $t }
+        forward_ref_binop! { impl const Div, div for $t, $t }
     )*)*)
 }
 
@@ -483,14 +487,15 @@ fn div(self, other: $t) -> $t { self / other }
 macro_rules! div_impl_float {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Div for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Div for $t {
             type Output = $t;
 
             #[inline]
             fn div(self, other: $t) -> $t { self / other }
         }
 
-        forward_ref_binop! { impl Div, div for $t, $t }
+        forward_ref_binop! { impl const Div, div for $t, $t }
     )*)
 }
 
@@ -564,14 +569,15 @@ macro_rules! rem_impl_integer {
         ///
         #[doc = $panic]
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Rem for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Rem for $t {
             type Output = $t;
 
             #[inline]
             fn rem(self, other: $t) -> $t { self % other }
         }
 
-        forward_ref_binop! { impl Rem, rem for $t, $t }
+        forward_ref_binop! { impl const Rem, rem for $t, $t }
     )*)*)
 }
 
@@ -598,14 +604,15 @@ macro_rules! rem_impl_float {
         /// assert_eq!(x % y, remainder);
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Rem for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Rem for $t {
             type Output = $t;
 
             #[inline]
             fn rem(self, other: $t) -> $t { self % other }
         }
 
-        forward_ref_binop! { impl Rem, rem for $t, $t }
+        forward_ref_binop! { impl const Rem, rem for $t, $t }
     )*)
 }
 
@@ -671,7 +678,8 @@ pub trait Neg {
 macro_rules! neg_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Neg for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Neg for $t {
             type Output = $t;
 
             #[inline]
@@ -679,7 +687,7 @@ impl Neg for $t {
             fn neg(self) -> $t { -self }
         }
 
-        forward_ref_unop! { impl Neg, neg for $t }
+        forward_ref_unop! { impl const Neg, neg for $t }
     )*)
 }
 
@@ -739,13 +747,14 @@ pub trait AddAssign<Rhs = Self> {
 macro_rules! add_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl AddAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const AddAssign for $t {
             #[inline]
             #[rustc_inherit_overflow_checks]
             fn add_assign(&mut self, other: $t) { *self += other }
         }
 
-        forward_ref_op_assign! { impl AddAssign, add_assign for $t, $t }
+        forward_ref_op_assign! { impl const AddAssign, add_assign for $t, $t }
     )+)
 }
 
@@ -805,13 +814,14 @@ pub trait SubAssign<Rhs = Self> {
 macro_rules! sub_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl SubAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const SubAssign for $t {
             #[inline]
             #[rustc_inherit_overflow_checks]
             fn sub_assign(&mut self, other: $t) { *self -= other }
         }
 
-        forward_ref_op_assign! { impl SubAssign, sub_assign for $t, $t }
+        forward_ref_op_assign! { impl const SubAssign, sub_assign for $t, $t }
     )+)
 }
 
@@ -862,13 +872,14 @@ pub trait MulAssign<Rhs = Self> {
 macro_rules! mul_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl MulAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const MulAssign for $t {
             #[inline]
             #[rustc_inherit_overflow_checks]
             fn mul_assign(&mut self, other: $t) { *self *= other }
         }
 
-        forward_ref_op_assign! { impl MulAssign, mul_assign for $t, $t }
+        forward_ref_op_assign! { impl const MulAssign, mul_assign for $t, $t }
     )+)
 }
 
@@ -919,12 +930,13 @@ pub trait DivAssign<Rhs = Self> {
 macro_rules! div_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl DivAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const DivAssign for $t {
             #[inline]
             fn div_assign(&mut self, other: $t) { *self /= other }
         }
 
-        forward_ref_op_assign! { impl DivAssign, div_assign for $t, $t }
+        forward_ref_op_assign! { impl const DivAssign, div_assign for $t, $t }
     )+)
 }
 
@@ -979,12 +991,13 @@ pub trait RemAssign<Rhs = Self> {
 macro_rules! rem_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl RemAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const RemAssign for $t {
             #[inline]
             fn rem_assign(&mut self, other: $t) { *self %= other }
         }
 
-        forward_ref_op_assign! { impl RemAssign, rem_assign for $t, $t }
+        forward_ref_op_assign! { impl const RemAssign, rem_assign for $t, $t }
     )+)
 }
 
index 92f45ac9e7ea9251c39e9cdd4d9cd1a6703cff16..255f6cb7933a244271100cc9cd556cf06e8938c8 100644 (file)
@@ -54,14 +54,15 @@ pub trait Not {
 macro_rules! not_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Not for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Not for $t {
             type Output = $t;
 
             #[inline]
             fn not(self) -> $t { !self }
         }
 
-        forward_ref_unop! { impl Not, not for $t }
+        forward_ref_unop! { impl const Not, not for $t }
     )*)
 }
 
@@ -154,14 +155,15 @@ pub trait BitAnd<Rhs = Self> {
 macro_rules! bitand_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl BitAnd for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitAnd for $t {
             type Output = $t;
 
             #[inline]
             fn bitand(self, rhs: $t) -> $t { self & rhs }
         }
 
-        forward_ref_binop! { impl BitAnd, bitand for $t, $t }
+        forward_ref_binop! { impl const BitAnd, bitand for $t, $t }
     )*)
 }
 
@@ -254,14 +256,15 @@ pub trait BitOr<Rhs = Self> {
 macro_rules! bitor_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl BitOr for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitOr for $t {
             type Output = $t;
 
             #[inline]
             fn bitor(self, rhs: $t) -> $t { self | rhs }
         }
 
-        forward_ref_binop! { impl BitOr, bitor for $t, $t }
+        forward_ref_binop! { impl const BitOr, bitor for $t, $t }
     )*)
 }
 
@@ -354,14 +357,15 @@ pub trait BitXor<Rhs = Self> {
 macro_rules! bitxor_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl BitXor for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitXor for $t {
             type Output = $t;
 
             #[inline]
             fn bitxor(self, other: $t) -> $t { self ^ other }
         }
 
-        forward_ref_binop! { impl BitXor, bitxor for $t, $t }
+        forward_ref_binop! { impl const BitXor, bitxor for $t, $t }
     )*)
 }
 
@@ -451,7 +455,8 @@ pub trait Shl<Rhs = Self> {
 macro_rules! shl_impl {
     ($t:ty, $f:ty) => {
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Shl<$f> for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Shl<$f> for $t {
             type Output = $t;
 
             #[inline]
@@ -461,7 +466,7 @@ fn shl(self, other: $f) -> $t {
             }
         }
 
-        forward_ref_binop! { impl Shl, shl for $t, $f }
+        forward_ref_binop! { impl const Shl, shl for $t, $f }
     };
 }
 
@@ -569,7 +574,8 @@ pub trait Shr<Rhs = Self> {
 macro_rules! shr_impl {
     ($t:ty, $f:ty) => {
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Shr<$f> for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const Shr<$f> for $t {
             type Output = $t;
 
             #[inline]
@@ -579,7 +585,7 @@ fn shr(self, other: $f) -> $t {
             }
         }
 
-        forward_ref_binop! { impl Shr, shr for $t, $f }
+        forward_ref_binop! { impl const Shr, shr for $t, $f }
     };
 }
 
@@ -704,12 +710,13 @@ pub trait BitAndAssign<Rhs = Self> {
 macro_rules! bitand_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl BitAndAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitAndAssign for $t {
             #[inline]
             fn bitand_assign(&mut self, other: $t) { *self &= other }
         }
 
-        forward_ref_op_assign! { impl BitAndAssign, bitand_assign for $t, $t }
+        forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for $t, $t }
     )+)
 }
 
@@ -775,12 +782,13 @@ pub trait BitOrAssign<Rhs = Self> {
 macro_rules! bitor_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl BitOrAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitOrAssign for $t {
             #[inline]
             fn bitor_assign(&mut self, other: $t) { *self |= other }
         }
 
-        forward_ref_op_assign! { impl BitOrAssign, bitor_assign for $t, $t }
+        forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for $t, $t }
     )+)
 }
 
@@ -846,12 +854,13 @@ pub trait BitXorAssign<Rhs = Self> {
 macro_rules! bitxor_assign_impl {
     ($($t:ty)+) => ($(
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl BitXorAssign for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitXorAssign for $t {
             #[inline]
             fn bitxor_assign(&mut self, other: $t) { *self ^= other }
         }
 
-        forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for $t, $t }
+        forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for $t, $t }
     )+)
 }
 
@@ -907,7 +916,8 @@ pub trait ShlAssign<Rhs = Self> {
 macro_rules! shl_assign_impl {
     ($t:ty, $f:ty) => {
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl ShlAssign<$f> for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const ShlAssign<$f> for $t {
             #[inline]
             #[rustc_inherit_overflow_checks]
             fn shl_assign(&mut self, other: $f) {
@@ -915,7 +925,7 @@ fn shl_assign(&mut self, other: $f) {
             }
         }
 
-        forward_ref_op_assign! { impl ShlAssign, shl_assign for $t, $f }
+        forward_ref_op_assign! { impl const ShlAssign, shl_assign for $t, $f }
     };
 }
 
@@ -989,7 +999,8 @@ pub trait ShrAssign<Rhs = Self> {
 macro_rules! shr_assign_impl {
     ($t:ty, $f:ty) => {
         #[stable(feature = "op_assign_traits", since = "1.8.0")]
-        impl ShrAssign<$f> for $t {
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const ShrAssign<$f> for $t {
             #[inline]
             #[rustc_inherit_overflow_checks]
             fn shr_assign(&mut self, other: $f) {
@@ -997,7 +1008,7 @@ fn shr_assign(&mut self, other: $f) {
             }
         }
 
-        forward_ref_op_assign! { impl ShrAssign, shr_assign for $t, $f }
+        forward_ref_op_assign! { impl const ShrAssign, shr_assign for $t, $f }
     };
 }
 
index cd2d57699c92c95e797b647c68480d0c60905377..b0c15898a1fd86a362db3c931ea5bf499a5e34d1 100644 (file)
@@ -7,6 +7,10 @@
 /// Having the enum makes it clearer -- no more wondering "wait, what did `false`
 /// mean again?" -- and allows including a value.
 ///
+/// Similar to [`Option`] and [`Result`], this enum can be used with the `?` operator
+/// to return immediately if the [`Break`] variant is present or otherwise continue normally
+/// with the value inside the [`Continue`] variant.
+///
 /// # Examples
 ///
 /// Early-exiting from [`Iterator::try_for_each`]:
@@ -24,7 +28,7 @@
 /// ```
 ///
 /// A basic tree traversal:
-/// ```no_run
+/// ```
 /// use std::ops::ControlFlow;
 ///
 /// pub struct TreeNode<T> {
 /// }
 ///
 /// impl<T> TreeNode<T> {
-///     pub fn traverse_inorder<B>(&self, mut f: impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
+///     pub fn traverse_inorder<B>(&self, f: &mut impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
 ///         if let Some(left) = &self.left {
-///             left.traverse_inorder(&mut f)?;
+///             left.traverse_inorder(f)?;
 ///         }
 ///         f(&self.value)?;
 ///         if let Some(right) = &self.right {
-///             right.traverse_inorder(&mut f)?;
+///             right.traverse_inorder(f)?;
 ///         }
 ///         ControlFlow::Continue(())
 ///     }
+///     fn leaf(value: T) -> Option<Box<TreeNode<T>>> {
+///         Some(Box::new(Self { value, left: None, right: None }))
+///     }
 /// }
+///
+/// let node = TreeNode {
+///     value: 0,
+///     left: TreeNode::leaf(1),
+///     right: Some(Box::new(TreeNode {
+///         value: -1,
+///         left: TreeNode::leaf(5),
+///         right: TreeNode::leaf(2),
+///     }))
+/// };
+/// let mut sum = 0;
+///
+/// let res = node.traverse_inorder(&mut |val| {
+///     if *val < 0 {
+///         ControlFlow::Break(*val)
+///     } else {
+///         sum += *val;
+///         ControlFlow::Continue(())
+///     }
+/// });
+/// assert_eq!(res, ControlFlow::Break(-1));
+/// assert_eq!(sum, 6);
 /// ```
+///
+/// [`Break`]: ControlFlow::Break
+/// [`Continue`]: ControlFlow::Continue
 #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
 #[derive(Debug, Clone, Copy, PartialEq)]
 pub enum ControlFlow<B, C = ()> {
index 347a346359f8cf5e9f25d9b58ab68b8bb554ce05..b74ba92c76eb6e459c5989c40e8b1388503f20fe 100644 (file)
@@ -743,6 +743,7 @@ impl<T: Clone> Bound<&T> {
     /// assert_eq!((1..12).start_bound(), Included(&1));
     /// assert_eq!((1..12).start_bound().cloned(), Included(1));
     /// ```
+    #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "bound_cloned", since = "1.55.0")]
     pub fn cloned(self) -> Bound<T> {
         match self {
index 401267f5613ee0c478ec470f4fa7496527004478..baf9948857bbe1e0c2d96eeaad6827e0727bebcd 100644 (file)
@@ -646,7 +646,8 @@ pub const fn as_ref(&self) -> Option<&T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn as_mut(&mut self) -> Option<&mut T> {
+    #[rustc_const_unstable(feature = "const_option", issue = "67441")]
+    pub const fn as_mut(&mut self) -> Option<&mut T> {
         match *self {
             Some(ref mut x) => Some(x),
             None => None,
@@ -799,19 +800,17 @@ pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
     /// # Examples
     ///
     /// ```
-    /// #![feature(option_result_unwrap_unchecked)]
     /// let x = Some("air");
     /// assert_eq!(unsafe { x.unwrap_unchecked() }, "air");
     /// ```
     ///
     /// ```no_run
-    /// #![feature(option_result_unwrap_unchecked)]
     /// let x: Option<&str> = None;
     /// assert_eq!(unsafe { x.unwrap_unchecked() }, "air"); // Undefined behavior!
     /// ```
     #[inline]
     #[track_caller]
-    #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")]
+    #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
     pub unsafe fn unwrap_unchecked(self) -> T {
         debug_assert!(self.is_some());
         match self {
@@ -1450,6 +1449,7 @@ impl<T: Copy> Option<&T> {
     /// let copied = opt_x.copied();
     /// assert_eq!(copied, Some(12));
     /// ```
+    #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "copied", since = "1.35.0")]
     #[rustc_const_unstable(feature = "const_option", issue = "67441")]
     pub const fn copied(self) -> Option<T> {
@@ -1722,7 +1722,8 @@ fn into_iter(self) -> IterMut<'a, T> {
 }
 
 #[stable(since = "1.12.0", feature = "option_from")]
-impl<T> From<T> for Option<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<T> for Option<T> {
     /// Moves `val` into a new [`Some`].
     ///
     /// # Examples
@@ -1738,7 +1739,8 @@ fn from(val: T) -> Option<T> {
 }
 
 #[stable(feature = "option_ref_from_ref_option", since = "1.30.0")]
-impl<'a, T> From<&'a Option<T>> for Option<&'a T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<'a, T> const From<&'a Option<T>> for Option<&'a T> {
     /// Converts from `&Option<T>` to `Option<&T>`.
     ///
     /// # Examples
@@ -1765,7 +1767,8 @@ fn from(o: &'a Option<T>) -> Option<&'a T> {
 }
 
 #[stable(feature = "option_ref_from_ref_option", since = "1.30.0")]
-impl<'a, T> From<&'a mut Option<T>> for Option<&'a mut T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<'a, T> const From<&'a mut Option<T>> for Option<&'a mut T> {
     /// Converts from `&mut Option<T>` to `Option<&mut T>`
     ///
     /// # Examples
@@ -2051,7 +2054,7 @@ fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
 }
 
 #[unstable(feature = "try_trait_v2", issue = "84277")]
-impl<T> ops::FromResidual for Option<T> {
+impl<T> const ops::FromResidual for Option<T> {
     #[inline]
     fn from_residual(residual: Option<convert::Infallible>) -> Self {
         match residual {
index a482414caaf9ae1c2149186bc6a849afe8452420..714e9b73c78a61f71e4c32e8c2a46dc51eeaa7d2 100644 (file)
@@ -79,6 +79,7 @@ impl<'a> Location<'a> {
     /// assert_ne!(this_location.line(), another_location.line());
     /// assert_ne!(this_location.column(), another_location.column());
     /// ```
+    #[must_use]
     #[stable(feature = "track_caller", since = "1.46.0")]
     #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")]
     #[track_caller]
@@ -119,6 +120,7 @@ pub const fn caller() -> &'static Location<'static> {
     ///
     /// panic!("Normal panic");
     /// ```
+    #[must_use]
     #[stable(feature = "panic_hooks", since = "1.10.0")]
     pub fn file(&self) -> &str {
         self.file
@@ -141,6 +143,7 @@ pub fn file(&self) -> &str {
     ///
     /// panic!("Normal panic");
     /// ```
+    #[must_use]
     #[stable(feature = "panic_hooks", since = "1.10.0")]
     pub fn line(&self) -> u32 {
         self.line
@@ -163,6 +166,7 @@ pub fn line(&self) -> u32 {
     ///
     /// panic!("Normal panic");
     /// ```
+    #[must_use]
     #[stable(feature = "panic_col", since = "1.25.0")]
     pub fn column(&self) -> u32 {
         self.col
index a52a0022e5d2bd7c2b02ba67d9d81e0597edc6e5..d8e421df5de5d321bd7e4d18d536091afa4e8c7a 100644 (file)
@@ -81,6 +81,7 @@ pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
     ///
     /// panic!("Normal panic");
     /// ```
+    #[must_use]
     #[stable(feature = "panic_hooks", since = "1.10.0")]
     pub fn payload(&self) -> &(dyn Any + Send) {
         self.payload
@@ -89,6 +90,7 @@ pub fn payload(&self) -> &(dyn Any + Send) {
     /// If the `panic!` macro from the `core` crate (not from `std`)
     /// was used with a formatting string and some additional arguments,
     /// returns that message ready to be used for example with [`fmt::write`]
+    #[must_use]
     #[unstable(feature = "panic_info_message", issue = "66745")]
     pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
         self.message
@@ -118,10 +120,11 @@ pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
     ///
     /// panic!("Normal panic");
     /// ```
+    #[must_use]
     #[stable(feature = "panic_hooks", since = "1.10.0")]
     pub fn location(&self) -> Option<&Location<'_>> {
         // NOTE: If this is changed to sometimes return None,
-        // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt.
+        // deal with that case in std::panicking::default_hook and core::panicking::panic_fmt.
         Some(&self.location)
     }
 }
index 6d3ec6ae8612a109987df7a91c59d319bdbe8fcd..29124c87e1bc5ff805c466cdd1ef874843efbbb6 100644 (file)
 // never inline unless panic_immediate_abort to avoid code
 // bloat at the call sites as much as possible
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[track_caller]
 #[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
-pub fn panic(expr: &'static str) -> ! {
-    if cfg!(feature = "panic_immediate_abort") {
-        super::intrinsics::abort()
-    }
-
+pub const fn panic(expr: &'static str) -> ! {
     // Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially
     // reduce size overhead. The format_args! macro uses str's Display trait to
     // write expr, which calls Formatter::pad, which must accommodate string
@@ -52,15 +49,16 @@ pub fn panic(expr: &'static str) -> ! {
 
 #[inline]
 #[track_caller]
-#[lang = "panic_str"] // needed for const-evaluated panics
-pub fn panic_str(expr: &str) -> ! {
-    panic_fmt(format_args!("{}", expr));
+#[lang = "panic_str"] // needed for `non-fmt-panics` lint
+pub const fn panic_str(expr: &str) -> ! {
+    panic_display(&expr);
 }
 
 #[inline]
 #[track_caller]
-#[cfg_attr(not(bootstrap), lang = "panic_display")] // needed for const-evaluated panics
-pub fn panic_display<T: fmt::Display>(x: &T) -> ! {
+#[lang = "panic_display"] // needed for const-evaluated panics
+#[rustc_do_not_const_check] // hooked by const-eval
+pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
     panic_fmt(format_args!("{}", *x));
 }
 
@@ -76,13 +74,21 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
     panic!("index out of bounds: the len is {} but the index is {}", len, index)
 }
 
-/// The underlying implementation of libcore's `panic!` macro when formatting is used.
+/// The entry point for panicking with a formatted message.
+///
+/// This is designed to reduce the amount of code required at the call
+/// site as much as possible (so that `panic!()` has as low an impact
+/// on (e.g.) the inlining of other functions as possible), by moving
+/// the actual formatting into this shared place.
 #[cold]
+// If panic_immediate_abort, inline the abort call,
+// otherwise avoid inlining because of it is cold path.
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[track_caller]
 #[lang = "panic_fmt"] // needed for const-evaluated panics
-pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
+#[rustc_do_not_const_check] // hooked by const-eval
+pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
         super::intrinsics::abort()
     }
index 34fc874ada09b7171017fcf43f9ec3b01462ab31..09fc6df5429759ce336bd08b7670b710d68dfce3 100644 (file)
@@ -705,6 +705,7 @@ pub unsafe fn map_unchecked<U, F>(self, func: F) -> Pin<&'a U>
     ///
     /// ["pinning projections"]: self#projections-and-structural-pinning
     #[inline(always)]
+    #[must_use]
     #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
     #[stable(feature = "pin", since = "1.33.0")]
     pub const fn get_ref(self) -> &'a T {
index 014170604ecaa573230c0de95f0d19709a694186..8ab72e6aeeafa3844d37b1c0e4abeee2b64c599f 100644 (file)
@@ -204,6 +204,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
 /// assert!(p.is_null());
 /// ```
 #[inline(always)]
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
 #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
@@ -223,6 +224,7 @@ pub const fn null<T>() -> *const T {
 /// assert!(p.is_null());
 /// ```
 #[inline(always)]
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
 #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
index ee93f00a7fb9be46c97b0b309774554fdbd34ca2..58110b068094381e9ac2e74130dab235c9608bf2 100644 (file)
@@ -83,6 +83,7 @@ impl<T: Sized> NonNull<T> {
     /// ```
     #[stable(feature = "nonnull", since = "1.25.0")]
     #[rustc_const_stable(feature = "const_nonnull_dangling", since = "1.36.0")]
+    #[must_use]
     #[inline]
     pub const fn dangling() -> Self {
         // SAFETY: mem::align_of() returns a non-zero usize which is then casted
@@ -423,6 +424,7 @@ impl<T> NonNull<[T]> {
     /// but `let slice = NonNull::from(&x[..]);` would be a better way to write code like this.)
     #[unstable(feature = "nonnull_slice_from_raw_parts", issue = "71941")]
     #[rustc_const_unstable(feature = "const_nonnull_slice_from_raw_parts", issue = "71941")]
+    #[must_use]
     #[inline]
     pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self {
         // SAFETY: `data` is a `NonNull` pointer which is necessarily non-null
@@ -447,6 +449,7 @@ pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self {
     /// ```
     #[unstable(feature = "slice_ptr_len", issue = "71146")]
     #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
+    #[must_use]
     #[inline]
     pub const fn len(self) -> usize {
         self.as_ptr().len()
@@ -698,7 +701,8 @@ fn hash<H: hash::Hasher>(&self, state: &mut H) {
 }
 
 #[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T: ?Sized> const From<Unique<T>> for NonNull<T> {
     #[inline]
     fn from(unique: Unique<T>) -> Self {
         // SAFETY: A Unique pointer cannot be null, so the conditions for
@@ -708,7 +712,8 @@ fn from(unique: Unique<T>) -> Self {
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> From<&mut T> for NonNull<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T: ?Sized> const From<&mut T> for NonNull<T> {
     #[inline]
     fn from(reference: &mut T) -> Self {
         // SAFETY: A mutable reference cannot be null.
@@ -717,7 +722,8 @@ fn from(reference: &mut T) -> Self {
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> From<&T> for NonNull<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T: ?Sized> const From<&T> for NonNull<T> {
     #[inline]
     fn from(reference: &T) -> Self {
         // SAFETY: A reference cannot be null, so the conditions for
index 5baceefb504a50d39a71216be6507d7137ba950f..d650a6f974b972c209f8f4b8f89746c39782ed5c 100644 (file)
@@ -68,6 +68,7 @@ impl<T: Sized> Unique<T> {
     /// a `T`, which means this must not be used as a "not yet initialized"
     /// sentinel value. Types that lazily allocate must track initialization by
     /// some other means.
+    #[must_use]
     #[inline]
     pub const fn dangling() -> Self {
         // SAFETY: mem::align_of() returns a valid, non-null pointer. The
@@ -176,7 +177,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 #[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> From<&mut T> for Unique<T> {
+impl<T: ?Sized> const From<&mut T> for Unique<T> {
     #[inline]
     fn from(reference: &mut T) -> Self {
         // SAFETY: A mutable reference cannot be null
index dda827900d9593b7c03ba1adf195e4edb9afc270..8fec2e928aae2505b8154d91c813dec46c5e627d 100644 (file)
@@ -729,7 +729,8 @@ pub const fn as_ref(&self) -> Result<&T, &E> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn as_mut(&mut self) -> Result<&mut T, &mut E> {
+    #[rustc_const_unstable(feature = "const_result", issue = "82814")]
+    pub const fn as_mut(&mut self) -> Result<&mut T, &mut E> {
         match *self {
             Ok(ref mut x) => Ok(x),
             Err(ref mut x) => Err(x),
@@ -1095,19 +1096,17 @@ pub fn unwrap_or_else<F: FnOnce(E) -> T>(self, op: F) -> T {
     /// # Examples
     ///
     /// ```
-    /// #![feature(option_result_unwrap_unchecked)]
     /// let x: Result<u32, &str> = Ok(2);
     /// assert_eq!(unsafe { x.unwrap_unchecked() }, 2);
     /// ```
     ///
     /// ```no_run
-    /// #![feature(option_result_unwrap_unchecked)]
     /// let x: Result<u32, &str> = Err("emergency failure");
     /// unsafe { x.unwrap_unchecked(); } // Undefined behavior!
     /// ```
     #[inline]
     #[track_caller]
-    #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")]
+    #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
     pub unsafe fn unwrap_unchecked(self) -> T {
         debug_assert!(self.is_ok());
         match self {
@@ -1129,19 +1128,17 @@ pub unsafe fn unwrap_unchecked(self) -> T {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(option_result_unwrap_unchecked)]
     /// let x: Result<u32, &str> = Ok(2);
     /// unsafe { x.unwrap_err_unchecked() }; // Undefined behavior!
     /// ```
     ///
     /// ```
-    /// #![feature(option_result_unwrap_unchecked)]
     /// let x: Result<u32, &str> = Err("emergency failure");
     /// assert_eq!(unsafe { x.unwrap_err_unchecked() }, "emergency failure");
     /// ```
     #[inline]
     #[track_caller]
-    #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")]
+    #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
     pub unsafe fn unwrap_err_unchecked(self) -> E {
         debug_assert!(self.is_err());
         match self {
index cbb5627cef9820b544ee98e3251d58efb65a29db..080256f493f5ffe95d2148d88f4f2ab384fb49c0 100644 (file)
@@ -11,6 +11,7 @@
 impl [u8] {
     /// Checks if all bytes in this slice are within the ASCII range.
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+    #[must_use]
     #[inline]
     pub fn is_ascii(&self) -> bool {
         is_ascii(self)
@@ -21,6 +22,7 @@ pub fn is_ascii(&self) -> bool {
     /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
     /// but without allocating and copying temporaries.
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+    #[must_use]
     #[inline]
     pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
         self.len() == other.len() && iter::zip(self, other).all(|(a, b)| a.eq_ignore_ascii_case(b))
index dbf97851b03e4e78294871ae94ba0d92f9836529..ad1d6b8b846a00433e422a92918e795522b2a0e9 100644 (file)
@@ -839,7 +839,6 @@ impl<T, P> FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> b
 /// [`rsplit`]: slice::rsplit
 /// [slices]: slice
 #[stable(feature = "slice_rsplit", since = "1.27.0")]
-#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`?
 pub struct RSplit<'a, T: 'a, P>
 where
     P: FnMut(&T) -> bool,
@@ -867,6 +866,17 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<T, P> Clone for RSplit<'_, T, P>
+where
+    P: Clone + FnMut(&T) -> bool,
+{
+    fn clone(&self) -> Self {
+        RSplit { inner: self.inner.clone() }
+    }
+}
+
 #[stable(feature = "slice_rsplit", since = "1.27.0")]
 impl<'a, T, P> Iterator for RSplit<'a, T, P>
 where
@@ -1714,6 +1724,7 @@ pub(super) fn new(slice: &'a [T], chunk_size: usize) -> Self {
     /// Returns the remainder of the original slice that is not going to be
     /// returned by the iterator. The returned slice has at most `chunk_size-1`
     /// elements.
+    #[must_use]
     #[stable(feature = "chunks_exact", since = "1.31.0")]
     pub fn remainder(&self) -> &'a [T] {
         self.rem
@@ -2143,6 +2154,7 @@ pub(super) fn new(slice: &'a [T]) -> Self {
     /// Returns the remainder of the original slice that is not going to be
     /// returned by the iterator. The returned slice has at most `N-1`
     /// elements.
+    #[must_use]
     #[unstable(feature = "array_chunks", issue = "74985")]
     pub fn remainder(&self) -> &'a [T] {
         self.rem
@@ -2718,6 +2730,7 @@ pub(super) fn new(slice: &'a [T], chunk_size: usize) -> Self {
     /// Returns the remainder of the original slice that is not going to be
     /// returned by the iterator. The returned slice has at most `chunk_size-1`
     /// elements.
+    #[must_use]
     #[stable(feature = "rchunks", since = "1.31.0")]
     pub fn remainder(&self) -> &'a [T] {
         self.rem
index 08077c700da69c0991f611e0ec5e7265f9c84fca..6da99055f2d5af887c03997e0f90e7880d561a89 100644 (file)
@@ -37,6 +37,7 @@ fn repeat_byte(b: u8) -> usize {
 }
 
 /// Returns the first index matching the byte `x` in `text`.
+#[must_use]
 #[inline]
 pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
     // Fast path for small slices
@@ -91,6 +92,7 @@ fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> {
 }
 
 /// Returns the last index matching the byte `x` in `text`.
+#[must_use]
 pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
     // Scan for a single byte value by reading two `usize` words at a time.
     //
index c0e0589d5edeed1ca238b30b35f9bd3e5bb3d585..65ed72cb0cdbe24ca0a2bf493ca1db779ac0cce3 100644 (file)
@@ -553,9 +553,9 @@ pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> {
     /// # Examples
     ///
     /// ```
-    /// let mut v = ["a", "b", "c", "d"];
-    /// v.swap(1, 3);
-    /// assert!(v == ["a", "d", "c", "b"]);
+    /// let mut v = ["a", "b", "c", "d", "e"];
+    /// v.swap(2, 4);
+    /// assert!(v == ["a", "b", "e", "d", "c"]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -1665,6 +1665,80 @@ pub unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [
         unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) }
     }
 
+    /// Divides one slice into an array and a remainder slice at an index.
+    ///
+    /// The array will contain all indices from `[0, N)` (excluding
+    /// the index `N` itself) and the slice will contain all
+    /// indices from `[N, len)` (excluding the index `len` itself).
+    ///
+    /// # Panics
+    ///
+    /// Panics if `N > len`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(split_array)]
+    ///
+    /// let v = &[1, 2, 3, 4, 5, 6][..];
+    ///
+    /// {
+    ///    let (left, right) = v.split_array_ref::<0>();
+    ///    assert_eq!(left, &[]);
+    ///    assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+    /// }
+    ///
+    /// {
+    ///     let (left, right) = v.split_array_ref::<2>();
+    ///     assert_eq!(left, &[1, 2]);
+    ///     assert_eq!(right, [3, 4, 5, 6]);
+    /// }
+    ///
+    /// {
+    ///     let (left, right) = v.split_array_ref::<6>();
+    ///     assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
+    ///     assert_eq!(right, []);
+    /// }
+    /// ```
+    #[unstable(feature = "split_array", reason = "new API", issue = "90091")]
+    #[inline]
+    pub fn split_array_ref<const N: usize>(&self) -> (&[T; N], &[T]) {
+        let (a, b) = self.split_at(N);
+        // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at)
+        unsafe { (&*(a.as_ptr() as *const [T; N]), b) }
+    }
+
+    /// Divides one mutable slice into an array and a remainder slice at an index.
+    ///
+    /// The array will contain all indices from `[0, N)` (excluding
+    /// the index `N` itself) and the slice will contain all
+    /// indices from `[N, len)` (excluding the index `len` itself).
+    ///
+    /// # Panics
+    ///
+    /// Panics if `N > len`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(split_array)]
+    ///
+    /// let mut v = &mut [1, 0, 3, 0, 5, 6][..];
+    /// let (left, right) = v.split_array_mut::<2>();
+    /// assert_eq!(left, &mut [1, 0]);
+    /// assert_eq!(right, [3, 0, 5, 6]);
+    /// left[1] = 2;
+    /// right[1] = 4;
+    /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+    /// ```
+    #[unstable(feature = "split_array", reason = "new API", issue = "90091")]
+    #[inline]
+    pub fn split_array_mut<const N: usize>(&mut self) -> (&mut [T; N], &mut [T]) {
+        let (a, b) = self.split_at_mut(N);
+        // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at_mut)
+        unsafe { (&mut *(a.as_mut_ptr() as *mut [T; N]), b) }
+    }
+
     /// Returns an iterator over subslices separated by elements that match
     /// `pred`. The matched element is not contained in the subslices.
     ///
@@ -2953,9 +3027,6 @@ pub fn fill_with<F>(&mut self, mut f: F)
     ///
     /// The length of `src` must be the same as `self`.
     ///
-    /// If `T` implements `Copy`, it can be more performant to use
-    /// [`copy_from_slice`].
-    ///
     /// # Panics
     ///
     /// This function will panic if the two slices have different lengths.
@@ -3005,6 +3076,7 @@ pub fn fill_with<F>(&mut self, mut f: F)
     /// [`copy_from_slice`]: slice::copy_from_slice
     /// [`split_at_mut`]: slice::split_at_mut
     #[stable(feature = "clone_from_slice", since = "1.7.0")]
+    #[track_caller]
     pub fn clone_from_slice(&mut self, src: &[T])
     where
         T: Clone,
@@ -3068,6 +3140,7 @@ pub fn clone_from_slice(&mut self, src: &[T])
     /// [`split_at_mut`]: slice::split_at_mut
     #[doc(alias = "memcpy")]
     #[stable(feature = "copy_from_slice", since = "1.9.0")]
+    #[track_caller]
     pub fn copy_from_slice(&mut self, src: &[T])
     where
         T: Copy,
@@ -3188,6 +3261,7 @@ pub fn copy_within<R: RangeBounds<usize>>(&mut self, src: R, dest: usize)
     ///
     /// [`split_at_mut`]: slice::split_at_mut
     #[stable(feature = "swap_with_slice", since = "1.27.0")]
+    #[track_caller]
     pub fn swap_with_slice(&mut self, other: &mut [T]) {
         assert!(self.len() == other.len(), "destination and source slices have different lengths");
         // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was
@@ -3510,6 +3584,7 @@ impl<T> CloneFromSpec<T> for [T]
 where
     T: Clone,
 {
+    #[track_caller]
     default fn spec_clone_from(&mut self, src: &[T]) {
         assert!(self.len() == src.len(), "destination and source slices have different lengths");
         // NOTE: We need to explicitly slice them to the same length
@@ -3527,6 +3602,7 @@ impl<T> CloneFromSpec<T> for [T]
 where
     T: Copy,
 {
+    #[track_caller]
     fn spec_clone_from(&mut self, src: &[T]) {
         self.copy_from_slice(src);
     }
index eda50dc287f6c943b822cd259c0e9c426d29078a..81bb16d54015e9551266e41068e1bb6ec63cd5a5 100644 (file)
@@ -1,8 +1,6 @@
 //! Free functions to create `&[T]` and `&mut [T]`.
 
 use crate::array;
-use crate::intrinsics::is_aligned_and_not_null;
-use crate::mem;
 use crate::ptr;
 
 /// Forms a slice from a pointer and a length.
 /// [`NonNull::dangling()`]: ptr::NonNull::dangling
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
-    debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
-    debug_assert!(
-        mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
-        "attempt to create slice covering at least half the address space"
-    );
+#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
+    debug_check_data_len(data, len);
+
     // SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
     unsafe { &*ptr::slice_from_raw_parts(data, len) }
 }
@@ -126,24 +122,58 @@ pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
 /// [`NonNull::dangling()`]: ptr::NonNull::dangling
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
-    debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
-    debug_assert!(
-        mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
-        "attempt to create slice covering at least half the address space"
-    );
+#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
+    debug_check_data_len(data as _, len);
+
     // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
     unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) }
 }
 
+// In debug builds checks that `data` pointer is aligned and non-null and that slice with given `len` would cover less than half the address space
+#[cfg(all(not(bootstrap), debug_assertions))]
+#[unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+const fn debug_check_data_len<T>(data: *const T, len: usize) {
+    fn rt_check<T>(data: *const T) {
+        use crate::intrinsics::is_aligned_and_not_null;
+
+        assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
+    }
+
+    const fn noop<T>(_: *const T) {}
+
+    // SAFETY:
+    //
+    // `rt_check` is just a debug assert to hint users that they are causing UB,
+    // it is not required for safety (the safety must be guatanteed by
+    // the `from_raw_parts[_mut]` caller).
+    //
+    // Since the checks are not required, we ignore them in CTFE as they can't
+    // be done there (alignment does not make much sense there).
+    unsafe {
+        crate::intrinsics::const_eval_select((data,), noop, rt_check);
+    }
+
+    assert!(
+        crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
+        "attempt to create slice covering at least half the address space"
+    );
+}
+
+#[cfg(not(all(not(bootstrap), debug_assertions)))]
+const fn debug_check_data_len<T>(_data: *const T, _len: usize) {}
+
 /// Converts a reference to T into a slice of length 1 (without copying).
 #[stable(feature = "from_ref", since = "1.28.0")]
-pub fn from_ref<T>(s: &T) -> &[T] {
+#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
+pub const fn from_ref<T>(s: &T) -> &[T] {
     array::from_ref(s)
 }
 
 /// Converts a reference to T into a slice of length 1 (without copying).
 #[stable(feature = "from_ref", since = "1.28.0")]
-pub fn from_mut<T>(s: &mut T) -> &mut [T] {
+#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
+pub const fn from_mut<T>(s: &mut T) -> &mut [T] {
     array::from_mut(s)
 }
index aa735a14cbd8fff3cab848c8a9340a0ee8243f3a..b6460d72fef32abc13f70a7a74581411131aaeaf 100644 (file)
@@ -72,6 +72,7 @@ impl Utf8Error {
     /// assert_eq!(1, error.valid_up_to());
     /// ```
     #[stable(feature = "utf8_error", since = "1.5.0")]
+    #[must_use]
     #[inline]
     pub fn valid_up_to(&self) -> usize {
         self.valid_up_to
@@ -93,6 +94,7 @@ pub fn valid_up_to(&self) -> usize {
     ///
     /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html
     #[stable(feature = "utf8_error_error_len", since = "1.20.0")]
+    #[must_use]
     #[inline]
     pub fn error_len(&self) -> Option<usize> {
         self.error_len.map(|len| len as usize)
index 94cb81e9d41a1f2543c7b1afab56eccb0692b85d..94a534c6e797e8a65357c4d50dadffe7b2848513 100644 (file)
@@ -27,6 +27,7 @@
 /// [`char`]: prim@char
 /// [`chars`]: str::chars
 #[derive(Clone)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Chars<'a> {
     pub(super) iter: slice::Iter<'a, u8>,
@@ -125,6 +126,7 @@ pub fn as_str(&self) -> &'a str {
 /// [`char`]: prim@char
 /// [`char_indices`]: str::char_indices
 #[derive(Clone, Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct CharIndices<'a> {
     pub(super) front_offset: usize,
@@ -211,6 +213,7 @@ pub fn as_str(&self) -> &'a str {
     /// assert_eq!(chars.next(), None);
     /// ```
     #[inline]
+    #[must_use]
     #[unstable(feature = "char_indices_offset", issue = "83871")]
     pub fn offset(&self) -> usize {
         self.front_offset
@@ -223,6 +226,7 @@ pub fn offset(&self) -> usize {
 /// See its documentation for more.
 ///
 /// [`bytes`]: str::bytes
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Clone, Debug)]
 pub struct Bytes<'a>(pub(super) Copied<slice::Iter<'a, u8>>);
@@ -1089,6 +1093,7 @@ fn next_back(&mut self) -> Option<&'a str>
 ///
 /// [`lines`]: str::lines
 #[stable(feature = "rust1", since = "1.0.0")]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[derive(Clone, Debug)]
 pub struct Lines<'a>(pub(super) Map<SplitTerminator<'a, char>, LinesAnyMap>);
 
@@ -1128,6 +1133,7 @@ impl FusedIterator for Lines<'_> {}
 /// [`lines_any`]: str::lines_any
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[derive(Clone, Debug)]
 #[allow(deprecated)]
 pub struct LinesAny<'a>(pub(super) Lines<'a>);
index d3c9d21c3c756c0acaec68fa99ad823787d71aef..6c21a5e802026b858073de5ebe0f2abdc27377cc 100644 (file)
@@ -29,6 +29,7 @@ pub fn chunks(&self) -> Utf8LossyChunksIter<'_> {
 }
 
 /// Iterator over lossy UTF-8 string
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[unstable(feature = "str_internals", issue = "none")]
 #[allow(missing_debug_implementations)]
 pub struct Utf8LossyChunksIter<'a> {
index 607a0179ff4b9a515ca69bd02522291ea1e42788..cd5ed35be79ba6769938b11624d94b99d941e7c8 100644 (file)
@@ -140,6 +140,7 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_str_len", since = "1.39.0")]
+    #[must_use]
     #[inline]
     pub const fn len(&self) -> usize {
         self.as_bytes().len()
@@ -158,9 +159,10 @@ pub const fn len(&self) -> usize {
     /// let s = "not empty";
     /// assert!(!s.is_empty());
     /// ```
-    #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_str_is_empty", since = "1.39.0")]
+    #[must_use]
+    #[inline]
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
@@ -498,6 +500,7 @@ pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked(begin..end)` instead")]
+    #[must_use]
     #[inline]
     pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
         // SAFETY: the caller must uphold the safety contract for `get_unchecked`;
@@ -570,6 +573,7 @@ pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut s
     /// assert_eq!(" Martin-Löf", last);
     /// ```
     #[inline]
+    #[must_use]
     #[stable(feature = "str_split_at", since = "1.4.0")]
     pub fn split_at(&self, mid: usize) -> (&str, &str) {
         // is_char_boundary checks that the index is in [0, .len()]
@@ -613,6 +617,7 @@ pub fn split_at(&self, mid: usize) -> (&str, &str) {
     /// assert_eq!("PER Martin-Löf", s);
     /// ```
     #[inline]
+    #[must_use]
     #[stable(feature = "str_split_at", since = "1.4.0")]
     pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
         // is_char_boundary checks that the index is in [0, .len()]
@@ -1663,7 +1668,7 @@ pub fn rmatches<'a, P>(&'a self, pat: P) -> RMatches<'a, P>
     /// If the pattern allows a reverse search but its results might differ
     /// from a forward search, the [`rmatch_indices`] method can be used.
     ///
-    /// [`rmatch_indices`]: str::match_indices
+    /// [`rmatch_indices`]: str::rmatch_indices
     ///
     /// # Examples
     ///
@@ -2255,6 +2260,7 @@ pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
     /// assert!(!non_ascii.is_ascii());
     /// ```
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+    #[must_use]
     #[inline]
     pub fn is_ascii(&self) -> bool {
         // We can treat each byte as character here: all multibyte characters
@@ -2276,6 +2282,7 @@ pub fn is_ascii(&self) -> bool {
     /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS"));
     /// ```
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+    #[must_use]
     #[inline]
     pub fn eq_ignore_ascii_case(&self, other: &str) -> bool {
         self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
index 55ac1aa765c1fabc0cdf6166a1d9dfabfb9c032e..031fb8e8b21fb8f853c859faf75b11ff801a438a 100644 (file)
@@ -22,6 +22,8 @@
 //! assert_eq!(s.find("you"), Some(4));
 //! // char pattern
 //! assert_eq!(s.find('n'), Some(2));
+//! // array of chars pattern
+//! assert_eq!(s.find(&['a', 'e', 'i', 'o', 'u']), Some(1));
 //! // slice of chars pattern
 //! assert_eq!(s.find(&['a', 'e', 'i', 'o', 'u'][..]), Some(1));
 //! // closure pattern
 /// assert_eq!("abaaa".find('b'), Some(1));
 /// assert_eq!("abaaa".find('c'), None);
 ///
+/// // &[char; N]
+/// assert_eq!("ab".find(&['b', 'a']), Some(0));
+/// assert_eq!("abaaa".find(&['a', 'z']), Some(0));
+/// assert_eq!("abaaa".find(&['c', 'd']), None);
+///
 /// // &[char]
 /// assert_eq!("ab".find(&['b', 'a'][..]), Some(0));
 /// assert_eq!("abaaa".find(&['a', 'z'][..]), Some(0));
@@ -601,6 +608,20 @@ fn matches(&mut self, c: char) -> bool {
     }
 }
 
+impl<const N: usize> MultiCharEq for [char; N] {
+    #[inline]
+    fn matches(&mut self, c: char) -> bool {
+        self.iter().any(|&m| m == c)
+    }
+}
+
+impl<const N: usize> MultiCharEq for &[char; N] {
+    #[inline]
+    fn matches(&mut self, c: char) -> bool {
+        self.iter().any(|&m| m == c)
+    }
+}
+
 impl MultiCharEq for &[char] {
     #[inline]
     fn matches(&mut self, c: char) -> bool {
@@ -752,6 +773,58 @@ fn next_reject_back(&mut self) -> Option<(usize, usize)> {
     };
 }
 
+/// Associated type for `<[char; N] as Pattern<'a>>::Searcher`.
+#[derive(Clone, Debug)]
+pub struct CharArraySearcher<'a, const N: usize>(
+    <MultiCharEqPattern<[char; N]> as Pattern<'a>>::Searcher,
+);
+
+/// Associated type for `<&[char; N] as Pattern<'a>>::Searcher`.
+#[derive(Clone, Debug)]
+pub struct CharArrayRefSearcher<'a, 'b, const N: usize>(
+    <MultiCharEqPattern<&'b [char; N]> as Pattern<'a>>::Searcher,
+);
+
+/// Searches for chars that are equal to any of the [`char`]s in the array.
+///
+/// # Examples
+///
+/// ```
+/// assert_eq!("Hello world".find(['l', 'l']), Some(2));
+/// assert_eq!("Hello world".find(['l', 'l']), Some(2));
+/// ```
+impl<'a, const N: usize> Pattern<'a> for [char; N] {
+    pattern_methods!(CharArraySearcher<'a, N>, MultiCharEqPattern, CharArraySearcher);
+}
+
+unsafe impl<'a, const N: usize> Searcher<'a> for CharArraySearcher<'a, N> {
+    searcher_methods!(forward);
+}
+
+unsafe impl<'a, const N: usize> ReverseSearcher<'a> for CharArraySearcher<'a, N> {
+    searcher_methods!(reverse);
+}
+
+/// Searches for chars that are equal to any of the [`char`]s in the array.
+///
+/// # Examples
+///
+/// ```
+/// assert_eq!("Hello world".find(&['l', 'l']), Some(2));
+/// assert_eq!("Hello world".find(&['l', 'l']), Some(2));
+/// ```
+impl<'a, 'b, const N: usize> Pattern<'a> for &'b [char; N] {
+    pattern_methods!(CharArrayRefSearcher<'a, 'b, N>, MultiCharEqPattern, CharArrayRefSearcher);
+}
+
+unsafe impl<'a, 'b, const N: usize> Searcher<'a> for CharArrayRefSearcher<'a, 'b, N> {
+    searcher_methods!(forward);
+}
+
+unsafe impl<'a, 'b, const N: usize> ReverseSearcher<'a> for CharArrayRefSearcher<'a, 'b, N> {
+    searcher_methods!(reverse);
+}
+
 /////////////////////////////////////////////////////////////////////////////
 // Impl for &[char]
 /////////////////////////////////////////////////////////////////////////////
index e225776bc647fe6d11e7d4e0f19e49d747303963..952676247489f938b1db7970fc9e97d94134e7b3 100644 (file)
@@ -234,7 +234,7 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
 /// Implements substring slicing with syntax `&self[.. end]` or `&mut
 /// self[.. end]`.
 ///
-/// Returns a slice of the given string from the byte range [`0`, `end`).
+/// Returns a slice of the given string from the byte range \[0, `end`).
 /// Equivalent to `&self[0 .. end]` or `&mut self[0 .. end]`.
 ///
 /// This operation is *O*(1).
@@ -304,9 +304,8 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
 /// Implements substring slicing with syntax `&self[begin ..]` or `&mut
 /// self[begin ..]`.
 ///
-/// Returns a slice of the given string from the byte range [`begin`,
-/// `len`). Equivalent to `&self[begin .. len]` or `&mut self[begin ..
-/// len]`.
+/// Returns a slice of the given string from the byte range \[`begin`, `len`).
+/// Equivalent to `&self[begin .. len]` or `&mut self[begin .. len]`.
 ///
 /// This operation is *O*(1).
 ///
@@ -433,7 +432,7 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
 /// Implements substring slicing with syntax `&self[..= end]` or `&mut
 /// self[..= end]`.
 ///
-/// Returns a slice of the given string from the byte range [0, `end`].
+/// Returns a slice of the given string from the byte range \[0, `end`\].
 /// Equivalent to `&self [0 .. end + 1]`, except if `end` has the maximum
 /// value for `usize`.
 ///
index 093c9c37b60b418b5be6481869946f26ae1f120e..9a1cf905e3b025c9aed55a9d56804da08d2482e3 100644 (file)
@@ -210,7 +210,7 @@ macro_rules! next {
                         // break if there is a nonascii byte
                         let zu = contains_nonascii(*block);
                         let zv = contains_nonascii(*block.offset(1));
-                        if zu | zv {
+                        if zu || zv {
                             break;
                         }
                     }
@@ -251,6 +251,7 @@ macro_rules! next {
 
 /// Given a first byte, determines how many bytes are in this UTF-8 character.
 #[unstable(feature = "str_internals", issue = "none")]
+#[must_use]
 #[inline]
 pub fn utf8_char_width(b: u8) -> usize {
     UTF8_CHAR_WIDTH[b as usize] as usize
index 1247f330875583865cd007a6dd3caba9c5bcce4b..1dd3b2d8e3c8d8c2ae4a0202aa090e64c96a16de 100644 (file)
@@ -1273,7 +1273,8 @@ pub fn fetch_update<F>(
 
 #[cfg(target_has_atomic_load_store = "8")]
 #[stable(feature = "atomic_bool_from", since = "1.24.0")]
-impl From<bool> for AtomicBool {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<bool> for AtomicBool {
     /// Converts a `bool` into an `AtomicBool`.
     ///
     /// # Examples
@@ -1291,7 +1292,8 @@ fn from(b: bool) -> Self {
 
 #[cfg(target_has_atomic_load_store = "ptr")]
 #[stable(feature = "atomic_from", since = "1.23.0")]
-impl<T> From<*mut T> for AtomicPtr<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<*mut T> for AtomicPtr<T> {
     #[inline]
     fn from(p: *mut T) -> Self {
         Self::new(p)
@@ -1363,7 +1365,8 @@ fn default() -> Self {
         }
 
         #[$stable_from]
-        impl From<$int_type> for $atomic_type {
+        #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
+        impl const From<$int_type> for $atomic_type {
             #[doc = concat!("Converts an `", stringify!($int_type), "` into an `", stringify!($atomic_type), "`.")]
             #[inline]
             fn from(v: $int_type) -> Self { Self::new(v) }
index 80e1458dc9421ba6f42278eec178ad5b05d75cbc..72a030617ad8ad387059f03450c43c73172428e6 100644 (file)
@@ -241,7 +241,8 @@ pub fn map_err<U, F>(self, f: F) -> Poll<Option<Result<T, U>>>
 }
 
 #[stable(feature = "futures_api", since = "1.36.0")]
-impl<T> From<T> for Poll<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<T> for Poll<T> {
     /// Convert to a `Ready` variant.
     ///
     /// # Example
index 620bff538799425c28ba158723712b072beca39f..6cba781c2ed8f6d41f1cc16b724b7c8022295aab 100644 (file)
@@ -167,6 +167,7 @@ pub fn from_waker(waker: &'a Waker) -> Self {
 
     /// Returns a reference to the `Waker` for the current task.
     #[stable(feature = "futures_api", since = "1.36.0")]
+    #[must_use]
     #[inline]
     pub fn waker(&self) -> &'a Waker {
         &self.waker
@@ -242,6 +243,7 @@ pub fn wake_by_ref(&self) {
     ///
     /// This function is primarily used for optimization purposes.
     #[inline]
+    #[must_use]
     #[stable(feature = "futures_api", since = "1.36.0")]
     pub fn will_wake(&self, other: &Waker) -> bool {
         self.waker == other.waker
index 5a74f39e8bc8b58469e6214909e99d92272ab797..a054d72a8800add4d17e15b60929ac9265bcecb3 100644 (file)
@@ -357,6 +357,7 @@ pub const fn as_secs(&self) -> u64 {
     /// ```
     #[stable(feature = "duration_extras", since = "1.27.0")]
     #[rustc_const_stable(feature = "duration_extras", since = "1.32.0")]
+    #[must_use]
     #[inline]
     pub const fn subsec_millis(&self) -> u32 {
         self.nanos / NANOS_PER_MILLI
@@ -379,6 +380,7 @@ pub const fn subsec_millis(&self) -> u32 {
     /// ```
     #[stable(feature = "duration_extras", since = "1.27.0")]
     #[rustc_const_stable(feature = "duration_extras", since = "1.32.0")]
+    #[must_use]
     #[inline]
     pub const fn subsec_micros(&self) -> u32 {
         self.nanos / NANOS_PER_MICRO
@@ -401,6 +403,7 @@ pub const fn subsec_micros(&self) -> u32 {
     /// ```
     #[stable(feature = "duration", since = "1.3.0")]
     #[rustc_const_stable(feature = "duration", since = "1.32.0")]
+    #[must_use]
     #[inline]
     pub const fn subsec_nanos(&self) -> u32 {
         self.nanos
@@ -737,7 +740,6 @@ pub const fn from_secs_f64(secs: f64) -> Duration {
     /// # Examples
     /// ```
     /// #![feature(duration_checked_float)]
-    ///
     /// use std::time::Duration;
     ///
     /// let dur = Duration::try_from_secs_f64(2.7);
@@ -756,7 +758,7 @@ pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromSecsError> {
         } else if nanos >= MAX_NANOS_F64 {
             Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
         } else if nanos < 0.0 {
-            Err(FromSecsError { kind: FromSecsErrorKind::Underflow })
+            Err(FromSecsError { kind: FromSecsErrorKind::Negative })
         } else {
             let nanos = nanos as u128;
             Ok(Duration {
@@ -799,7 +801,6 @@ pub const fn from_secs_f32(secs: f32) -> Duration {
     /// # Examples
     /// ```
     /// #![feature(duration_checked_float)]
-    ///
     /// use std::time::Duration;
     ///
     /// let dur = Duration::try_from_secs_f32(2.7);
@@ -818,7 +819,7 @@ pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromSecsError> {
         } else if nanos >= MAX_NANOS_F32 {
             Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
         } else if nanos < 0.0 {
-            Err(FromSecsError { kind: FromSecsErrorKind::Underflow })
+            Err(FromSecsError { kind: FromSecsErrorKind::Negative })
         } else {
             let nanos = nanos as u128;
             Ok(Duration {
@@ -1258,7 +1259,6 @@ fn fmt_decimal(
 ///
 /// ```
 /// #![feature(duration_checked_float)]
-///
 /// use std::time::Duration;
 ///
 /// if let Err(e) = Duration::try_from_secs_f32(-1.0) {
@@ -1274,11 +1274,9 @@ pub struct FromSecsError {
 impl FromSecsError {
     const fn description(&self) -> &'static str {
         match self.kind {
-            FromSecsErrorKind::NonFinite => {
-                "got non-finite value when converting float to duration"
-            }
+            FromSecsErrorKind::NonFinite => "non-finite value when converting float to duration",
             FromSecsErrorKind::Overflow => "overflow when converting float to duration",
-            FromSecsErrorKind::Underflow => "underflow when converting float to duration",
+            FromSecsErrorKind::Negative => "negative value when converting float to duration",
         }
     }
 }
@@ -1292,10 +1290,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 enum FromSecsErrorKind {
-    // Value is not a finite value (either infinity or NaN).
+    // Value is not a finite value (either + or - infinity or NaN).
     NonFinite,
     // Value is too large to store in a `Duration`.
     Overflow,
-    // Value is less than `0.0`.
-    Underflow,
+    // Value is negative.
+    Negative,
 }
index b3af1328c90d45869d0efb236f97e77e6a53df53..7dc071b74235d3f872c742f8f540cfb628f369d6 100644 (file)
@@ -7,6 +7,11 @@ fn array_from_ref() {
     let value: String = "Hello World!".into();
     let arr: &[String; 1] = array::from_ref(&value);
     assert_eq!(&[value.clone()], arr);
+
+    const VALUE: &&str = &"Hello World!";
+    const ARR: &[&str; 1] = array::from_ref(VALUE);
+    assert_eq!(&[*VALUE], ARR);
+    assert!(core::ptr::eq(VALUE, &ARR[0]));
 }
 
 #[test]
@@ -436,3 +441,36 @@ fn catch_unwind_silent<F, R>(f: F) -> std::thread::Result<R>
     std::panic::set_hook(prev_hook);
     result
 }
+
+#[test]
+fn array_split_array_mut() {
+    let mut v = [1, 2, 3, 4, 5, 6];
+
+    {
+        let (left, right) = v.split_array_mut::<0>();
+        assert_eq!(left, &mut []);
+        assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]);
+    }
+
+    {
+        let (left, right) = v.split_array_mut::<6>();
+        assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]);
+        assert_eq!(right, &mut []);
+    }
+}
+
+#[should_panic]
+#[test]
+fn array_split_array_ref_out_of_bounds() {
+    let v = [1, 2, 3, 4, 5, 6];
+
+    v.split_array_ref::<7>();
+}
+
+#[should_panic]
+#[test]
+fn array_split_array_mut_out_of_bounds() {
+    let mut v = [1, 2, 3, 4, 5, 6];
+
+    v.split_array_mut::<7>();
+}
index 66c25e449df2b9f7035404899ede8c331f53ed13..6d2cf3e83bce9683bbf9fea9dbd510072cb79c6c 100644 (file)
@@ -115,7 +115,7 @@ fn test_eq_ignore_ascii_case() {
 #[test]
 fn inference_works() {
     let x = "a".to_string();
-    x.eq_ignore_ascii_case("A");
+    let _ = x.eq_ignore_ascii_case("A");
 }
 
 // Shorthands used by the is_ascii_* tests.
index b735957666fc52b8d4a35235fc8cc22d2b532a02..7f8672f035417bb2c0e8ae51a319bfc60c6d0a2f 100644 (file)
@@ -220,3 +220,10 @@ fn atomic_compare_exchange() {
     ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok();
     ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok();
 }
+
+#[test]
+fn atomic_const_from() {
+    const _ATOMIC_U8: AtomicU8 = AtomicU8::from(1);
+    const _ATOMIC_BOOL: AtomicBool = AtomicBool::from(true);
+    const _ATOMIC_PTR: AtomicPtr<u32> = AtomicPtr::from(core::ptr::null_mut());
+}
index 85a006c5d5bef7ebca5a4146ae651a1f5891b298..4707cc7076ec0fa8038fb84659f1e76474ec1742 100644 (file)
@@ -465,4 +465,13 @@ fn const_cells() {
 
     const CELL: Cell<i32> = Cell::new(3);
     const _: i32 = CELL.into_inner();
+
+    const UNSAFE_CELL_FROM: UnsafeCell<i32> = UnsafeCell::from(3);
+    const _: i32 = UNSAFE_CELL.into_inner();
+
+    const REF_CELL_FROM: RefCell<i32> = RefCell::from(3);
+    const _: i32 = REF_CELL.into_inner();
+
+    const CELL_FROM: Cell<i32> = Cell::from(3);
+    const _: i32 = CELL.into_inner();
 }
index 51eca1e05d3438a463f07d7ffad33ee7aae7d015..6e434cf1a8d0f825e0449ee6db6de63b0779f947 100644 (file)
@@ -5,6 +5,8 @@
 #[test]
 fn test_convert() {
     assert_eq!(u32::from('a'), 0x61);
+    assert_eq!(u64::from('b'), 0x62);
+    assert_eq!(u128::from('c'), 0x63);
     assert_eq!(char::from(b'\0'), '\0');
     assert_eq!(char::from(b'a'), 'a');
     assert_eq!(char::from(b'\xFF'), '\u{FF}');
@@ -19,6 +21,16 @@ fn test_convert() {
     assert!(char::try_from(0xFFFF_FFFF_u32).is_err());
 }
 
+#[test]
+const fn test_convert_const() {
+    assert!(u32::from('a') == 0x61);
+    assert!(u64::from('b') == 0x62);
+    assert!(u128::from('c') == 0x63);
+    assert!(char::from(b'\0') == '\0');
+    assert!(char::from(b'a') == 'a');
+    assert!(char::from(b'\xFF') == '\u{FF}');
+}
+
 #[test]
 fn test_from_str() {
     assert_eq!(char::from_str("a").unwrap(), 'a');
index bd0daf7a8eb8487b1ce795cc4ae6f7fde055719d..47a7400f76ef95ecfb73146e2f295aa649ac3907 100644 (file)
@@ -12,6 +12,16 @@ fn test_format_f64() {
     assert_eq!("1.23456789E3", format!("{:E}", 1234.56789f64));
     assert_eq!("0.0", format!("{:?}", 0.0f64));
     assert_eq!("1.01", format!("{:?}", 1.01f64));
+
+    let high_cutoff = 1e16_f64;
+    assert_eq!("1e16", format!("{:?}", high_cutoff));
+    assert_eq!("-1e16", format!("{:?}", -high_cutoff));
+    assert!(!is_exponential(&format!("{:?}", high_cutoff * (1.0 - 2.0 * f64::EPSILON))));
+    assert_eq!("-3.0", format!("{:?}", -3f64));
+    assert_eq!("0.0001", format!("{:?}", 0.0001f64));
+    assert_eq!("9e-5", format!("{:?}", 0.00009f64));
+    assert_eq!("1234567.9", format!("{:.1?}", 1234567.89f64));
+    assert_eq!("1234.6", format!("{:.1?}", 1234.56789f64));
 }
 
 #[test]
@@ -28,4 +38,18 @@ fn test_format_f32() {
     assert_eq!("1.2345679E3", format!("{:E}", 1234.56789f32));
     assert_eq!("0.0", format!("{:?}", 0.0f32));
     assert_eq!("1.01", format!("{:?}", 1.01f32));
+
+    let high_cutoff = 1e16_f32;
+    assert_eq!("1e16", format!("{:?}", high_cutoff));
+    assert_eq!("-1e16", format!("{:?}", -high_cutoff));
+    assert!(!is_exponential(&format!("{:?}", high_cutoff * (1.0 - 2.0 * f32::EPSILON))));
+    assert_eq!("-3.0", format!("{:?}", -3f32));
+    assert_eq!("0.0001", format!("{:?}", 0.0001f32));
+    assert_eq!("9e-5", format!("{:?}", 0.00009f32));
+    assert_eq!("1234567.9", format!("{:.1?}", 1234567.89f32));
+    assert_eq!("1234.6", format!("{:.1?}", 1234.56789f32));
+}
+
+fn is_exponential(s: &str) -> bool {
+    s.contains("e") || s.contains("E")
 }
index 24f921ca7e4dc7a277d30c737577197cb8f72d06..064024ab87b281243bec34b3351f1df415b208af 100644 (file)
@@ -47,6 +47,12 @@ fn unsync_once_cell_drop_empty() {
     drop(x);
 }
 
+#[test]
+const fn once_cell_const() {
+    let _once_cell: OnceCell<u32> = OnceCell::new();
+    let _once_cell: OnceCell<u32> = OnceCell::from(32);
+}
+
 #[test]
 fn clone() {
     let s = OnceCell::new();
index 3608853dce4e05e41679195add2e47c8772ef9c4..ce40bac3f31a515d300a0d2bfb540f1ad8c573ea 100644 (file)
@@ -9,6 +9,7 @@
 #![feature(cfg_target_has_atomic)]
 #![feature(const_assume)]
 #![feature(const_cell_into_inner)]
+#![feature(const_convert)]
 #![feature(const_maybe_uninit_assume_init)]
 #![feature(const_ptr_read)]
 #![feature(const_ptr_write)]
 #![feature(const_raw_ptr_deref)]
 #![feature(never_type)]
 #![feature(unwrap_infallible)]
-#![feature(option_result_unwrap_unchecked)]
 #![feature(result_into_ok_or_err)]
 #![feature(ptr_metadata)]
 #![feature(once_cell)]
 #![feature(unsized_tuple_coercion)]
 #![feature(const_option)]
+#![feature(const_result)]
 #![feature(integer_atomics)]
 #![feature(int_roundings)]
 #![feature(slice_group_by)]
+#![feature(split_array)]
 #![feature(trusted_random_access)]
 #![feature(unsize)]
 #![feature(unzip_option)]
+#![feature(const_array_from_ref)]
+#![feature(const_slice_from_ref)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 extern crate test;
index c2c08522d0cae13d058b3f32d94f0040d071cb9b..a0ca919a851c36c15762c45e1001263f769dffe2 100644 (file)
@@ -204,9 +204,9 @@ fn nonzero_const() {
     // test that the methods of `NonZeroX>` are usable in a const context
     // Note: only tests NonZero8
 
-    const NONZERO: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) };
+    const NONZERO_U8: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) };
 
-    const GET: u8 = NONZERO.get();
+    const GET: u8 = NONZERO_U8.get();
     assert_eq!(GET, 5);
 
     const ZERO: Option<NonZeroU8> = NonZeroU8::new(0);
@@ -214,6 +214,12 @@ fn nonzero_const() {
 
     const ONE: Option<NonZeroU8> = NonZeroU8::new(1);
     assert!(ONE.is_some());
+
+    const FROM_NONZERO_U8: u8 = u8::from(NONZERO_U8);
+    assert_eq!(FROM_NONZERO_U8, 5);
+
+    const NONZERO_CONVERT: NonZeroU32 = NonZeroU32::from(NONZERO_U8);
+    assert_eq!(NONZERO_CONVERT.get(), 5);
 }
 
 #[test]
index 8995f96b1238a654badb66cece7ed962f109dd3c..cd07d6c52c2ade49cb03bc1da73590431dc7bad9 100644 (file)
@@ -358,10 +358,17 @@ fn option_const() {
     // test that the methods of `Option` are usable in a const context
 
     const OPTION: Option<usize> = Some(32);
+    assert_eq!(OPTION, Some(32));
+
+    const OPTION_FROM: Option<usize> = Option::from(32);
+    assert_eq!(OPTION_FROM, Some(32));
 
     const REF: Option<&usize> = OPTION.as_ref();
     assert_eq!(REF, Some(&32));
 
+    const REF_FROM: Option<&usize> = Option::from(&OPTION);
+    assert_eq!(REF_FROM, Some(&32));
+
     const IS_SOME: bool = OPTION.is_some();
     assert!(IS_SOME);
 
@@ -380,6 +387,22 @@ const fn option_const_mut() {
 
     let _take = option.take();
     let _replace = option.replace(42);
+
+    {
+        let as_mut = option.as_mut();
+        match as_mut {
+            Some(v) => *v = 32,
+            None => unreachable!(),
+        }
+    }
+
+    {
+        let as_mut: Option<&mut usize> = Option::from(&mut option);
+        match as_mut {
+            Some(v) => *v = 42,
+            None => unreachable!(),
+        }
+    }
 }
 
 #[test]
index 612f083a5c17820e2ab5e0df1e494db8816cbc5c..1652c1b83de3383fc36a7b01d06b5d3ddda625d8 100644 (file)
@@ -352,6 +352,29 @@ fn result_const() {
     assert!(!IS_ERR)
 }
 
+#[test]
+const fn result_const_mut() {
+    let mut result: Result<usize, bool> = Ok(32);
+
+    {
+        let as_mut = result.as_mut();
+        match as_mut {
+            Ok(v) => *v = 42,
+            Err(_) => unreachable!(),
+        }
+    }
+
+    let mut result_err: Result<usize, bool> = Err(false);
+
+    {
+        let as_mut = result_err.as_mut();
+        match as_mut {
+            Ok(_) => unreachable!(),
+            Err(v) => *v = true,
+        }
+    }
+}
+
 #[test]
 fn result_opt_conversions() {
     #[derive(Copy, Clone, Debug, PartialEq)]
index b6a326f3d7368007b3453ccf56fee296d6476e5e..8d05e47edf489f7add51dcf9d43514177166a607 100644 (file)
@@ -2146,6 +2146,14 @@ fn foo(x: &Cell<isize>) -> Foo<'_> {
     assert_eq!(x.get(), 1);
 }
 
+#[test]
+fn test_const_from_ref() {
+    const VALUE: &i32 = &1;
+    const SLICE: &[i32] = core::slice::from_ref(VALUE);
+
+    assert!(core::ptr::eq(VALUE, &SLICE[0]))
+}
+
 #[test]
 fn test_slice_fill_with_uninit() {
     // This should not UB. See #87891
@@ -2191,3 +2199,36 @@ fn index_b_greater_than_len() {
         x.swap(2, 5);
     }
 }
+
+#[test]
+fn slice_split_array_mut() {
+    let v = &mut [1, 2, 3, 4, 5, 6][..];
+
+    {
+        let (left, right) = v.split_array_mut::<0>();
+        assert_eq!(left, &mut []);
+        assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+    }
+
+    {
+        let (left, right) = v.split_array_mut::<6>();
+        assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]);
+        assert_eq!(right, []);
+    }
+}
+
+#[should_panic]
+#[test]
+fn slice_split_array_ref_out_of_bounds() {
+    let v = &[1, 2, 3, 4, 5, 6][..];
+
+    v.split_array_ref::<7>();
+}
+
+#[should_panic]
+#[test]
+fn slice_split_array_mut_out_of_bounds() {
+    let v = &mut [1, 2, 3, 4, 5, 6][..];
+
+    v.split_array_mut::<7>();
+}
index 6bc445c6f2b07b084ca4c110747bdcd84eba14ef..248ecdf4befcef742ae2cdd5235c532412c67437 100644 (file)
@@ -15,7 +15,7 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] }
 panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core" }
-libc = { version = "0.2.103", default-features = false, features = ['rustc-dep-of-std'] }
+libc = { version = "0.2.106", default-features = false, features = ['rustc-dep-of-std'] }
 compiler_builtins = { version = "0.1.44" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
index 9ace3e1b60007c24dd16378358634da9817affba..0b86b4f30b959925834c25207fdb194ed434fda8 100644 (file)
 /// previous point in time. In some instances the `Backtrace` type may
 /// internally be empty due to configuration. For more information see
 /// `Backtrace::capture`.
+#[must_use]
 pub struct Backtrace {
     inner: Inner,
 }
@@ -355,6 +356,7 @@ fn create(ip: usize) -> Backtrace {
     /// Returns the status of this backtrace, indicating whether this backtrace
     /// request was unsupported, disabled, or a stack trace was actually
     /// captured.
+    #[must_use]
     pub fn status(&self) -> BacktraceStatus {
         match self.inner {
             Inner::Unsupported => BacktraceStatus::Unsupported,
@@ -366,6 +368,7 @@ pub fn status(&self) -> BacktraceStatus {
 
 impl<'a> Backtrace {
     /// Returns an iterator over the backtrace frames.
+    #[must_use]
     #[unstable(feature = "backtrace_frames", issue = "79676")]
     pub fn frames(&'a self) -> &'a [BacktraceFrame] {
         if let Inner::Captured(c) = &self.inner { &c.force().frames } else { &[] }
index 01019344f4f67b2dff83edcee55e9b18acd1495c..12246b5173d394058c21dba7ef05acf70e110900 100644 (file)
@@ -1707,6 +1707,7 @@ pub fn and_modify<F>(self, f: F) -> Self
 impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> {
     /// Gets a reference to the key in the entry.
     #[inline]
+    #[must_use]
     #[unstable(feature = "hash_raw_entry", issue = "56167")]
     pub fn key(&self) -> &K {
         self.base.key()
@@ -1714,6 +1715,7 @@ pub fn key(&self) -> &K {
 
     /// Gets a mutable reference to the key in the entry.
     #[inline]
+    #[must_use]
     #[unstable(feature = "hash_raw_entry", issue = "56167")]
     pub fn key_mut(&mut self) -> &mut K {
         self.base.key_mut()
@@ -1730,6 +1732,7 @@ pub fn into_key(self) -> &'a mut K {
 
     /// Gets a reference to the value in the entry.
     #[inline]
+    #[must_use]
     #[unstable(feature = "hash_raw_entry", issue = "56167")]
     pub fn get(&self) -> &V {
         self.base.get()
@@ -1746,6 +1749,7 @@ pub fn into_mut(self) -> &'a mut V {
 
     /// Gets a mutable reference to the value in the entry.
     #[inline]
+    #[must_use]
     #[unstable(feature = "hash_raw_entry", issue = "56167")]
     pub fn get_mut(&mut self) -> &mut V {
         self.base.get_mut()
@@ -1753,6 +1757,7 @@ pub fn get_mut(&mut self) -> &mut V {
 
     /// Gets a reference to the key and value in the entry.
     #[inline]
+    #[must_use]
     #[unstable(feature = "hash_raw_entry", issue = "56167")]
     pub fn get_key_value(&mut self) -> (&K, &V) {
         self.base.get_key_value()
index 5804701892e6e447641ea8144b1a815c42799648..1fc1d39b1816e63cd3e48c19defd8b486169ffed 100644 (file)
@@ -38,8 +38,8 @@
 /// determined by the [`Eq`] trait, changes while it is in the set. This is
 /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or
 /// unsafe code. The behavior resulting from such a logic error is not
-/// specified, but will not result in undefined behavior. This could include
-/// panics, incorrect results, aborts, memory leaks, and non-termination.
+/// specified (it could include panics, incorrect results, aborts, memory
+/// leaks, or non-termination) but will not be undefined behavior.
 ///
 /// # Examples
 ///
@@ -1320,6 +1320,8 @@ pub struct DrainFilter<'a, K, F>
 ///
 /// let mut intersection = a.intersection(&b);
 /// ```
+#[must_use = "this returns the intersection as an iterator, \
+              without modifying either input set"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Intersection<'a, T: 'a, S: 'a> {
     // iterator of the first set
@@ -1345,6 +1347,8 @@ pub struct Intersection<'a, T: 'a, S: 'a> {
 ///
 /// let mut difference = a.difference(&b);
 /// ```
+#[must_use = "this returns the difference as an iterator, \
+              without modifying either input set"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Difference<'a, T: 'a, S: 'a> {
     // iterator of the first set
@@ -1370,6 +1374,8 @@ pub struct Difference<'a, T: 'a, S: 'a> {
 ///
 /// let mut intersection = a.symmetric_difference(&b);
 /// ```
+#[must_use = "this returns the difference as an iterator, \
+              without modifying either input set"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SymmetricDifference<'a, T: 'a, S: 'a> {
     iter: Chain<Difference<'a, T, S>, Difference<'a, T, S>>,
@@ -1392,6 +1398,8 @@ pub struct SymmetricDifference<'a, T: 'a, S: 'a> {
 ///
 /// let mut union_iter = a.union(&b);
 /// ```
+#[must_use = "this returns the union as an iterator, \
+              without modifying either input set"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Union<'a, T: 'a, S: 'a> {
     iter: Chain<Iter<'a, T>, Difference<'a, T, S>>,
index 40b46878cd8ba8c270f6780eafa2088c753a4321..c6af708f6cd0a99c9884dffd266475a067d89749 100644 (file)
@@ -113,6 +113,7 @@ pub struct VarsOs {
 /// ```
 ///
 /// [`env::vars_os()`]: vars_os
+#[must_use]
 #[stable(feature = "env", since = "1.0.0")]
 pub fn vars() -> Vars {
     Vars { inner: vars_os() }
@@ -140,6 +141,7 @@ pub fn vars() -> Vars {
 ///     println!("{:?}: {:?}", key, value);
 /// }
 /// ```
+#[must_use]
 #[stable(feature = "env", since = "1.0.0")]
 pub fn vars_os() -> VarsOs {
     VarsOs { inner: os_imp::env() }
@@ -244,6 +246,7 @@ fn _var(key: &OsStr) -> Result<String, VarError> {
 ///     None => println!("{} is not defined in the environment.", key)
 /// }
 /// ```
+#[must_use]
 #[stable(feature = "env", since = "1.0.0")]
 pub fn var_os<K: AsRef<OsStr>>(key: K) -> Option<OsString> {
     _var_os(key.as_ref())
@@ -384,6 +387,7 @@ fn _remove_var(key: &OsStr) {
 /// documentation for more.
 ///
 /// [`env::split_paths()`]: split_paths
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "env", since = "1.0.0")]
 pub struct SplitPaths<'a> {
     inner: os_imp::SplitPaths<'a>,
@@ -564,6 +568,7 @@ fn description(&self) -> &str {
     reason = "This function's behavior is unexpected and probably not what you want. \
               Consider using a crate from crates.io instead."
 )]
+#[must_use]
 #[stable(feature = "env", since = "1.0.0")]
 pub fn home_dir() -> Option<PathBuf> {
     os_imp::home_dir()
@@ -603,6 +608,7 @@ pub fn home_dir() -> Option<PathBuf> {
 ///     println!("Temporary directory: {}", dir.display());
 /// }
 /// ```
+#[must_use]
 #[stable(feature = "env", since = "1.0.0")]
 pub fn temp_dir() -> PathBuf {
     os_imp::temp_dir()
@@ -690,6 +696,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
 /// should not be relied upon for security purposes.
 ///
 /// [`env::args()`]: args
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "env", since = "1.0.0")]
 pub struct Args {
     inner: ArgsOs,
@@ -706,6 +713,7 @@ pub struct Args {
 /// should not be relied upon for security purposes.
 ///
 /// [`env::args_os()`]: args_os
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "env", since = "1.0.0")]
 pub struct ArgsOs {
     inner: sys::args::Args,
index 0b392897f9d8ac02b3505064f0849eca71eb457d..d23f5244d88d4e4f9999509c23900fcec7515bc5 100644 (file)
@@ -878,40 +878,4 @@ pub fn acosh(self) -> f32 {
     pub fn atanh(self) -> f32 {
         0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
     }
-
-    /// Linear interpolation between `start` and `end`.
-    ///
-    /// This enables linear interpolation between `start` and `end`, where start is represented by
-    /// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all
-    /// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0
-    /// at a given rate, the result will change from `start` to `end` at a similar rate.
-    ///
-    /// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the
-    /// range from `start` to `end`. This also is useful for transition functions which might
-    /// move slightly past the end or start for a desired effect. Mathematically, the values
-    /// returned are equivalent to `start + self * (end - start)`, although we make a few specific
-    /// guarantees that are useful specifically to linear interpolation.
-    ///
-    /// These guarantees are:
-    ///
-    /// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the
-    ///   value at 1.0 is always `end`. (exactness)
-    /// * If `start` and `end` are [finite], the values will always move in the direction from
-    ///   `start` to `end` (monotonicity)
-    /// * If `self` is [finite] and `start == end`, the value at any point will always be
-    ///   `start == end`. (consistency)
-    ///
-    /// [finite]: #method.is_finite
-    #[must_use = "method returns a new number and does not mutate the original value"]
-    #[unstable(feature = "float_interpolation", issue = "86269")]
-    pub fn lerp(self, start: f32, end: f32) -> f32 {
-        // consistent
-        if start == end {
-            start
-
-        // exact/monotonic
-        } else {
-            self.mul_add(end, (-self).mul_add(start, start))
-        }
-    }
 }
index fe66a73afd63ab7ef6d55f5dfe708640e22cde46..0d4b865f3392a66304e13e47e9fa652099428534 100644 (file)
@@ -757,66 +757,3 @@ fn s_nan() -> f32 {
     assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY));
     assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
 }
-
-#[test]
-fn test_lerp_exact() {
-    // simple values
-    assert_eq!(f32::lerp(0.0, 2.0, 4.0), 2.0);
-    assert_eq!(f32::lerp(1.0, 2.0, 4.0), 4.0);
-
-    // boundary values
-    assert_eq!(f32::lerp(0.0, f32::MIN, f32::MAX), f32::MIN);
-    assert_eq!(f32::lerp(1.0, f32::MIN, f32::MAX), f32::MAX);
-}
-
-#[test]
-fn test_lerp_consistent() {
-    assert_eq!(f32::lerp(f32::MAX, f32::MIN, f32::MIN), f32::MIN);
-    assert_eq!(f32::lerp(f32::MIN, f32::MAX, f32::MAX), f32::MAX);
-
-    // as long as t is finite, a/b can be infinite
-    assert_eq!(f32::lerp(f32::MAX, f32::NEG_INFINITY, f32::NEG_INFINITY), f32::NEG_INFINITY);
-    assert_eq!(f32::lerp(f32::MIN, f32::INFINITY, f32::INFINITY), f32::INFINITY);
-}
-
-#[test]
-fn test_lerp_nan_infinite() {
-    // non-finite t is not NaN if a/b different
-    assert!(!f32::lerp(f32::INFINITY, f32::MIN, f32::MAX).is_nan());
-    assert!(!f32::lerp(f32::NEG_INFINITY, f32::MIN, f32::MAX).is_nan());
-}
-
-#[test]
-fn test_lerp_values() {
-    // just a few basic values
-    assert_eq!(f32::lerp(0.25, 1.0, 2.0), 1.25);
-    assert_eq!(f32::lerp(0.50, 1.0, 2.0), 1.50);
-    assert_eq!(f32::lerp(0.75, 1.0, 2.0), 1.75);
-}
-
-#[test]
-fn test_lerp_monotonic() {
-    // near 0
-    let below_zero = f32::lerp(-f32::EPSILON, f32::MIN, f32::MAX);
-    let zero = f32::lerp(0.0, f32::MIN, f32::MAX);
-    let above_zero = f32::lerp(f32::EPSILON, f32::MIN, f32::MAX);
-    assert!(below_zero <= zero);
-    assert!(zero <= above_zero);
-    assert!(below_zero <= above_zero);
-
-    // near 0.5
-    let below_half = f32::lerp(0.5 - f32::EPSILON, f32::MIN, f32::MAX);
-    let half = f32::lerp(0.5, f32::MIN, f32::MAX);
-    let above_half = f32::lerp(0.5 + f32::EPSILON, f32::MIN, f32::MAX);
-    assert!(below_half <= half);
-    assert!(half <= above_half);
-    assert!(below_half <= above_half);
-
-    // near 1
-    let below_one = f32::lerp(1.0 - f32::EPSILON, f32::MIN, f32::MAX);
-    let one = f32::lerp(1.0, f32::MIN, f32::MAX);
-    let above_one = f32::lerp(1.0 + f32::EPSILON, f32::MIN, f32::MAX);
-    assert!(below_one <= one);
-    assert!(one <= above_one);
-    assert!(below_one <= above_one);
-}
index 602cceb5d1a1ce55e13cc98faf9d0baaeaff8743..55e17b471905d29dd293be5e2db9a494e9a55d5c 100644 (file)
@@ -881,42 +881,6 @@ pub fn atanh(self) -> f64 {
         0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
     }
 
-    /// Linear interpolation between `start` and `end`.
-    ///
-    /// This enables linear interpolation between `start` and `end`, where start is represented by
-    /// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all
-    /// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0
-    /// at a given rate, the result will change from `start` to `end` at a similar rate.
-    ///
-    /// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the
-    /// range from `start` to `end`. This also is useful for transition functions which might
-    /// move slightly past the end or start for a desired effect. Mathematically, the values
-    /// returned are equivalent to `start + self * (end - start)`, although we make a few specific
-    /// guarantees that are useful specifically to linear interpolation.
-    ///
-    /// These guarantees are:
-    ///
-    /// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the
-    ///   value at 1.0 is always `end`. (exactness)
-    /// * If `start` and `end` are [finite], the values will always move in the direction from
-    ///   `start` to `end` (monotonicity)
-    /// * If `self` is [finite] and `start == end`, the value at any point will always be
-    ///   `start == end`. (consistency)
-    ///
-    /// [finite]: #method.is_finite
-    #[must_use = "method returns a new number and does not mutate the original value"]
-    #[unstable(feature = "float_interpolation", issue = "86269")]
-    pub fn lerp(self, start: f64, end: f64) -> f64 {
-        // consistent
-        if start == end {
-            start
-
-        // exact/monotonic
-        } else {
-            self.mul_add(end, (-self).mul_add(start, start))
-        }
-    }
-
     // Solaris/Illumos requires a wrapper around log, log2, and log10 functions
     // because of their non-standard behavior (e.g., log(-n) returns -Inf instead
     // of expected NaN).
index 04cb0109261a48068d54261a7c3cb381ed458220..5c163cfe90e0b2eff9030bc80dd0cfeb4c71532c 100644 (file)
@@ -753,58 +753,3 @@ fn s_nan() -> f64 {
     assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY));
     assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
 }
-
-#[test]
-fn test_lerp_exact() {
-    // simple values
-    assert_eq!(f64::lerp(0.0, 2.0, 4.0), 2.0);
-    assert_eq!(f64::lerp(1.0, 2.0, 4.0), 4.0);
-
-    // boundary values
-    assert_eq!(f64::lerp(0.0, f64::MIN, f64::MAX), f64::MIN);
-    assert_eq!(f64::lerp(1.0, f64::MIN, f64::MAX), f64::MAX);
-}
-
-#[test]
-fn test_lerp_consistent() {
-    assert_eq!(f64::lerp(f64::MAX, f64::MIN, f64::MIN), f64::MIN);
-    assert_eq!(f64::lerp(f64::MIN, f64::MAX, f64::MAX), f64::MAX);
-
-    // as long as t is finite, a/b can be infinite
-    assert_eq!(f64::lerp(f64::MAX, f64::NEG_INFINITY, f64::NEG_INFINITY), f64::NEG_INFINITY);
-    assert_eq!(f64::lerp(f64::MIN, f64::INFINITY, f64::INFINITY), f64::INFINITY);
-}
-
-#[test]
-fn test_lerp_nan_infinite() {
-    // non-finite t is not NaN if a/b different
-    assert!(!f64::lerp(f64::INFINITY, f64::MIN, f64::MAX).is_nan());
-    assert!(!f64::lerp(f64::NEG_INFINITY, f64::MIN, f64::MAX).is_nan());
-}
-
-#[test]
-fn test_lerp_values() {
-    // just a few basic values
-    assert_eq!(f64::lerp(0.25, 1.0, 2.0), 1.25);
-    assert_eq!(f64::lerp(0.50, 1.0, 2.0), 1.50);
-    assert_eq!(f64::lerp(0.75, 1.0, 2.0), 1.75);
-}
-
-#[test]
-fn test_lerp_monotonic() {
-    // near 0
-    let below_zero = f64::lerp(-f64::EPSILON, f64::MIN, f64::MAX);
-    let zero = f64::lerp(0.0, f64::MIN, f64::MAX);
-    let above_zero = f64::lerp(f64::EPSILON, f64::MIN, f64::MAX);
-    assert!(below_zero <= zero);
-    assert!(zero <= above_zero);
-    assert!(below_zero <= above_zero);
-
-    // near 1
-    let below_one = f64::lerp(1.0 - f64::EPSILON, f64::MIN, f64::MAX);
-    let one = f64::lerp(1.0, f64::MIN, f64::MAX);
-    let above_one = f64::lerp(1.0 + f64::EPSILON, f64::MIN, f64::MAX);
-    assert!(below_one <= one);
-    assert!(one <= above_one);
-    assert!(below_one <= above_one);
-}
index 6827d3a8d2448342218881c9fc6c66a0116dd257..465bbae8631c519b591a7b33ddb0f496f9f9ec4b 100644 (file)
@@ -251,13 +251,12 @@ pub struct FromBytesWithNulError {
 /// # Examples
 ///
 /// ```
-/// #![feature(cstring_from_vec_with_nul)]
 /// use std::ffi::{CString, FromVecWithNulError};
 ///
 /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"f\0oo".to_vec()).unwrap_err();
 /// ```
 #[derive(Clone, PartialEq, Eq, Debug)]
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
 pub struct FromVecWithNulError {
     error_kind: FromBytesWithNulErrorKind,
     bytes: Vec<u8>,
@@ -278,7 +277,7 @@ fn not_nul_terminated() -> FromBytesWithNulError {
     }
 }
 
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
 impl FromVecWithNulError {
     /// Returns a slice of [`u8`]s bytes that were attempted to convert to a [`CString`].
     ///
@@ -287,7 +286,6 @@ impl FromVecWithNulError {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(cstring_from_vec_with_nul)]
     /// use std::ffi::CString;
     ///
     /// // Some invalid bytes in a vector
@@ -298,6 +296,7 @@ impl FromVecWithNulError {
     /// assert_eq!(&bytes[..], value.unwrap_err().as_bytes());
     /// ```
     #[must_use]
+    #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
     pub fn as_bytes(&self) -> &[u8] {
         &self.bytes[..]
     }
@@ -313,7 +312,6 @@ pub fn as_bytes(&self) -> &[u8] {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(cstring_from_vec_with_nul)]
     /// use std::ffi::CString;
     ///
     /// // Some invalid bytes in a vector
@@ -324,6 +322,7 @@ pub fn as_bytes(&self) -> &[u8] {
     /// assert_eq!(bytes, value.unwrap_err().into_bytes());
     /// ```
     #[must_use = "`self` will be dropped if the result is not used"]
+    #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
     pub fn into_bytes(self) -> Vec<u8> {
         self.bytes
     }
@@ -704,7 +703,6 @@ fn into_inner(self) -> Box<[u8]> {
     /// # Example
     ///
     /// ```
-    /// #![feature(cstring_from_vec_with_nul)]
     /// use std::ffi::CString;
     /// assert_eq!(
     ///     unsafe { CString::from_vec_with_nul_unchecked(b"abc\0".to_vec()) },
@@ -712,7 +710,7 @@ fn into_inner(self) -> Box<[u8]> {
     /// );
     /// ```
     #[must_use]
-    #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+    #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
     pub unsafe fn from_vec_with_nul_unchecked(v: Vec<u8>) -> Self {
         Self { inner: v.into_boxed_slice() }
     }
@@ -733,7 +731,6 @@ pub unsafe fn from_vec_with_nul_unchecked(v: Vec<u8>) -> Self {
     /// when called without the ending nul byte.
     ///
     /// ```
-    /// #![feature(cstring_from_vec_with_nul)]
     /// use std::ffi::CString;
     /// assert_eq!(
     ///     CString::from_vec_with_nul(b"abc\0".to_vec())
@@ -745,14 +742,13 @@ pub unsafe fn from_vec_with_nul_unchecked(v: Vec<u8>) -> Self {
     /// An incorrectly formatted [`Vec`] will produce an error.
     ///
     /// ```
-    /// #![feature(cstring_from_vec_with_nul)]
     /// use std::ffi::{CString, FromVecWithNulError};
     /// // Interior nul byte
     /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"a\0bc".to_vec()).unwrap_err();
     /// // No nul byte
     /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"abc".to_vec()).unwrap_err();
     /// ```
-    #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+    #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
     pub fn from_vec_with_nul(v: Vec<u8>) -> Result<Self, FromVecWithNulError> {
         let nul_pos = memchr::memchr(0, &v);
         match nul_pos {
@@ -1013,6 +1009,7 @@ impl NulError {
     /// let nul_error = CString::new("foo bar\0").unwrap_err();
     /// assert_eq!(nul_error.nul_position(), 7);
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn nul_position(&self) -> usize {
         self.0
@@ -1084,10 +1081,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
 impl Error for FromVecWithNulError {}
 
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
 impl fmt::Display for FromVecWithNulError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.error_kind {
@@ -1111,6 +1108,7 @@ pub fn into_cstring(self) -> CString {
     }
 
     /// Access the underlying UTF-8 error that was the cause of this error.
+    #[must_use]
     #[stable(feature = "cstring_into", since = "1.7.0")]
     pub fn utf8_error(&self) -> Utf8Error {
         self.error
@@ -1175,6 +1173,7 @@ impl CStr {
     /// }
     /// # }
     /// ```
+    #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
@@ -1260,7 +1259,7 @@ pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError>
     #[inline]
     #[must_use]
     #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
-    #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "none")]
+    #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "90343")]
     pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
         // SAFETY: Casting to CStr is safe because its internal representation
         // is a [u8] too (safe only inside std).
@@ -1459,6 +1458,7 @@ pub fn to_string_lossy(&self) -> Cow<'_, str> {
     /// let boxed = c_string.into_boxed_c_str();
     /// assert_eq!(boxed.into_c_string(), CString::new("foo").expect("CString::new failed"));
     /// ```
+    #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "into_boxed_c_str", since = "1.20.0")]
     pub fn into_c_string(self: Box<CStr>) -> CString {
         let raw = Box::into_raw(self) as *mut [u8];
index 82a76aa73c583fb78ecaea7bb101cca179d71547..7f3bb836754ed5396607dc6a4889a6f249edebc0 100644 (file)
 
 #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
 pub use self::c_str::FromBytesWithNulError;
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
 pub use self::c_str::FromVecWithNulError;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::c_str::{CStr, CString, IntoStringError, NulError};
index 46c9aa5e627c502082a5cabb691c5107eabd6ed6..0f9912fa64d8bef01dafbd44dfec39ca9da1f08f 100644 (file)
@@ -239,6 +239,7 @@ pub fn clear(&mut self) {
     /// assert!(os_string.capacity() >= 10);
     /// ```
     #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+    #[must_use]
     #[inline]
     pub fn capacity(&self) -> usize {
         self.inner.capacity()
@@ -669,6 +670,7 @@ pub fn to_os_string(&self) -> OsString {
     /// assert!(!os_str.is_empty());
     /// ```
     #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+    #[must_use]
     #[inline]
     pub fn is_empty(&self) -> bool {
         self.inner.inner.is_empty()
@@ -700,6 +702,7 @@ pub fn is_empty(&self) -> bool {
     /// assert_eq!(os_str.len(), 3);
     /// ```
     #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+    #[must_use]
     #[inline]
     pub fn len(&self) -> usize {
         self.inner.inner.len()
@@ -707,6 +710,7 @@ pub fn len(&self) -> usize {
 
     /// Converts a <code>[Box]<[OsStr]></code> into an [`OsString`] without copying or allocating.
     #[stable(feature = "into_boxed_os_str", since = "1.20.0")]
+    #[must_use = "`self` will be dropped if the result is not used"]
     pub fn into_os_string(self: Box<OsStr>) -> OsString {
         let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) };
         OsString { inner: Buf::from_box(boxed) }
@@ -829,6 +833,7 @@ pub fn to_ascii_uppercase(&self) -> OsString {
     /// assert!(!non_ascii.is_ascii());
     /// ```
     #[stable(feature = "osstring_ascii", since = "1.53.0")]
+    #[must_use]
     #[inline]
     pub fn is_ascii(&self) -> bool {
         self.inner.is_ascii()
index 9f45e89aa7504217fcb23f898c9c9073376ba9e4..e13add799bcb97804559fc6d918ea16f0fbf24a4 100644 (file)
@@ -374,6 +374,7 @@ pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
     ///     Ok(())
     /// }
     /// ```
+    #[must_use]
     #[unstable(feature = "with_options", issue = "65439")]
     pub fn with_options() -> OpenOptions {
         OpenOptions::new()
@@ -983,6 +984,7 @@ impl Metadata {
     ///     Ok(())
     /// }
     /// ```
+    #[must_use]
     #[stable(feature = "file_type", since = "1.1.0")]
     pub fn file_type(&self) -> FileType {
         FileType(self.0.file_type())
@@ -1046,7 +1048,6 @@ pub fn is_file(&self) -> bool {
     ///
     #[cfg_attr(unix, doc = "```no_run")]
     #[cfg_attr(not(unix), doc = "```ignore")]
-    /// #![feature(is_symlink)]
     /// use std::fs;
     /// use std::path::Path;
     /// use std::os::unix::fs::symlink;
@@ -1062,7 +1063,7 @@ pub fn is_file(&self) -> bool {
     /// }
     /// ```
     #[must_use]
-    #[unstable(feature = "is_symlink", issue = "85748")]
+    #[stable(feature = "is_symlink", since = "1.57.0")]
     pub fn is_symlink(&self) -> bool {
         self.file_type().is_symlink()
     }
@@ -1081,6 +1082,7 @@ pub fn is_symlink(&self) -> bool {
     ///     Ok(())
     /// }
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn len(&self) -> u64 {
         self.0.size()
@@ -1100,6 +1102,7 @@ pub fn len(&self) -> u64 {
     ///     Ok(())
     /// }
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn permissions(&self) -> Permissions {
         Permissions(self.0.perm())
@@ -1247,6 +1250,7 @@ impl Permissions {
     ///     Ok(())
     /// }
     /// ```
+    #[must_use = "call `set_readonly` to modify the readonly flag"]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn readonly(&self) -> bool {
         self.0.readonly()
@@ -1441,6 +1445,7 @@ impl DirEntry {
     /// ```
     ///
     /// The exact text, of course, depends on what files you have in `.`.
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn path(&self) -> PathBuf {
         self.0.path()
@@ -1536,6 +1541,7 @@ pub fn file_type(&self) -> io::Result<FileType> {
     ///     }
     /// }
     /// ```
+    #[must_use]
     #[stable(feature = "dir_entry_ext", since = "1.1.0")]
     pub fn file_name(&self) -> OsString {
         self.0.file_name()
index 13dbae3b7b580016ca1667d03d32832ee29af152..628de13156c67f4bff68fee4cff9f7d1161f45ed 100644 (file)
@@ -1411,3 +1411,32 @@ fn symlink_hard_link() {
     // "hard_link" should still appear as a symlink.
     assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
 }
+
+/// Ensure `fs::create_dir` works on Windows with longer paths.
+#[test]
+#[cfg(windows)]
+fn create_dir_long_paths() {
+    use crate::{ffi::OsStr, iter, os::windows::ffi::OsStrExt};
+    const PATH_LEN: usize = 247;
+
+    let tmpdir = tmpdir();
+    let mut path = tmpdir.path().to_path_buf();
+    path.push("a");
+    let mut path = path.into_os_string();
+
+    let utf16_len = path.encode_wide().count();
+    if utf16_len >= PATH_LEN {
+        // Skip the test in the unlikely event the local user has a long temp directory path.
+        // This should not affect CI.
+        return;
+    }
+    // Increase the length of the path.
+    path.extend(iter::repeat(OsStr::new("a")).take(PATH_LEN - utf16_len));
+
+    // This should succeed.
+    fs::create_dir(&path).unwrap();
+
+    // This will fail if the path isn't converted to verbatim.
+    path.push("a");
+    fs::create_dir(&path).unwrap();
+}
index 59a9cd781cb99f32f83fd3f12fe83f9bcad7ef1b..3da28695b34bd951e9e3b84a1e5e28a3c99fbe8e 100644 (file)
@@ -442,6 +442,7 @@ pub(crate) const fn new_const(kind: ErrorKind, message: &'static &'static str) -
     /// println!("last OS error: {:?}", Error::last_os_error());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     #[inline]
     pub fn last_os_error() -> Error {
         Error::from_raw_os_error(sys::os::errno() as i32)
@@ -509,6 +510,7 @@ pub fn from_raw_os_error(code: i32) -> Error {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     #[inline]
     pub fn raw_os_error(&self) -> Option<i32> {
         match self.repr {
@@ -547,6 +549,7 @@ pub fn raw_os_error(&self) -> Option<i32> {
     /// }
     /// ```
     #[stable(feature = "io_error_inner", since = "1.3.0")]
+    #[must_use]
     #[inline]
     pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
         match self.repr {
@@ -620,6 +623,7 @@ pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
     /// }
     /// ```
     #[stable(feature = "io_error_inner", since = "1.3.0")]
+    #[must_use]
     #[inline]
     pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> {
         match self.repr {
@@ -688,6 +692,7 @@ pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     #[inline]
     pub fn kind(&self) -> ErrorKind {
         match self.repr {
index abe29ba0f7caa379c339c2fde186777cfe3d17f2..8cc91566418dc957c57de39e3ca4f59e0ca8482b 100644 (file)
 
 const DEFAULT_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
 
-pub(crate) fn cleanup() {
-    stdio::cleanup()
-}
+pub(crate) use stdio::cleanup;
 
 struct Guard<'a> {
     buf: &'a mut Vec<u8>,
@@ -1310,6 +1308,7 @@ fn deref(&self) -> &[u8] {
 impl Initializer {
     /// Returns a new `Initializer` which will zero out buffers.
     #[unstable(feature = "read_initializer", issue = "42788")]
+    #[must_use]
     #[inline]
     pub fn zeroing() -> Initializer {
         Initializer(true)
@@ -1324,6 +1323,7 @@ pub fn zeroing() -> Initializer {
     /// the method accurately reflects the number of bytes that have been
     /// written to the head of the buffer.
     #[unstable(feature = "read_initializer", issue = "42788")]
+    #[must_use]
     #[inline]
     pub unsafe fn nop() -> Initializer {
         Initializer(false)
@@ -1331,6 +1331,7 @@ pub unsafe fn nop() -> Initializer {
 
     /// Indicates if a buffer should be initialized.
     #[unstable(feature = "read_initializer", issue = "42788")]
+    #[must_use]
     #[inline]
     pub fn should_initialize(&self) -> bool {
         self.0
index 9389501e0129e63b8a6d4d5a042b06a79e7a27a5..f7fc23c1e829c47b4701ad8503890d586b3c0b9a 100644 (file)
@@ -301,6 +301,7 @@ pub struct StdinLock<'a> {
 ///     Ok(())
 /// }
 /// ```
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn stdin() -> Stdin {
     static INSTANCE: SyncOnceCell<Mutex<BufReader<StdinRaw>>> = SyncOnceCell::new();
@@ -487,6 +488,7 @@ pub fn lines(self) -> Lines<StdinLock<'static>> {
     ///     println!("got a chunk: {}", String::from_utf8_lossy(&split.unwrap()));
     /// }
     /// ```
+    #[must_use = "`self` will be dropped if the result is not used"]
     #[unstable(feature = "stdin_forwarders", issue = "87096")]
     pub fn split(self, byte: u8) -> Split<StdinLock<'static>> {
         self.into_locked().split(byte)
@@ -673,6 +675,7 @@ pub struct StdoutLock<'a> {
 ///     Ok(())
 /// }
 /// ```
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn stdout() -> Stdout {
     Stdout {
@@ -953,6 +956,7 @@ pub struct StderrLock<'a> {
 ///     Ok(())
 /// }
 /// ```
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn stderr() -> Stderr {
     // Note that unlike `stdout()` we don't use `at_exit` here to register a
index 2f3520ae7a5a5fb4c9aab4c4364b64fe334b5d70..9cd7c5148499db87b228f260139b06f002100e0d 100644 (file)
@@ -32,6 +32,7 @@
 /// io::empty().read_to_string(&mut buffer).unwrap();
 /// assert!(buffer.is_empty());
 /// ```
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
 pub const fn empty() -> Empty {
@@ -112,6 +113,7 @@ pub struct Repeat {
 /// io::repeat(0b101).read_exact(&mut buffer).unwrap();
 /// assert_eq!(buffer, [0b101, 0b101, 0b101]);
 /// ```
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
 pub const fn repeat(byte: u8) -> Repeat {
@@ -192,6 +194,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// let num_bytes = io::sink().write(&buffer).unwrap();
 /// assert_eq!(num_bytes, 5);
 /// ```
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
 pub const fn sink() -> Sink {
index 1d2d26b8f004699ee26939e4d469100c62525f7c..c2243b259538aee080699b2f79fadf51663931a4 100644 (file)
 #![feature(const_cstr_unchecked)]
 #![feature(const_fn_floating_point_arithmetic)]
 #![feature(const_fn_fn_ptr_basics)]
+#![feature(const_fn_trait_bound)]
 #![feature(const_format_args)]
 #![feature(const_io_structs)]
 #![feature(const_ip)]
 #![feature(custom_test_frameworks)]
 #![feature(decl_macro)]
 #![feature(doc_cfg)]
-#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))]
+#![feature(doc_cfg_hide)]
 #![feature(doc_keyword)]
 #![feature(doc_masked)]
 #![feature(doc_notable_trait)]
 #![feature(exact_size_is_empty)]
 #![feature(exhaustive_patterns)]
 #![feature(extend_one)]
-#![feature(float_interpolation)]
 #![feature(fn_traits)]
 #![feature(format_args_nl)]
 #![feature(gen_future)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(min_specialization)]
 #![feature(mixed_integer_ops)]
-#![cfg_attr(not(bootstrap), feature(must_not_suspend))]
+#![feature(must_not_suspend)]
 #![feature(needs_panic_runtime)]
 #![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(ptr_internals)]
 #![feature(rustc_attrs)]
 #![feature(rustc_private)]
-#![feature(saturating_div)]
 #![feature(saturating_int_impl)]
 #![feature(slice_concat_ext)]
 #![feature(slice_internals)]
index a689d2a56b721d2c8fd1574c907e0de28e21418c..201cbf3f08d28aad58e73f59350867298114f66f 100644 (file)
@@ -149,6 +149,7 @@ pub fn new(ip: IpAddr, port: u16) -> SocketAddr {
     /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
     /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
     /// ```
+    #[must_use]
     #[stable(feature = "ip_addr", since = "1.7.0")]
     #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
     pub const fn ip(&self) -> IpAddr {
@@ -189,6 +190,7 @@ pub fn set_ip(&mut self, new_ip: IpAddr) {
     /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
     /// assert_eq!(socket.port(), 8080);
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
     pub const fn port(&self) -> u16 {
@@ -297,6 +299,7 @@ pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
     /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
     /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
     pub const fn ip(&self) -> &Ipv4Addr {
@@ -331,6 +334,7 @@ pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
     /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
     /// assert_eq!(socket.port(), 8080);
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
     pub const fn port(&self) -> u16 {
@@ -396,6 +400,7 @@ pub fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV
     /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
     /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
     pub const fn ip(&self) -> &Ipv6Addr {
@@ -428,6 +433,7 @@ pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
     /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
     /// assert_eq!(socket.port(), 8080);
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
     pub const fn port(&self) -> u16 {
@@ -470,6 +476,7 @@ pub fn set_port(&mut self, new_port: u16) {
     /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
     /// assert_eq!(socket.flowinfo(), 10);
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
     pub const fn flowinfo(&self) -> u32 {
@@ -509,6 +516,7 @@ pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
     /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
     /// assert_eq!(socket.scope_id(), 78);
     /// ```
+    #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
     pub const fn scope_id(&self) -> u32 {
index e5e9fedb61eaf1b70833540079c8b6534f6ac494..140647128a937d934b31d0c831c91f4593fce512 100644 (file)
@@ -59,7 +59,8 @@ pub enum IpAddr {
 ///
 /// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal
 /// notation, divided by `.` (this is called "dot-decimal notation").
-/// Notably, octal numbers and hexadecimal numbers are not allowed per [IETF RFC 6943].
+/// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which
+/// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943].
 ///
 /// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1
 /// [`FromStr`]: crate::str::FromStr
@@ -72,6 +73,9 @@ pub enum IpAddr {
 /// let localhost = Ipv4Addr::new(127, 0, 0, 1);
 /// assert_eq!("127.0.0.1".parse(), Ok(localhost));
 /// assert_eq!(localhost.is_loopback(), true);
+/// assert!("012.004.002.000".parse::<Ipv4Addr>().is_err()); // all octets are in octal
+/// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal
+/// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex
 /// ```
 #[derive(Copy)]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -514,6 +518,7 @@ pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
     /// ```
     #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     #[inline]
     pub const fn octets(&self) -> [u8; 4] {
         // This returns the order we want because s_addr is stored in big-endian.
@@ -1280,6 +1285,7 @@ pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16)
     /// ```
     #[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     #[inline]
     pub const fn segments(&self) -> [u16; 8] {
         // All elements in `s6_addr` must be big endian.
@@ -1590,6 +1596,7 @@ pub const fn is_unicast_global(&self) -> bool {
     /// ```
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
     #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
     #[inline]
     pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
         if self.is_multicast() {
@@ -1740,6 +1747,7 @@ pub const fn to_canonical(&self) -> IpAddr {
     /// ```
     #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")]
     #[stable(feature = "ipv6_to_octets", since = "1.12.0")]
+    #[must_use]
     #[inline]
     pub const fn octets(&self) -> [u8; 16] {
         self.inner.s6_addr
index babc854cd1d333e8dcf136197ada43dad24bdc3f..17581f330266dc7394f8b3c42138becb861816a6 100644 (file)
@@ -20,6 +20,14 @@ fn test_from_str_ipv4() {
     // no number between dots
     let none: Option<Ipv4Addr> = "255.0..1".parse().ok();
     assert_eq!(None, none);
+    // octal
+    let none: Option<Ipv4Addr> = "255.0.0.01".parse().ok();
+    assert_eq!(None, none);
+    // octal zero
+    let none: Option<Ipv4Addr> = "255.0.0.00".parse().ok();
+    assert_eq!(None, none);
+    let none: Option<Ipv4Addr> = "255.0.00.0".parse().ok();
+    assert_eq!(None, none);
 }
 
 #[test]
index 88a8cb76befbf61b794cbf994efa6cbeefafa964..4e16a55edece26a1b71d9acf7578d712d8efa0ca 100644 (file)
@@ -111,10 +111,12 @@ fn read_number<T: ReadNumberHelper>(
         &mut self,
         radix: u32,
         max_digits: Option<usize>,
+        allow_zero_prefix: bool,
     ) -> Option<T> {
         self.read_atomically(move |p| {
             let mut result = T::ZERO;
             let mut digit_count = 0;
+            let has_leading_zero = p.peek_char() == Some('0');
 
             while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) {
                 result = result.checked_mul(radix)?;
@@ -127,7 +129,13 @@ fn read_number<T: ReadNumberHelper>(
                 }
             }
 
-            if digit_count == 0 { None } else { Some(result) }
+            if digit_count == 0 {
+                None
+            } else if !allow_zero_prefix && has_leading_zero && digit_count > 1 {
+                None
+            } else {
+                Some(result)
+            }
         })
     }
 
@@ -140,10 +148,7 @@ fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> {
                 *slot = p.read_separator('.', i, |p| {
                     // Disallow octal number in IP string.
                     // https://tools.ietf.org/html/rfc6943#section-3.1.1
-                    match (p.peek_char(), p.read_number(10, None)) {
-                        (Some('0'), Some(number)) if number != 0 => None,
-                        (_, number) => number,
-                    }
+                    p.read_number(10, Some(3), false)
                 })?;
             }
 
@@ -175,7 +180,7 @@ fn read_groups(p: &mut Parser<'_>, groups: &mut [u16]) -> (usize, bool) {
                     }
                 }
 
-                let group = p.read_separator(':', i, |p| p.read_number(16, Some(4)));
+                let group = p.read_separator(':', i, |p| p.read_number(16, Some(4), true));
 
                 match group {
                     Some(g) => *slot = g,
@@ -227,7 +232,7 @@ fn read_ip_addr(&mut self) -> Option<IpAddr> {
     fn read_port(&mut self) -> Option<u16> {
         self.read_atomically(|p| {
             p.read_given_char(':')?;
-            p.read_number(10, None)
+            p.read_number(10, None, true)
         })
     }
 
@@ -235,7 +240,7 @@ fn read_port(&mut self) -> Option<u16> {
     fn read_scope_id(&mut self) -> Option<u32> {
         self.read_atomically(|p| {
             p.read_given_char('%')?;
-            p.read_number(10, None)
+            p.read_number(10, None, true)
         })
     }
 
@@ -281,7 +286,12 @@ fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
 impl FromStr for Ipv4Addr {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_ipv4_addr())
+        // don't try to parse if too long
+        if s.len() > 15 {
+            Err(AddrParseError(()))
+        } else {
+            Parser::new(s).parse_with(|p| p.read_ipv4_addr())
+        }
     }
 }
 
index 2c6e3930059905bd94f42b56c2305db7b4a72b2b..5738862fb58b2c7f6d5dc41d5e7926ce9f223e21 100644 (file)
@@ -90,6 +90,7 @@
 /// See its documentation for more.
 ///
 /// [`accept`]: TcpListener::accept
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Debug)]
 pub struct Incoming<'a> {
index 30eeac14b43f5dde525fa633c2a4db89023dcf79..01392ffab79cac81f03288b789efce77ce064de4 100644 (file)
@@ -165,7 +165,14 @@ macro_rules! type_alias {
 #[unstable(feature = "c_size_t", issue = "88345")]
 pub type c_size_t = usize;
 
-/// Equivalent to C's `ssize_t` type, from `stddef.h` (or `cstddef` for C++).
+/// Equivalent to C's `ptrdiff_t` type, from `stddef.h` (or `cstddef` for C++).
+///
+/// This type is currently always [`isize`], however in the future there may be
+/// platforms where this is not the case.
+#[unstable(feature = "c_size_t", issue = "88345")]
+pub type c_ptrdiff_t = isize;
+
+/// Equivalent to C's `ssize_t` (on POSIX) or `SSIZE_T` (on Windows) type.
 ///
 /// This type is currently always [`isize`], however in the future there may be
 /// platforms where this is not the case.
index 57bb61903c147964c6d74b08ed6ba788e1c075cb..6e6f5212b4651d934290ffbb4f07216b214be378 100644 (file)
@@ -201,6 +201,7 @@ pub fn set_pid(&mut self, pid: libc::pid_t) {
     }
 
     /// Get the current PID.
+    #[must_use]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn get_pid(&self) -> libc::pid_t {
         self.0.pid
@@ -213,6 +214,7 @@ pub fn set_uid(&mut self, uid: libc::uid_t) {
     }
 
     /// Get the current UID.
+    #[must_use]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn get_uid(&self) -> libc::uid_t {
         self.0.uid
@@ -225,6 +227,7 @@ pub fn set_gid(&mut self, gid: libc::gid_t) {
     }
 
     /// Get the current GID.
+    #[must_use]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn get_gid(&self) -> libc::gid_t {
         self.0.gid
@@ -330,6 +333,7 @@ fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> {
 }
 
 /// This struct is used to iterate through the control messages.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 pub struct Messages<'a> {
     buffer: &'a [u8],
@@ -425,18 +429,21 @@ pub fn new(buffer: &'a mut [u8]) -> Self {
     }
 
     /// Returns the capacity of the buffer.
+    #[must_use]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn capacity(&self) -> usize {
         self.buffer.len()
     }
 
     /// Returns `true` if the ancillary data is empty.
+    #[must_use]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn is_empty(&self) -> bool {
         self.length == 0
     }
 
     /// Returns the number of used bytes.
+    #[must_use]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn len(&self) -> usize {
         self.length
@@ -471,6 +478,7 @@ pub fn messages(&self) -> Messages<'_> {
     ///     Ok(())
     /// }
     /// ```
+    #[must_use]
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn truncated(&self) -> bool {
         self.truncated
index 97348afe7de12823e7c8e9388c15ac84b0290283..b23dd6062f6822fce6576454ee8ec4ca0e33aaf3 100644 (file)
@@ -365,6 +365,7 @@ fn into_iter(self) -> Incoming<'a> {
 /// }
 /// ```
 #[derive(Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "unix_socket", since = "1.10.0")]
 pub struct Incoming<'a> {
     listener: &'a UnixListener,
index 4d23805e479ba067e4eb5c00dabc13db24566a2a..286a7c3b386f9d79e4d23c7db159242b91cdaa74 100644 (file)
@@ -239,27 +239,27 @@ pub trait ExitStatusExt: Sealed {
     fn signal(&self) -> Option<i32>;
 
     /// If the process was terminated by a signal, says whether it dumped core.
-    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+    #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
     fn core_dumped(&self) -> bool;
 
     /// If the process was stopped by a signal, returns that signal.
     ///
     /// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`.  This is only possible if the status came from
     /// a `wait` system call which was passed `WUNTRACED`, and was then converted into an `ExitStatus`.
-    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+    #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
     fn stopped_signal(&self) -> Option<i32>;
 
     /// Whether the process was continued from a stopped status.
     ///
     /// Ie, `WIFCONTINUED`.  This is only possible if the status came from a `wait` system call
     /// which was passed `WCONTINUED`, and was then converted into an `ExitStatus`.
-    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+    #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
     fn continued(&self) -> bool;
 
     /// Returns the underlying raw `wait` status.
     ///
     /// The returned integer is a **wait status, not an exit status**.
-    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+    #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
     fn into_raw(self) -> i32;
 }
 
@@ -436,6 +436,7 @@ fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd {
 }
 
 /// Returns the OS-assigned process identifier associated with this process's parent.
+#[must_use]
 #[stable(feature = "unix_ppid", since = "1.27.0")]
 pub fn parent_id() -> u32 {
     crate::sys::os::getppid()
index 21e9669c11079718073c402f8d4135859e7ec7f2..c0605b2f4121c098244f40dfd1cb1282d9c17b20 100644 (file)
@@ -25,7 +25,7 @@
         $crate::rt::panic_display(&$arg)
     }),
     ($fmt:expr, $($arg:tt)+) => ({
-        $crate::rt::begin_panic_fmt(&$crate::const_format_args!($fmt, $($arg)+))
+        $crate::rt::panic_fmt($crate::const_format_args!($fmt, $($arg)+))
     }),
 }
 
index 231c9fc19c08a365d3ad0d7e7ffd3bcd240b61e6..6fc6b8daec0a6c76a15100194315271beecfa7ba 100644 (file)
@@ -160,6 +160,7 @@ pub fn set_hook(hook: Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>) {
 ///
 /// panic!("Normal panic");
 /// ```
+#[must_use]
 #[stable(feature = "panic_hooks", since = "1.10.0")]
 pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
     if thread::panicking() {
@@ -284,11 +285,13 @@ pub fn set_always_abort() {
     }
 
     // Disregards ALWAYS_ABORT_FLAG
+    #[must_use]
     pub fn get_count() -> usize {
         LOCAL_PANIC_COUNT.with(|c| c.get())
     }
 
     // Disregards ALWAYS_ABORT_FLAG
+    #[must_use]
     #[inline]
     pub fn count_is_zero() -> bool {
         if GLOBAL_PANIC_COUNT.load(Ordering::Relaxed) & !ALWAYS_ABORT_FLAG == 0 {
@@ -437,31 +440,9 @@ pub fn panicking() -> bool {
     !panic_count::count_is_zero()
 }
 
-/// The entry point for panicking with a formatted message.
-///
-/// This is designed to reduce the amount of code required at the call
-/// site as much as possible (so that `panic!()` has as low an impact
-/// on (e.g.) the inlining of other functions as possible), by moving
-/// the actual formatting into this shared place.
-#[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")]
-#[cold]
-// If panic_immediate_abort, inline the abort call,
-// otherwise avoid inlining because of it is cold path.
-#[cfg_attr(not(feature = "panic_immediate_abort"), track_caller)]
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cfg_attr(not(test), lang = "begin_panic_fmt")]
-pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> ! {
-    if cfg!(feature = "panic_immediate_abort") {
-        intrinsics::abort()
-    }
-
-    let info = PanicInfo::internal_constructor(Some(msg), Location::caller());
-    begin_panic_handler(&info)
-}
-
 /// Entry point of panics from the libcore crate (`panic_impl` lang item).
-#[cfg_attr(not(test), panic_handler)]
+#[cfg(not(test))]
+#[panic_handler]
 pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
     struct PanicPayload<'a> {
         inner: &'a fmt::Arguments<'a>,
@@ -534,7 +515,8 @@ fn get(&mut self) -> &(dyn Any + Send) {
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
 #[cold]
 #[track_caller]
-pub fn begin_panic<M: Any + Send>(msg: M) -> ! {
+#[rustc_do_not_const_check] // hooked by const-eval
+pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
         intrinsics::abort()
     }
index 47156dc33e518d1902c7d3b061927c1a416afffe..dc0c735a06c6f5a4cd502ccc03cb228ea8d6be7a 100644 (file)
@@ -422,6 +422,7 @@ impl<'a> PrefixComponent<'a> {
     /// See [`Prefix`]'s documentation for more information on the different
     /// kinds of prefixes.
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     #[inline]
     pub fn kind(&self) -> Prefix<'a> {
         self.parsed
@@ -583,6 +584,7 @@ fn as_ref(&self) -> &Path {
 ///
 /// [`components`]: Path::components
 #[derive(Clone)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Components<'a> {
     // The path left to parse components from
@@ -609,6 +611,7 @@ pub struct Components<'a> {
 ///
 /// [`iter`]: Path::iter
 #[derive(Clone)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a> {
     inner: Components<'a>,
@@ -1051,6 +1054,7 @@ fn compare_components(mut left: Components<'_>, mut right: Components<'_>) -> cm
 ///
 /// [`ancestors`]: Path::ancestors
 #[derive(Copy, Clone, Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "path_ancestors", since = "1.28.0")]
 pub struct Ancestors<'a> {
     next: Option<&'a Path>,
@@ -1208,6 +1212,9 @@ pub fn as_path(&self) -> &Path {
     /// * if `path` has a root but no prefix (e.g., `\windows`), it
     ///   replaces everything except for the prefix (if any) of `self`.
     /// * if `path` has a prefix but no root, it replaces `self`.
+    /// * if `self` has a verbatim prefix (e.g. `\\?\C:\windows`)
+    ///   and `path` is not empty, the new path is normalized: all references
+    ///   to `.` and `..` are removed.
     ///
     /// # Examples
     ///
@@ -1254,7 +1261,7 @@ fn _push(&mut self, path: &Path) {
             self.as_mut_vec().truncate(0);
 
         // verbatim paths need . and .. removed
-        } else if comps.prefix_verbatim() {
+        } else if comps.prefix_verbatim() && !path.inner.is_empty() {
             let mut buf: Vec<_> = comps.collect();
             for c in path.components() {
                 match c {
@@ -1456,6 +1463,7 @@ pub fn into_boxed_path(self) -> Box<Path> {
     ///
     /// [`capacity`]: OsString::capacity
     #[stable(feature = "path_buf_capacity", since = "1.44.0")]
+    #[must_use]
     #[inline]
     pub fn capacity(&self) -> usize {
         self.inner.capacity()
@@ -2100,6 +2108,7 @@ pub fn has_root(&self) -> bool {
     /// assert_eq!(grand_parent.parent(), None);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     pub fn parent(&self) -> Option<&Path> {
         let mut comps = self.components();
         let comp = comps.next_back();
@@ -2166,6 +2175,7 @@ pub fn ancestors(&self) -> Ancestors<'_> {
     /// assert_eq!(None, Path::new("/").file_name());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     pub fn file_name(&self) -> Option<&OsStr> {
         self.components().next_back().and_then(|p| match p {
             Component::Normal(p) => Some(p),
@@ -2238,6 +2248,7 @@ fn _strip_prefix(&self, base: &Path) -> Result<&Path, StripPrefixError> {
     /// assert!(!Path::new("/etc/foo.rs").starts_with("/etc/foo"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
         self._starts_with(base.as_ref())
     }
@@ -2265,6 +2276,7 @@ fn _starts_with(&self, base: &Path) -> bool {
     /// assert!(!path.ends_with("conf")); // use .extension() instead
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool {
         self._ends_with(child.as_ref())
     }
@@ -2300,6 +2312,7 @@ fn _ends_with(&self, child: &Path) -> bool {
     /// [`Path::file_prefix`]: Path::file_prefix
     ///
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     pub fn file_stem(&self) -> Option<&OsStr> {
         self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.or(after))
     }
@@ -2333,6 +2346,7 @@ pub fn file_stem(&self) -> Option<&OsStr> {
     /// [`Path::file_stem`]: Path::file_stem
     ///
     #[unstable(feature = "path_file_prefix", issue = "86319")]
+    #[must_use]
     pub fn file_prefix(&self) -> Option<&OsStr> {
         self.file_name().map(split_file_at_dot).and_then(|(before, _after)| Some(before))
     }
@@ -2357,6 +2371,7 @@ pub fn file_prefix(&self) -> Option<&OsStr> {
     /// assert_eq!("gz", Path::new("foo.tar.gz").extension().unwrap());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     pub fn extension(&self) -> Option<&OsStr> {
         self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.and(after))
     }
@@ -2400,6 +2415,7 @@ fn _join(&self, path: &Path) -> PathBuf {
     /// assert_eq!(path.with_file_name("var"), PathBuf::from("/var"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
         self._with_file_name(file_name.as_ref())
     }
@@ -2657,6 +2673,7 @@ pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
     /// This is a convenience function that coerces errors to false. If you want to
     /// check errors, call [`fs::metadata`].
     #[stable(feature = "path_ext", since = "1.5.0")]
+    #[must_use]
     #[inline]
     pub fn exists(&self) -> bool {
         fs::metadata(self).is_ok()
@@ -2748,7 +2765,7 @@ pub fn is_dir(&self) -> bool {
         fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
     }
 
-    /// Returns true if the path exists on disk and is pointing at a symbolic link.
+    /// Returns `true` if the path exists on disk and is pointing at a symbolic link.
     ///
     /// This function will not traverse symbolic links.
     /// In case of a broken symbolic link this will also return true.
@@ -2760,7 +2777,6 @@ pub fn is_dir(&self) -> bool {
     ///
     #[cfg_attr(unix, doc = "```no_run")]
     #[cfg_attr(not(unix), doc = "```ignore")]
-    /// #![feature(is_symlink)]
     /// use std::path::Path;
     /// use std::os::unix::fs::symlink;
     ///
@@ -2769,8 +2785,14 @@ pub fn is_dir(&self) -> bool {
     /// assert_eq!(link_path.is_symlink(), true);
     /// assert_eq!(link_path.exists(), false);
     /// ```
-    #[unstable(feature = "is_symlink", issue = "85748")]
+    ///
+    /// # See Also
+    ///
+    /// This is a convenience function that coerces errors to false. If you want to
+    /// check errors, call [`fs::symlink_metadata`] and handle its [`Result`]. Then call
+    /// [`fs::Metadata::is_symlink`] if it was [`Ok`].
     #[must_use]
+    #[stable(feature = "is_symlink", since = "1.57.0")]
     pub fn is_symlink(&self) -> bool {
         fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false)
     }
@@ -2778,6 +2800,7 @@ pub fn is_symlink(&self) -> bool {
     /// Converts a [`Box<Path>`](Box) into a [`PathBuf`] without copying or
     /// allocating.
     #[stable(feature = "into_boxed_path", since = "1.20.0")]
+    #[must_use = "`self` will be dropped if the result is not used"]
     pub fn into_path_buf(self: Box<Path>) -> PathBuf {
         let rw = Box::into_raw(self) as *mut OsStr;
         let inner = unsafe { Box::from_raw(rw) };
index 3973a6829d3d3e42cd9b58f6c37fb7e695d3a168..0a16ff2a721cefcaaf6be6373303296ffd189d15 100644 (file)
@@ -1271,6 +1271,7 @@ macro_rules! tp (
         tp!(r"\\?\A:\x\y", "/foo", r"\\?\A:\foo");
         tp!(r"\\?\A:", r"..\foo\.", r"\\?\A:\foo");
         tp!(r"\\?\A:\x\y", r".\foo\.", r"\\?\A:\x\y\foo");
+        tp!(r"\\?\A:\x\y", r"", r"\\?\A:\x\y\");
     }
 }
 
index 4bd06475e2761510fe681acd80de672683f0e094..9cc7fc2f0352e6e09b2fa7ab9565fc3936bc165a 100644 (file)
@@ -948,6 +948,7 @@ pub fn status(&mut self) -> io::Result<ExitStatus> {
     /// let cmd = Command::new("echo");
     /// assert_eq!(cmd.get_program(), "echo");
     /// ```
+    #[must_use]
     #[stable(feature = "command_access", since = "1.57.0")]
     pub fn get_program(&self) -> &OsStr {
         self.inner.get_program()
@@ -1021,6 +1022,7 @@ pub fn get_envs(&self) -> CommandEnvs<'_> {
     /// cmd.current_dir("/bin");
     /// assert_eq!(cmd.get_current_dir(), Some(Path::new("/bin")));
     /// ```
+    #[must_use]
     #[stable(feature = "command_access", since = "1.57.0")]
     pub fn get_current_dir(&self) -> Option<&Path> {
         self.inner.get_current_dir()
@@ -1053,6 +1055,7 @@ fn as_inner_mut(&mut self) -> &mut imp::Command {
 ///
 /// This struct is created by [`Command::get_args`]. See its documentation for
 /// more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "command_access", since = "1.57.0")]
 #[derive(Debug)]
 pub struct CommandArgs<'a> {
@@ -1183,6 +1186,7 @@ impl Stdio {
     /// its entire stdin before writing more than a pipe buffer's worth of output.
     /// The size of a pipe buffer varies on different targets.
     ///
+    #[must_use]
     #[stable(feature = "process", since = "1.0.0")]
     pub fn piped() -> Stdio {
         Stdio(imp::Stdio::MakePipe)
@@ -1222,6 +1226,7 @@ pub fn piped() -> Stdio {
     /// print!("You piped in the reverse of: ");
     /// io::stdout().write_all(&output.stdout).unwrap();
     /// ```
+    #[must_use]
     #[stable(feature = "process", since = "1.0.0")]
     pub fn inherit() -> Stdio {
         Stdio(imp::Stdio::Inherit)
@@ -1261,6 +1266,7 @@ pub fn inherit() -> Stdio {
     /// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
     /// // Ignores any piped-in input
     /// ```
+    #[must_use]
     #[stable(feature = "process", since = "1.0.0")]
     pub fn null() -> Stdio {
         Stdio(imp::Stdio::Null)
@@ -1462,6 +1468,7 @@ pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
     ///     println!("failed to create 'projects/' directory: {}", status);
     /// }
     /// ```
+    #[must_use]
     #[stable(feature = "process", since = "1.0.0")]
     pub fn success(&self) -> bool {
         self.0.exit_ok().is_ok()
@@ -1493,6 +1500,7 @@ pub fn success(&self) -> bool {
     ///     None       => println!("Process terminated by signal")
     /// }
     /// ```
+    #[must_use]
     #[stable(feature = "process", since = "1.0.0")]
     pub fn code(&self) -> Option<i32> {
         self.0.code()
@@ -1580,6 +1588,7 @@ impl ExitStatusError {
     /// assert_eq!(bad.code(), Some(1));
     /// # } // #[cfg(unix)]
     /// ```
+    #[must_use]
     pub fn code(&self) -> Option<i32> {
         self.code_nonzero().map(Into::into)
     }
@@ -1605,11 +1614,13 @@ pub fn code(&self) -> Option<i32> {
     /// assert_eq!(bad.code_nonzero().unwrap(), NonZeroI32::try_from(1).unwrap());
     /// # } // cfg!(unix)
     /// ```
+    #[must_use]
     pub fn code_nonzero(&self) -> Option<NonZeroI32> {
         self.0.code()
     }
 
     /// Converts an `ExitStatusError` (back) to an `ExitStatus`.
+    #[must_use]
     pub fn into_status(&self) -> ExitStatus {
         ExitStatus(self.0.into())
     }
@@ -1718,6 +1729,7 @@ pub fn kill(&mut self) -> io::Result<()> {
     ///     println!("ls command didn't start");
     /// }
     /// ```
+    #[must_use]
     #[stable(feature = "process_id", since = "1.3.0")]
     pub fn id(&self) -> u32 {
         self.handle.id()
@@ -1988,6 +2000,7 @@ pub fn abort() -> ! {
 /// ```
 ///
 ///
+#[must_use]
 #[stable(feature = "getpid", since = "1.26.0")]
 pub fn id() -> u32 {
     crate::sys::os::getpid()
index 4d72aff011684c8c2efe874ce0e1105e405ef4e0..08e58257572b24fcfddeb1a18be409b6b124c8a6 100644 (file)
@@ -19,8 +19,8 @@
 use crate::ffi::CString;
 
 // Re-export some of our utilities which are expected by other crates.
-pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count};
-pub use core::panicking::panic_display;
+pub use crate::panicking::{begin_panic, panic_count};
+pub use core::panicking::{panic_display, panic_fmt};
 
 use crate::sync::Once;
 use crate::sys;
@@ -128,8 +128,7 @@ fn lang_start_internal(
     let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
         .map_err(move |e| {
             mem::forget(e);
-            rtprintpanic!("drop of the panic payload panicked");
-            sys::abort_internal()
+            rtabort!("drop of the panic payload panicked");
         });
     panic::catch_unwind(cleanup).map_err(rt_abort)?;
     ret_code
index 133c3e46cd8a66a997638a477a714e48169114fd..11836b7b694b38fd06043ca542b23ceb0244835f 100644 (file)
@@ -130,7 +130,7 @@ pub fn wait(&self) -> BarrierWaitResult {
         if lock.count < self.num_threads {
             // We need a while loop to guard against spurious wakeups.
             // https://en.wikipedia.org/wiki/Spurious_wakeup
-            while local_gen == lock.generation_id && lock.count < self.num_threads {
+            while local_gen == lock.generation_id {
                 lock = self.cvar.wait(lock).unwrap();
             }
             BarrierWaitResult(false)
index d8aca9651b8678726b24244920c2dc574badca15..b41918ec1cffc6c1f7613b70da2b4732026b87dc 100644 (file)
@@ -61,6 +61,7 @@ impl WaitTimeoutResult {
     ///     }
     /// }
     /// ```
+    #[must_use]
     #[stable(feature = "wait_timeout", since = "1.5.0")]
     pub fn timed_out(&self) -> bool {
         self.0
index b0842144328a8bfa2f21f11d2f2e338fc5bd04cf..f95b0ddd589ac4b311c4a7d4abfe96c186c80dd0 100644 (file)
@@ -2,10 +2,7 @@
 
 #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[repr(align(64))]
-pub(super) struct Aligner;
-
-#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub(super) struct CacheAligned<T>(pub T, pub Aligner);
+pub(super) struct CacheAligned<T>(pub T);
 
 impl<T> Deref for CacheAligned<T> {
     type Target = T;
@@ -22,6 +19,6 @@ fn deref_mut(&mut self) -> &mut Self::Target {
 
 impl<T> CacheAligned<T> {
     pub(super) fn new(t: T) -> Self {
-        CacheAligned(t, Aligner)
+        CacheAligned(t)
     }
 }
index b4f4456537b9693f41b56df9208e5588ce4f88ab..2cf678ef69b073677b32a32774ba686272a0e4e6 100644 (file)
@@ -707,6 +707,7 @@ fn inner_unsafe(&self) -> &UnsafeCell<Flavor<T>> {
 /// // Let's see what that answer was
 /// println!("{:?}", receiver.recv().unwrap());
 /// ```
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
     let a = Arc::new(oneshot::Packet::new());
@@ -755,6 +756,7 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
 /// assert_eq!(receiver.recv().unwrap(), 1);
 /// assert_eq!(receiver.recv().unwrap(), 2);
 /// ```
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
     let a = Arc::new(sync::Packet::new(bound));
index fa8ef8fc37a95d4ab3a1e4c75bd95346cbb3e042..b62f21a9dac02d705989c77295020fe630da2cc7 100644 (file)
@@ -55,8 +55,20 @@ pub unsafe fn wait(&self, mutex: &Mutex) {
         mutex.lock();
     }
 
-    pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
-        panic!("wait_timeout not supported on hermit");
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+        self.counter.fetch_add(1, SeqCst);
+        mutex.unlock();
+        let millis = dur.as_millis().min(u32::MAX as u128) as u32;
+
+        let res = if millis > 0 {
+            abi::sem_timedwait(self.sem1, millis)
+        } else {
+            abi::sem_trywait(self.sem1)
+        };
+
+        abi::sem_post(self.sem2);
+        mutex.lock();
+        res == 0
     }
 
     pub unsafe fn destroy(&self) {
index 880ef678a4f7a2f704635cbdd35dd863cec37bad..1a6b3bc63e6def5868ab4015a8f021a3560cf40c 100644 (file)
@@ -182,7 +182,7 @@ pub fn duplicate(&self) -> io::Result<TcpStream> {
         Ok(self.clone())
     }
 
-    pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
+    pub fn set_linger(&self, _linger: Option<Duration>) -> io::Result<()> {
         unsupported()
     }
 
index 4feb9c5a6d74047155547994bab0c76fb931fa80..bb9fa54d02ea4174eb596c3df960b4a77540fafd 100644 (file)
@@ -347,6 +347,6 @@ unsafe fn terminate_and_delete_current_task() -> ! {
     unsafe { crate::hint::unreachable_unchecked() };
 }
 
-pub fn available_concurrency() -> io::Result<crate::num::NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<crate::num::NonZeroUsize> {
     super::unsupported()
 }
index db1a2a26a8903c21797fce7449b14749c400aec6..1e8d1137ac8b865f1a8bbb8a74d57baec9ded908 100644 (file)
@@ -6,7 +6,7 @@
 pub use self::imp::init;
 
 pub struct Handler {
-    _data: *mut libc::c_void,
+    data: *mut libc::c_void,
 }
 
 impl Handler {
@@ -15,14 +15,14 @@ pub unsafe fn new() -> Handler {
     }
 
     fn null() -> Handler {
-        Handler { _data: crate::ptr::null_mut() }
+        Handler { data: crate::ptr::null_mut() }
     }
 }
 
 impl Drop for Handler {
     fn drop(&mut self) {
         unsafe {
-            drop_handler(self);
+            drop_handler(self.data);
         }
     }
 }
@@ -134,12 +134,12 @@ pub unsafe fn init() {
         }
 
         let handler = make_handler();
-        MAIN_ALTSTACK.store(handler._data, Ordering::Relaxed);
+        MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed);
         mem::forget(handler);
     }
 
     pub unsafe fn cleanup() {
-        Handler { _data: MAIN_ALTSTACK.load(Ordering::Relaxed) };
+        drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed));
     }
 
     unsafe fn get_stackp() -> *mut libc::c_void {
@@ -176,14 +176,14 @@ pub unsafe fn make_handler() -> Handler {
         if stack.ss_flags & SS_DISABLE != 0 {
             stack = get_stack();
             sigaltstack(&stack, ptr::null_mut());
-            Handler { _data: stack.ss_sp as *mut libc::c_void }
+            Handler { data: stack.ss_sp as *mut libc::c_void }
         } else {
             Handler::null()
         }
     }
 
-    pub unsafe fn drop_handler(handler: &mut Handler) {
-        if !handler._data.is_null() {
+    pub unsafe fn drop_handler(data: *mut libc::c_void) {
+        if !data.is_null() {
             let stack = libc::stack_t {
                 ss_sp: ptr::null_mut(),
                 ss_flags: SS_DISABLE,
@@ -196,7 +196,7 @@ pub unsafe fn drop_handler(handler: &mut Handler) {
             sigaltstack(&stack, ptr::null_mut());
             // We know from `get_stackp` that the alternate stack we installed is part of a mapping
             // that started one page earlier, so walk back a page and unmap from there.
-            munmap(handler._data.sub(page_size()), SIGSTKSZ + page_size());
+            munmap(data.sub(page_size()), SIGSTKSZ + page_size());
         }
     }
 }
@@ -220,5 +220,5 @@ pub unsafe fn make_handler() -> super::Handler {
         super::Handler::null()
     }
 
-    pub unsafe fn drop_handler(_handler: &mut super::Handler) {}
+    pub unsafe fn drop_handler(_data: *mut libc::c_void) {}
 }
index 7dc09add27fd717c7487bd2af781a4c9dc1f7131..824283ef6c41eea84ca6543844632bc3ff4138ee 100644 (file)
@@ -303,6 +303,7 @@ pub const fn zero() -> Instant {
         pub fn actually_monotonic() -> bool {
             (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
                 || (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
+                || (cfg!(target_os = "linux") && cfg!(target_arch = "aarch64"))
                 || cfg!(target_os = "fuchsia")
         }
 
index e5c550802a7abb8000d851d473296a396601eb01..9dfc8114eb596e29ad2079d4efd9d7586bee24f6 100644 (file)
@@ -977,6 +977,12 @@ pub fn CompareStringOrdinal(
         cchCount2: c_int,
         bIgnoreCase: BOOL,
     ) -> c_int;
+    pub fn GetFullPathNameW(
+        lpFileName: LPCWSTR,
+        nBufferLength: DWORD,
+        lpBuffer: LPWSTR,
+        lpFilePart: *mut LPWSTR,
+    ) -> DWORD;
 }
 
 #[link(name = "ws2_32")]
index ad550a823ae90e2596c26614d19c2911bbd953ad..9859000c8d417480f97823bc6c585341d1a92bfc 100644 (file)
@@ -14,6 +14,7 @@
 use crate::sys::{c, cvt};
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 
+use super::path::maybe_verbatim;
 use super::to_u16s;
 
 pub struct File {
@@ -281,7 +282,7 @@ fn get_flags_and_attributes(&self) -> c::DWORD {
 
 impl File {
     pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
-        let path = to_u16s(path)?;
+        let path = maybe_verbatim(path)?;
         let handle = unsafe {
             c::CreateFileW(
                 path.as_ptr(),
@@ -706,7 +707,7 @@ pub fn new() -> DirBuilder {
     }
 
     pub fn mkdir(&self, p: &Path) -> io::Result<()> {
-        let p = to_u16s(p)?;
+        let p = maybe_verbatim(p)?;
         cvt(unsafe { c::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) })?;
         Ok(())
     }
@@ -715,7 +716,7 @@ pub fn mkdir(&self, p: &Path) -> io::Result<()> {
 pub fn readdir(p: &Path) -> io::Result<ReadDir> {
     let root = p.to_path_buf();
     let star = p.join("*");
-    let path = to_u16s(&star)?;
+    let path = maybe_verbatim(&star)?;
 
     unsafe {
         let mut wfd = mem::zeroed();
@@ -733,20 +734,20 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
 }
 
 pub fn unlink(p: &Path) -> io::Result<()> {
-    let p_u16s = to_u16s(p)?;
+    let p_u16s = maybe_verbatim(p)?;
     cvt(unsafe { c::DeleteFileW(p_u16s.as_ptr()) })?;
     Ok(())
 }
 
 pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
-    let old = to_u16s(old)?;
-    let new = to_u16s(new)?;
+    let old = maybe_verbatim(old)?;
+    let new = maybe_verbatim(new)?;
     cvt(unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) })?;
     Ok(())
 }
 
 pub fn rmdir(p: &Path) -> io::Result<()> {
-    let p = to_u16s(p)?;
+    let p = maybe_verbatim(p)?;
     cvt(unsafe { c::RemoveDirectoryW(p.as_ptr()) })?;
     Ok(())
 }
@@ -794,7 +795,7 @@ pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
 
 pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()> {
     let original = to_u16s(original)?;
-    let link = to_u16s(link)?;
+    let link = maybe_verbatim(link)?;
     let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 };
     // Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10
     // Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the
@@ -823,8 +824,8 @@ pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()>
 
 #[cfg(not(target_vendor = "uwp"))]
 pub fn link(original: &Path, link: &Path) -> io::Result<()> {
-    let original = to_u16s(original)?;
-    let link = to_u16s(link)?;
+    let original = maybe_verbatim(original)?;
+    let link = maybe_verbatim(link)?;
     cvt(unsafe { c::CreateHardLinkW(link.as_ptr(), original.as_ptr(), ptr::null_mut()) })?;
     Ok(())
 }
@@ -857,7 +858,7 @@ pub fn lstat(path: &Path) -> io::Result<FileAttr> {
 }
 
 pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
-    let p = to_u16s(p)?;
+    let p = maybe_verbatim(p)?;
     unsafe {
         cvt(c::SetFileAttributesW(p.as_ptr(), perm.attrs))?;
         Ok(())
@@ -900,8 +901,8 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
         }
         c::PROGRESS_CONTINUE
     }
-    let pfrom = to_u16s(from)?;
-    let pto = to_u16s(to)?;
+    let pfrom = maybe_verbatim(from)?;
+    let pto = maybe_verbatim(to)?;
     let mut size = 0i64;
     cvt(unsafe {
         c::CopyFileExW(
index 883690c4831675b2b2c317a78275d87ac7acd9d8..b5209aa690b4c6837a36ac5eb7c569361059c877 100644 (file)
@@ -281,6 +281,10 @@ pub fn temp_dir() -> PathBuf {
 #[cfg(not(target_vendor = "uwp"))]
 fn home_dir_crt() -> Option<PathBuf> {
     unsafe {
+        // The magic constant -4 can be used as the token passed to GetUserProfileDirectoryW below
+        // instead of us having to go through these multiple steps to get a token. However this is
+        // not implemented on Windows 7, only Windows 8 and up. When we drop support for Windows 7
+        // we can simplify this code. See #90144 for details.
         use crate::sys::handle::Handle;
 
         let me = c::GetCurrentProcess();
index b8f512f6a232fc88fdf64fd3b2eb05fa1f3441f6..460c1eff7788d1cfd105002a9c3ab91f004bc6b0 100644 (file)
@@ -1,6 +1,10 @@
+use super::{c, fill_utf16_buf, to_u16s};
 use crate::ffi::OsStr;
+use crate::io;
 use crate::mem;
+use crate::path::Path;
 use crate::path::Prefix;
+use crate::ptr;
 
 #[cfg(test)]
 mod tests;
@@ -141,3 +145,100 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
         None => (path, OsStr::new("")),
     }
 }
+
+/// Returns a UTF-16 encoded path capable of bypassing the legacy `MAX_PATH` limits.
+///
+/// This path may or may not have a verbatim prefix.
+pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
+    // Normally the MAX_PATH is 260 UTF-16 code units (including the NULL).
+    // However, for APIs such as CreateDirectory[1], the limit is 248.
+    //
+    // [1]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createdirectorya#parameters
+    const LEGACY_MAX_PATH: usize = 248;
+    // UTF-16 encoded code points, used in parsing and building UTF-16 paths.
+    // All of these are in the ASCII range so they can be cast directly to `u16`.
+    const SEP: u16 = b'\\' as _;
+    const ALT_SEP: u16 = b'/' as _;
+    const QUERY: u16 = b'?' as _;
+    const COLON: u16 = b':' as _;
+    const DOT: u16 = b'.' as _;
+    const U: u16 = b'U' as _;
+    const N: u16 = b'N' as _;
+    const C: u16 = b'C' as _;
+
+    // \\?\
+    const VERBATIM_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP];
+    // \??\
+    const NT_PREFIX: &[u16] = &[SEP, QUERY, QUERY, SEP];
+    // \\?\UNC\
+    const UNC_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP, U, N, C, SEP];
+
+    let mut path = to_u16s(path)?;
+    if path.starts_with(VERBATIM_PREFIX) || path.starts_with(NT_PREFIX) {
+        // Early return for paths that are already verbatim.
+        return Ok(path);
+    } else if path.len() < LEGACY_MAX_PATH {
+        // Early return if an absolute path is less < 260 UTF-16 code units.
+        // This is an optimization to avoid calling `GetFullPathNameW` unnecessarily.
+        match path.as_slice() {
+            // Starts with `D:`, `D:\`, `D:/`, etc.
+            // Does not match if the path starts with a `\` or `/`.
+            [drive, COLON, 0] | [drive, COLON, SEP | ALT_SEP, ..]
+                if *drive != SEP && *drive != ALT_SEP =>
+            {
+                return Ok(path);
+            }
+            // Starts with `\\`, `//`, etc
+            [SEP | ALT_SEP, SEP | ALT_SEP, ..] => return Ok(path),
+            _ => {}
+        }
+    }
+
+    // Firstly, get the absolute path using `GetFullPathNameW`.
+    // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
+    let lpfilename = path.as_ptr();
+    fill_utf16_buf(
+        // SAFETY: `fill_utf16_buf` ensures the `buffer` and `size` are valid.
+        // `lpfilename` is a pointer to a null terminated string that is not
+        // invalidated until after `GetFullPathNameW` returns successfully.
+        |buffer, size| unsafe {
+            // While the docs for `GetFullPathNameW` have the standard note
+            // about needing a `\\?\` path for a long lpfilename, this does not
+            // appear to be true in practice.
+            // See:
+            // https://stackoverflow.com/questions/38036943/getfullpathnamew-and-long-windows-file-paths
+            // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html
+            c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut())
+        },
+        |mut absolute| {
+            path.clear();
+
+            // Secondly, add the verbatim prefix. This is easier here because we know the
+            // path is now absolute and fully normalized (e.g. `/` has been changed to `\`).
+            let prefix = match absolute {
+                // C:\ => \\?\C:\
+                [_, COLON, SEP, ..] => VERBATIM_PREFIX,
+                // \\.\ => \\?\
+                [SEP, SEP, DOT, SEP, ..] => {
+                    absolute = &absolute[4..];
+                    VERBATIM_PREFIX
+                }
+                // Leave \\?\ and \??\ as-is.
+                [SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[],
+                // \\ => \\?\UNC\
+                [SEP, SEP, ..] => {
+                    absolute = &absolute[2..];
+                    UNC_PREFIX
+                }
+                // Anything else we leave alone.
+                _ => &[],
+            };
+
+            path.reserve_exact(prefix.len() + absolute.len() + 1);
+            path.extend_from_slice(prefix);
+            path.extend_from_slice(absolute);
+            path.push(0);
+        },
+    )?;
+    Ok(path)
+}
index 9675da6ff883bd0bbeeec68bf900a44ca9ba8cd4..c6c84519f419cbe750582153d96e906d59e7de69 100644 (file)
@@ -42,3 +42,56 @@ fn test_parse_next_component() {
         (OsStr::new(r"server"), OsStr::new(r"\\\\\\\\\\\\\share"))
     );
 }
+
+#[test]
+fn verbatim() {
+    use crate::path::Path;
+    fn check(path: &str, expected: &str) {
+        let verbatim = maybe_verbatim(Path::new(path)).unwrap();
+        let verbatim = String::from_utf16_lossy(verbatim.strip_suffix(&[0]).unwrap());
+        assert_eq!(&verbatim, expected, "{}", path);
+    }
+
+    // Ensure long paths are correctly prefixed.
+    check(
+        r"C:\Program Files\Rust\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+        r"\\?\C:\Program Files\Rust\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+    );
+    check(
+        r"\\server\share\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+        r"\\?\UNC\server\share\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+    );
+    check(
+        r"\\.\PIPE\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+        r"\\?\PIPE\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+    );
+    // `\\?\` prefixed paths are left unchanged...
+    check(
+        r"\\?\verbatim.\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+        r"\\?\verbatim.\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+    );
+    // But `//?/` is not a verbatim prefix so it will be normalized.
+    check(
+        r"//?/E:/verbatim.\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+        r"\\?\E:\verbatim\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+    );
+
+    // For performance, short absolute paths are left unchanged.
+    check(r"C:\Program Files\Rust", r"C:\Program Files\Rust");
+    check(r"\\server\share", r"\\server\share");
+    check(r"\\.\COM1", r"\\.\COM1");
+
+    // Check that paths of length 247 are converted to verbatim.
+    // This is necessary for `CreateDirectory`.
+    check(
+        r"C:\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+        r"\\?\C:\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+    );
+
+    // Make sure opening a drive will work.
+    check("Z:", "Z:");
+
+    // An empty path or a path that contains null are not valid paths.
+    assert!(maybe_verbatim(Path::new("")).is_err());
+    assert!(maybe_verbatim(Path::new("\0")).is_err());
+}
index 7be13bc4b2bc7cf7edb2653dfc929908af829a9c..25d1c6e8e87c2914908430fd4e92c17d11bb10aa 100644 (file)
@@ -1,4 +1,28 @@
+//! Implements thread-local destructors that are not associated with any
+//! particular data.
+
 #![unstable(feature = "thread_local_internals", issue = "none")]
 #![cfg(target_thread_local)]
 
-pub use crate::sys_common::thread_local_dtor::register_dtor_fallback as register_dtor;
+// Using a per-thread list avoids the problems in synchronizing global state.
+#[thread_local]
+static mut DESTRUCTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
+
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
+    DESTRUCTORS.push((t, dtor));
+}
+
+/// Runs destructors. This should not be called until thread exit.
+pub unsafe fn run_keyless_dtors() {
+    // Drop all the destructors.
+    //
+    // Note: While this is potentially an infinite loop, it *should* be
+    // the case that this loop always terminates because we provide the
+    // guarantee that a TLS key cannot be set after it is flagged for
+    // destruction.
+    while let Some((ptr, dtor)) = DESTRUCTORS.pop() {
+        (dtor)(ptr);
+    }
+    // We're done so free the memory.
+    DESTRUCTORS = Vec::new();
+}
index 0bc511146654b790fbbd6807c29d7ba266e84aa9..ec670238e6f0eaa9ba65ec60687f173d0ebbab6d 100644 (file)
@@ -196,6 +196,8 @@ unsafe fn register_dtor(key: Key, dtor: Dtor) {
 unsafe extern "system" fn on_tls_callback(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID) {
     if dwReason == c::DLL_THREAD_DETACH || dwReason == c::DLL_PROCESS_DETACH {
         run_dtors();
+        #[cfg(target_thread_local)]
+        super::thread_local_dtor::run_keyless_dtors();
     }
 
     // See comments above for what this is doing. Note that we don't need this
index 3d71219756a207bfaba82d9a6a980ef102e6e338..2cd1e29f6c45ddfcc05bb6b93c272e899fee6fca 100644 (file)
@@ -106,6 +106,7 @@ pub fn iter(&self) -> CommandEnvs<'_> {
 /// This struct is created by
 /// [`Command::get_envs`][crate::process::Command::get_envs]. See its
 /// documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "command_access", since = "1.57.0")]
 #[derive(Debug)]
 pub struct CommandEnvs<'a> {
index 9508bd7da594b8853e207b517e089d87bfcc55f6..0629859bd9dcc15bc232b502366bf21512500ff7 100644 (file)
@@ -686,7 +686,7 @@ pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
     }
 }
 
-/// Returns a slice of the given string for the byte range [`begin`..`end`).
+/// Returns a slice of the given string for the byte range \[`begin`..`end`).
 ///
 /// # Panics
 ///
index b2aa500a0fd8fc84f4009b5d207408f486cfa086..2a155ce31173130d028af622c1944985ffb608d8 100644 (file)
@@ -257,6 +257,7 @@ pub const fn require_unstable_const_init_thread_local() {}
 /// [`unwrap`]: crate::result::Result::unwrap
 /// [naming-threads]: ./index.html#naming-threads
 /// [stack-size]: ./index.html#stack-size
+#[must_use = "must eventually spawn the thread"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Debug)]
 pub struct Builder {
@@ -649,6 +650,7 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
 ///
 /// handler.join().unwrap();
 /// ```
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn current() -> Thread {
     thread_info::current_thread().expect(
@@ -737,6 +739,7 @@ pub fn yield_now() {
 ///
 /// [Mutex]: crate::sync::Mutex
 #[inline]
+#[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn panicking() -> bool {
     panicking::panicking()
@@ -1131,6 +1134,7 @@ pub fn unpark(&self) {
     /// assert!(thread::current().id() != other_thread_id);
     /// ```
     #[stable(feature = "thread_id", since = "1.19.0")]
+    #[must_use]
     pub fn id(&self) -> ThreadId {
         self.inner.id
     }
@@ -1173,6 +1177,7 @@ pub fn id(&self) -> ThreadId {
     ///
     /// [naming-threads]: ./index.html#naming-threads
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     pub fn name(&self) -> Option<&str> {
         self.cname().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) })
     }
@@ -1360,6 +1365,7 @@ impl<T> JoinHandle<T> {
     /// println!("thread id: {:?}", thread.id());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
     pub fn thread(&self) -> &Thread {
         &self.0.thread
     }
@@ -1401,6 +1407,15 @@ pub fn thread(&self) -> &Thread {
     pub fn join(mut self) -> Result<T> {
         self.0.join()
     }
+
+    /// Checks if the the associated thread is still running its main function.
+    ///
+    /// This might return `false` for a brief moment after the thread's main
+    /// function has returned, but before the thread itself has stopped running.
+    #[unstable(feature = "thread_is_running", issue = "90470")]
+    pub fn is_running(&self) -> bool {
+        Arc::strong_count(&self.0.packet.0) > 1
+    }
 }
 
 impl<T> AsInner<imp::Thread> for JoinHandle<T> {
@@ -1449,6 +1464,10 @@ fn _assert_both<T: Send + Sync>() {}
 /// global state in order to more accurately query the amount of available
 /// parallelism.
 ///
+/// Resource limits can be changed during the runtime of a program, therefore the value is
+/// not cached and instead recomputed every time this function is called. It should not be
+/// called from hot code.
+///
 /// The value returned by this function should be considered a simplified
 /// approximation of the actual amount of parallelism available at any given
 /// time. To get a more detailed or precise overview of the amount of
index 16ad366fc126a3ece82d309c2b36873273ac3228..ca0d88135a5d8ae43fe35edb7654507da6b34bd7 100644 (file)
@@ -2,9 +2,13 @@
 use crate::any::Any;
 use crate::mem;
 use crate::result;
-use crate::sync::mpsc::{channel, Sender};
+use crate::sync::{
+    mpsc::{channel, Sender},
+    Arc, Barrier,
+};
 use crate::thread::{self, ThreadId};
 use crate::time::Duration;
+use crate::time::Instant;
 
 // !!! These tests are dangerous. If something is buggy, they will hang, !!!
 // !!! instead of exiting cleanly. This might wedge the buildbots.       !!!
@@ -46,6 +50,36 @@ fn test_run_basic() {
     rx.recv().unwrap();
 }
 
+#[test]
+fn test_is_running() {
+    let b = Arc::new(Barrier::new(2));
+    let t = thread::spawn({
+        let b = b.clone();
+        move || {
+            b.wait();
+            1234
+        }
+    });
+
+    // Thread is definitely running here, since it's still waiting for the barrier.
+    assert_eq!(t.is_running(), true);
+
+    // Unblock the barrier.
+    b.wait();
+
+    // Now check that t.is_running() becomes false within a reasonable time.
+    let start = Instant::now();
+    while t.is_running() {
+        assert!(start.elapsed() < Duration::from_secs(2));
+        thread::sleep(Duration::from_millis(15));
+    }
+
+    // Joining the thread should not block for a significant time now.
+    let join_time = Instant::now();
+    assert_eq!(t.join().unwrap(), 1234);
+    assert!(join_time.elapsed() < Duration::from_secs(2));
+}
+
 #[test]
 fn test_join_panic() {
     match thread::spawn(move || panic!()).join() {
index 5efd8c9be56333be494db209d4f9e4861b9cd62a..a5e3bd0c29030731aaba4e6cfe7aa16c0575d664 100644 (file)
@@ -239,6 +239,7 @@ impl Instant {
     ///
     /// let now = Instant::now();
     /// ```
+    #[must_use]
     #[stable(feature = "time2", since = "1.8.0")]
     pub fn now() -> Instant {
         let os_now = time::Instant::now();
@@ -268,6 +269,20 @@ pub fn now() -> Instant {
         //
         // To hopefully mitigate the impact of this, a few platforms are
         // excluded as "these at least haven't gone backwards yet".
+        //
+        // While issues have been seen on arm64 platforms the Arm architecture
+        // requires that the counter monotonically increases and that it must
+        // provide a uniform view of system time (e.g. it must not be possible
+        // for a core to recieve a message from another core with a time stamp
+        // and observe time going backwards (ARM DDI 0487G.b D11.1.2). While
+        // there have been a few 64bit SoCs that have bugs which cause time to
+        // not monoticially increase, these have been fixed in the Linux kernel
+        // and we shouldn't penalize all Arm SoCs for those who refuse to
+        // update their kernels:
+        // SUN50I_ERRATUM_UNKNOWN1 - Allwinner A64 / Pine A64 - fixed in 5.1
+        // FSL_ERRATUM_A008585 - Freescale LS2080A/LS1043A - fixed in 4.10
+        // HISILICON_ERRATUM_161010101 - Hisilicon 1610 - fixed in 4.11
+        // ARM64_ERRATUM_858921 - Cortex A73 - fixed in 4.12
         if time::Instant::actually_monotonic() {
             return Instant(os_now);
         }
@@ -292,6 +307,7 @@ pub fn now() -> Instant {
     /// let new_now = Instant::now();
     /// println!("{:?}", new_now.duration_since(now));
     /// ```
+    #[must_use]
     #[stable(feature = "time2", since = "1.8.0")]
     pub fn duration_since(&self, earlier: Instant) -> Duration {
         self.0.checked_sub_instant(&earlier.0).expect("supplied instant is later than self")
@@ -312,6 +328,7 @@ pub fn duration_since(&self, earlier: Instant) -> Duration {
     /// println!("{:?}", new_now.checked_duration_since(now));
     /// println!("{:?}", now.checked_duration_since(new_now)); // None
     /// ```
+    #[must_use]
     #[stable(feature = "checked_duration_since", since = "1.39.0")]
     pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
         self.0.checked_sub_instant(&earlier.0)
@@ -332,6 +349,7 @@ pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
     /// println!("{:?}", new_now.saturating_duration_since(now));
     /// println!("{:?}", now.saturating_duration_since(new_now)); // 0ns
     /// ```
+    #[must_use]
     #[stable(feature = "checked_duration_since", since = "1.39.0")]
     pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
         self.checked_duration_since(earlier).unwrap_or_default()
@@ -356,6 +374,7 @@ pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
     /// sleep(three_secs);
     /// assert!(instant.elapsed() >= three_secs);
     /// ```
+    #[must_use]
     #[stable(feature = "time2", since = "1.8.0")]
     pub fn elapsed(&self) -> Duration {
         Instant::now() - *self
@@ -462,6 +481,7 @@ impl SystemTime {
     ///
     /// let sys_time = SystemTime::now();
     /// ```
+    #[must_use]
     #[stable(feature = "time2", since = "1.8.0")]
     pub fn now() -> SystemTime {
         SystemTime(time::SystemTime::now())
@@ -630,6 +650,7 @@ impl SystemTimeError {
     ///     Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
     /// }
     /// ```
+    #[must_use]
     #[stable(feature = "time2", since = "1.8.0")]
     pub fn duration(&self) -> Duration {
         self.0
index dc44c9346b6ef946be2cf61b92f22aacc5f37d9d..7279925a6d0bef166ad8b044d6b36bad1626afb8 100644 (file)
@@ -48,7 +48,7 @@ fn instant_monotonic_concurrent() -> crate::thread::Result<()> {
 #[test]
 fn instant_elapsed() {
     let a = Instant::now();
-    a.elapsed();
+    let _ = a.elapsed();
 }
 
 #[test]
@@ -93,7 +93,7 @@ fn instant_math_is_associative() {
 #[should_panic]
 fn instant_duration_since_panic() {
     let a = Instant::now();
-    (a - Duration::SECOND).duration_since(a);
+    let _ = (a - Duration::SECOND).duration_since(a);
 }
 
 #[test]
index e2aebee916d0eae7bb4f1364fec83f62660141fa..fa23cf2689671c14d8b7da1e14225bd8334d19d1 100644 (file)
@@ -55,8 +55,8 @@ fn write_result(
         _stdout: &[u8],
         _state: &ConsoleTestState,
     ) -> io::Result<()> {
-        // Because the testsuit node holds some of the information as attributes, we can't write it
-        // until all of the tests has ran. Instead of writting every result as they come in, we add
+        // Because the testsuite node holds some of the information as attributes, we can't write it
+        // until all of the tests have finished. Instead of writing every result as they come in, we add
         // them to a Vec and write them all at once when run is complete.
         let duration = exec_time.map(|t| t.0).unwrap_or_default();
         self.results.push((desc.clone(), result.clone(), duration));
index e263780bf38796dbdae16e73b90bb8774edf39eb..079626f0fea54c38755fbc1a7be8af9918890643 100644 (file)
@@ -5,7 +5,6 @@
 #![feature(native_link_modifiers_bundle)]
 #![feature(nll)]
 #![feature(staged_api)]
-#![feature(static_nobundle)]
 #![feature(c_unwind)]
 #![cfg_attr(not(target_env = "msvc"), feature(libc))]
 
index ac8bbfe102dfea63efb4f7491c99946f06cc4046..ed53a98e9a53f69967796a0da077cb4c10d139db 100644 (file)
@@ -146,7 +146,7 @@ fn main() {
     }
 
     let is_test = args.iter().any(|a| a == "--test");
-    if verbose > 1 {
+    if verbose > 2 {
         let rust_env_vars =
             env::vars().filter(|(k, _)| k.starts_with("RUST") || k.starts_with("CARGO"));
         let prefix = if is_test { "[RUSTC-SHIM] rustc --test" } else { "[RUSTC-SHIM] rustc" };
index 0170be967e1e307c2410a53a77f1a719eda247e2..38d3c7aec4941f5bfe12c1c7957a9eb93f9d5044 100644 (file)
@@ -492,10 +492,11 @@ class RustBuild(object):
 
     def downloading_llvm(self):
         opt = self.get_toml('download-ci-llvm', 'llvm')
-        # This is currently all tier 1 targets (since others may not have CI
-        # artifacts)
+        # This is currently all tier 1 targets and tier 2 targets with host tools
+        # (since others may not have CI artifacts)
         # https://doc.rust-lang.org/rustc/platform-support.html#tier-1
         supported_platforms = [
+            # tier 1
             "aarch64-unknown-linux-gnu",
             "i686-pc-windows-gnu",
             "i686-pc-windows-msvc",
@@ -504,6 +505,26 @@ class RustBuild(object):
             "x86_64-apple-darwin",
             "x86_64-pc-windows-gnu",
             "x86_64-pc-windows-msvc",
+            # tier 2 with host tools
+            "aarch64-apple-darwin",
+            "aarch64-pc-windows-msvc",
+            "aarch64-unknown-linux-musl",
+            "arm-unknown-linux-gnueabi",
+            "arm-unknown-linux-gnueabihf",
+            "armv7-unknown-linux-gnueabihf",
+            "mips-unknown-linux-gnu",
+            "mips64-unknown-linux-gnuabi64",
+            "mips64el-unknown-linux-gnuabi64",
+            "mipsel-unknown-linux-gnu",
+            "powerpc-unknown-linux-gnu",
+            "powerpc64-unknown-linux-gnu",
+            "powerpc64le-unknown-linux-gnu",
+            "riscv64gc-unknown-linux-gnu",
+            "s390x-unknown-linux-gnu",
+            "x86_64-unknown-freebsd",
+            "x86_64-unknown-illumos",
+            "x86_64-unknown-linux-musl",
+            "x86_64-unknown-netbsd",
         ]
         return opt == "true" \
             or (opt == "if-available" and self.build in supported_platforms)
@@ -959,7 +980,7 @@ class RustBuild(object):
                 self.cargo()))
         args = [self.cargo(), "build", "--manifest-path",
                 os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")]
-        for _ in range(1, self.verbose):
+        for _ in range(0, self.verbose):
             args.append("--verbose")
         if self.use_locked_deps:
             args.append("--locked")
@@ -1005,7 +1026,15 @@ class RustBuild(object):
         if self.git_version >= distutils.version.LooseVersion("2.11.0"):
             update_args.append("--progress")
         update_args.append(module)
-        run(update_args, cwd=self.rust_root, verbose=self.verbose, exception=True)
+        try:
+            run(update_args, cwd=self.rust_root, verbose=self.verbose, exception=True)
+        except RuntimeError:
+            print("Failed updating submodule. This is probably due to uncommitted local changes.")
+            print('Either stash the changes by running "git stash" within the submodule\'s')
+            print('directory, reset them by running "git reset --hard", or commit them.')
+            print("To reset all submodules' changes run", end=" ")
+            print('"git submodule foreach --recursive git reset --hard".')
+            raise SystemExit(1)
 
         run(["git", "reset", "-q", "--hard"],
             cwd=module_path, verbose=self.verbose)
index 6750f7a549dd6d338b027f223d87ff39f5eea916..6ba1b1b6036eae55f1ae9d78095f0dedf89e3ee0 100644 (file)
@@ -482,6 +482,7 @@ macro_rules! describe {
                 doc::RustByExample,
                 doc::RustcBook,
                 doc::CargoBook,
+                doc::Clippy,
                 doc::EmbeddedBook,
                 doc::EditionGuide,
             ),
@@ -972,8 +973,26 @@ pub fn cargo(
             }
         }
 
-        if self.config.rust_new_symbol_mangling {
+        let use_new_symbol_mangling = match self.config.rust_new_symbol_mangling {
+            Some(setting) => {
+                // If an explicit setting is given, use that
+                setting
+            }
+            None => {
+                if mode == Mode::Std {
+                    // The standard library defaults to the legacy scheme
+                    false
+                } else {
+                    // The compiler and tools default to the new scheme
+                    true
+                }
+            }
+        };
+
+        if use_new_symbol_mangling {
             rustflags.arg("-Zsymbol-mangling-version=v0");
+        } else {
+            rustflags.arg("-Zsymbol-mangling-version=legacy");
         }
 
         // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
@@ -1483,7 +1502,7 @@ pub fn cargo(
             cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1");
         }
 
-        for _ in 1..self.verbosity {
+        for _ in 0..self.verbosity {
             cargo.arg("-v");
         }
 
index e9cc7662e6397a9b8bd9c5b2a0392cd4f9115194..007ca9f7f5a92f6431d3025767576f58427b3b4f 100644 (file)
@@ -197,7 +197,7 @@ fn copy_self_contained_objects(
     t!(fs::create_dir_all(&libdir_self_contained));
     let mut target_deps = vec![];
 
-    // Copies the CRT objects.
+    // Copies the libc and CRT objects.
     //
     // rustc historically provides a more self-contained installation for musl targets
     // not requiring the presence of a native musl toolchain. For example, it can fall back
@@ -208,7 +208,7 @@ fn copy_self_contained_objects(
         let srcdir = builder.musl_libdir(target).unwrap_or_else(|| {
             panic!("Target {:?} does not have a \"musl-libdir\" key", target.triple)
         });
-        for &obj in &["crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
+        for &obj in &["libc.a", "crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
             copy_and_stamp(
                 builder,
                 &libdir_self_contained,
@@ -235,7 +235,7 @@ fn copy_self_contained_objects(
                 panic!("Target {:?} does not have a \"wasi-root\" key", target.triple)
             })
             .join("lib/wasm32-wasi");
-        for &obj in &["crt1-command.o", "crt1-reactor.o"] {
+        for &obj in &["libc.a", "crt1-command.o", "crt1-reactor.o"] {
             copy_and_stamp(
                 builder,
                 &libdir_self_contained,
index e658d958d0a26970895091a507d8fb7010f8545d..68e20f90b7fa4e3043193721d5f832d335c9b69a 100644 (file)
@@ -90,6 +90,7 @@ pub struct Config {
     // llvm codegen options
     pub llvm_skip_rebuild: bool,
     pub llvm_assertions: bool,
+    pub llvm_tests: bool,
     pub llvm_plugins: bool,
     pub llvm_optimize: bool,
     pub llvm_thin_lto: bool,
@@ -140,7 +141,7 @@ pub struct Config {
     pub rust_verify_llvm_ir: bool,
     pub rust_thin_lto_import_instr_limit: Option<u32>,
     pub rust_remap_debuginfo: bool,
-    pub rust_new_symbol_mangling: bool,
+    pub rust_new_symbol_mangling: Option<bool>,
     pub rust_profile_use: Option<String>,
     pub rust_profile_generate: Option<String>,
     pub llvm_profile_use: Option<String>,
@@ -422,6 +423,7 @@ struct Llvm {
     thin_lto: Option<bool>,
     release_debuginfo: Option<bool>,
     assertions: Option<bool>,
+    tests: Option<bool>,
     plugins: Option<bool>,
     ccache: Option<StringOrBool>,
     version_check: Option<bool>,
@@ -715,6 +717,7 @@ pub fn parse(args: &[String]) -> Config {
         // Store off these values as options because if they're not provided
         // we'll infer default values for them later
         let mut llvm_assertions = None;
+        let mut llvm_tests = None;
         let mut llvm_plugins = None;
         let mut debug = None;
         let mut debug_assertions = None;
@@ -740,6 +743,7 @@ pub fn parse(args: &[String]) -> Config {
             }
             set(&mut config.ninja_in_file, llvm.ninja);
             llvm_assertions = llvm.assertions;
+            llvm_tests = llvm.tests;
             llvm_plugins = llvm.plugins;
             llvm_skip_rebuild = llvm_skip_rebuild.or(llvm.skip_rebuild);
             set(&mut config.llvm_optimize, llvm.optimize);
@@ -765,10 +769,12 @@ pub fn parse(args: &[String]) -> Config {
             config.llvm_from_ci = match llvm.download_ci_llvm {
                 Some(StringOrBool::String(s)) => {
                     assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s);
-                    // This is currently all tier 1 targets (since others may not have CI artifacts)
+                    // This is currently all tier 1 targets and tier 2 targets with host tools
+                    // (since others may not have CI artifacts)
                     // https://doc.rust-lang.org/rustc/platform-support.html#tier-1
                     // FIXME: this is duplicated in bootstrap.py
                     let supported_platforms = [
+                        // tier 1
                         "aarch64-unknown-linux-gnu",
                         "i686-pc-windows-gnu",
                         "i686-pc-windows-msvc",
@@ -777,6 +783,26 @@ pub fn parse(args: &[String]) -> Config {
                         "x86_64-apple-darwin",
                         "x86_64-pc-windows-gnu",
                         "x86_64-pc-windows-msvc",
+                        // tier 2 with host tools
+                        "aarch64-apple-darwin",
+                        "aarch64-pc-windows-msvc",
+                        "aarch64-unknown-linux-musl",
+                        "arm-unknown-linux-gnueabi",
+                        "arm-unknown-linux-gnueabihf",
+                        "armv7-unknown-linux-gnueabihf",
+                        "mips-unknown-linux-gnu",
+                        "mips64-unknown-linux-gnuabi64",
+                        "mips64el-unknown-linux-gnuabi64",
+                        "mipsel-unknown-linux-gnu",
+                        "powerpc-unknown-linux-gnu",
+                        "powerpc64-unknown-linux-gnu",
+                        "powerpc64le-unknown-linux-gnu",
+                        "riscv64gc-unknown-linux-gnu",
+                        "s390x-unknown-linux-gnu",
+                        "x86_64-unknown-freebsd",
+                        "x86_64-unknown-illumos",
+                        "x86_64-unknown-linux-musl",
+                        "x86_64-unknown-netbsd",
                     ];
                     supported_platforms.contains(&&*config.build.triple)
                 }
@@ -848,7 +874,7 @@ pub fn parse(args: &[String]) -> Config {
             config.rust_run_dsymutil = rust.run_dsymutil.unwrap_or(false);
             optimize = rust.optimize;
             ignore_git = rust.ignore_git;
-            set(&mut config.rust_new_symbol_mangling, rust.new_symbol_mangling);
+            config.rust_new_symbol_mangling = rust.new_symbol_mangling;
             set(&mut config.rust_optimize_tests, rust.optimize_tests);
             set(&mut config.codegen_tests, rust.codegen_tests);
             set(&mut config.rust_rpath, rust.rpath);
@@ -969,6 +995,7 @@ pub fn parse(args: &[String]) -> Config {
 
         config.llvm_skip_rebuild = llvm_skip_rebuild.unwrap_or(false);
         config.llvm_assertions = llvm_assertions.unwrap_or(false);
+        config.llvm_tests = llvm_tests.unwrap_or(false);
         config.llvm_plugins = llvm_plugins.unwrap_or(false);
         config.rust_optimize = optimize.unwrap_or(true);
 
index 6f2470b706a64ff8d16b979376181196ce976230..2804e7119fbc14e8418365082bb879b22861d299 100644 (file)
@@ -755,6 +755,7 @@ fn run(self, builder: &Builder<'_>) {
     "src/tools/rustfmt",
     ["rustfmt-nightly", "rustfmt-config_proc_macro"],
 );
+tool_doc!(Clippy, "clippy", "src/tools/clippy", ["clippy_utils"]);
 
 #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct ErrorIndex {
index 2d4e15278972469bacd9de44c1b11b34fcaf39f5..3b3c8a9227d95f4c98f76ddf150867eeff761d75 100644 (file)
@@ -277,7 +277,6 @@ pub struct Build {
 struct Crate {
     name: Interned<String>,
     deps: HashSet<Interned<String>>,
-    id: String,
     path: PathBuf,
 }
 
index a38391c7b88f28f31125681682e41bc4441e1d76..65e229697dc87aba4e5627c09f4d6352b344a5df 100644 (file)
@@ -14,7 +14,6 @@ struct Output {
 
 #[derive(Deserialize)]
 struct Package {
-    id: String,
     name: String,
     source: Option<String>,
     manifest_path: String,
@@ -50,7 +49,7 @@ pub fn build(build: &mut Build) {
                 .filter(|dep| dep.source.is_none())
                 .map(|dep| INTERNER.intern_string(dep.name))
                 .collect();
-            build.crates.insert(name, Crate { name, id: package.id, deps, path });
+            build.crates.insert(name, Crate { name, deps, path });
         }
     }
 }
index 27c9bb2504f6d2bdb030f5ee7725ad63f4a783b6..37578e30f6d0f698a4185ac5d23e0c410c5a063c 100644 (file)
@@ -170,6 +170,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 
         let assertions = if builder.config.llvm_assertions { "ON" } else { "OFF" };
         let plugins = if builder.config.llvm_plugins { "ON" } else { "OFF" };
+        let enable_tests = if builder.config.llvm_tests { "ON" } else { "OFF" };
 
         cfg.out_dir(&out_dir)
             .profile(profile)
@@ -180,7 +181,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .define("LLVM_INCLUDE_EXAMPLES", "OFF")
             .define("LLVM_INCLUDE_DOCS", "OFF")
             .define("LLVM_INCLUDE_BENCHMARKS", "OFF")
-            .define("LLVM_INCLUDE_TESTS", "OFF")
+            .define("LLVM_INCLUDE_TESTS", enable_tests)
             .define("LLVM_ENABLE_TERMINFO", "OFF")
             .define("LLVM_ENABLE_LIBEDIT", "OFF")
             .define("LLVM_ENABLE_BINDINGS", "OFF")
@@ -377,11 +378,11 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
     let version = output(cmd.arg("--version"));
     let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
     if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) {
-        if major >= 10 {
+        if major >= 12 {
             return;
         }
     }
-    panic!("\n\nbad LLVM version: {}, need >=10.0\n\n", version)
+    panic!("\n\nbad LLVM version: {}, need >=12.0\n\n", version)
 }
 
 fn configure_cmake(
index e04f6409f54feb94ccac38ac2ee32464a4e5722a..07dcb9ea928f82bd9290f940f236ef9d08228448 100644 (file)
@@ -40,3 +40,4 @@ ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS
 # running with assertions again is not useful
 ENV NO_DEBUG_ASSERTIONS=1
 ENV NO_LLVM_ASSERTIONS=1
+ENV NO_OVERFLOW_CHECKS=1
index 63836654293f222908ada9a651c0f8f5b238129e..2b4b78e81350d5dd396e62e038781a837b3c308c 100644 (file)
@@ -1,3 +1,15 @@
+# We need recent curl, OpenSSL and CA certificates, so we can download further
+# dependencies in the debian:6 image. We use an ubuntu 20.04 image download
+# those.
+FROM ubuntu:20.04
+RUN apt-get update && \
+    apt-get install -y --no-install-recommends \
+        curl \
+        ca-certificates
+WORKDIR /tmp
+COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/
+RUN ./download-openssl-curl.sh
+
 # We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other
 # distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and
 # SLES 11 SP4 (glibc 2.11, kernel 3.0).
@@ -14,8 +26,6 @@ RUN apt-get update && \
     apt-get install --allow-unauthenticated -y --no-install-recommends \
       automake \
       bzip2 \
-      ca-certificates \
-      curl \
       file \
       g++ \
       g++-multilib \
@@ -34,11 +44,6 @@ RUN apt-get update && \
       xz-utils \
       zlib1g-dev
 
-# Install new Let's Encrypt root CA certificate and remove the expired one.
-COPY host-x86_64/shared/ISRG_Root_X1.crt /usr/local/share/ca-certificates/ISRG_Root_X1.crt
-RUN sed -i '/mozilla\/DST_Root_CA_X3\.crt/d' /etc/ca-certificates.conf
-RUN /usr/sbin/update-ca-certificates
-
 ENV PATH=/rustroot/bin:$PATH
 ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
 ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
@@ -50,6 +55,7 @@ COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
 # static.rust-lang.org. This'll be used to link into libcurl below (and used
 # later as well), so build a copy of OpenSSL with dynamic libraries into our
 # generic root.
+COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz
 COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/
 RUN ./build-openssl.sh
 
@@ -59,8 +65,13 @@ RUN ./build-openssl.sh
 #
 # Note that we also disable a bunch of optional features of curl that we don't
 # really need.
+COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz
 COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/
-RUN ./build-curl.sh && apt-get remove -y curl
+RUN ./build-curl.sh
+
+# Use up-to-date curl CA bundle
+COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
+ENV CURL_CA_BUNDLE /tmp/cacert.pem
 
 # binutils < 2.22 has a bug where the 32-bit executables it generates
 # immediately segfault in Rust, so we need to install our own binutils.
index 82d0f7dc471e8d95c9ee718e7ccfd917acf7be69..9bd56394eafc6add71473ce3f2f914811d22a051 100755 (executable)
@@ -10,7 +10,7 @@ export PATH=`pwd`/clang+llvm-11.0.1-x86_64-linux-gnu-ubuntu-16.04/bin:$PATH
 git clone https://github.com/WebAssembly/wasi-libc
 
 cd wasi-libc
-git reset --hard 58795582905e08fa7748846c1971b4ab911d1e16
+git reset --hard ad5133410f66b93a2381db5b542aad5e0964db96
 make -j$(nproc) INSTALL_DIR=/wasm32-wasi install
 
 cd ..
index 7b560aaaaa68826af7441aab521281294b78d867..50452349931e84c9321a41512c283581859f9068 100644 (file)
@@ -1,3 +1,15 @@
+# We need recent curl, OpenSSL and CA certificates, so we can download further
+# dependencies in the debian:6 image. We use an ubuntu 20.04 image download
+# those.
+FROM ubuntu:20.04
+RUN apt-get update && \
+    apt-get install -y --no-install-recommends \
+        curl \
+        ca-certificates
+WORKDIR /tmp
+COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/
+RUN ./download-openssl-curl.sh
+
 # We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other
 # distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and
 # SLES 11 SP4 (glibc 2.11, kernel 3.0).
@@ -14,8 +26,6 @@ RUN apt-get update && \
     apt-get install --allow-unauthenticated -y --no-install-recommends \
       automake \
       bzip2 \
-      ca-certificates \
-      curl \
       file \
       g++ \
       g++-multilib \
@@ -34,11 +44,6 @@ RUN apt-get update && \
       xz-utils \
       zlib1g-dev
 
-# Install new Let's Encrypt root CA certificate and remove the expired one.
-COPY host-x86_64/shared/ISRG_Root_X1.crt /usr/local/share/ca-certificates/ISRG_Root_X1.crt
-RUN sed -i '/mozilla\/DST_Root_CA_X3\.crt/d' /etc/ca-certificates.conf
-RUN /usr/sbin/update-ca-certificates
-
 ENV PATH=/rustroot/bin:$PATH
 ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
 ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
@@ -50,6 +55,7 @@ COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
 # static.rust-lang.org. This'll be used to link into libcurl below (and used
 # later as well), so build a copy of OpenSSL with dynamic libraries into our
 # generic root.
+COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz
 COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/
 RUN ./build-openssl.sh
 
@@ -59,8 +65,13 @@ RUN ./build-openssl.sh
 #
 # Note that we also disable a bunch of optional features of curl that we don't
 # really need.
+COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz
 COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/
-RUN ./build-curl.sh && apt-get remove -y curl
+RUN ./build-curl.sh
+
+# Use up-to-date curl CA bundle
+COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
+ENV CURL_CA_BUNDLE /tmp/cacert.pem
 
 # binutils < 2.22 has a bug where the 32-bit executables it generates
 # immediately segfault in Rust, so we need to install our own binutils.
index ed5edfec4e1a6c303b2b7a044db8a1db3bc032c0..562be752f846d5971d2c03f8472d2d3fa63b1390 100755 (executable)
@@ -4,7 +4,7 @@ set -ex
 
 source shared.sh
 
-LLVM=llvmorg-12.0.1
+LLVM=llvmorg-13.0.0
 
 mkdir llvm-project
 cd llvm-project
index 6efa789756619fcaf3e318159da75bf2a1051c9b..88ee96eaa89b579c0a5e4ea56b7c594fb8a4482d 100755 (executable)
@@ -3,18 +3,11 @@
 set -ex
 source shared.sh
 
-VERSION=7.66.0
-
-# This needs to be downloaded directly from S3, it can't go through the CDN.
-# That's because the CDN is backed by CloudFront, which requires SNI and TLSv1
-# (without paying an absurd amount of money).
-curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/curl-$VERSION.tar.xz \
-  | xz --decompress \
-  | tar xf -
+tar xJf curl.tar.xz
 
 mkdir curl-build
 cd curl-build
-hide_output ../curl-$VERSION/configure \
+hide_output ../curl-*/configure \
       --prefix=/rustroot \
       --with-ssl=/rustroot \
       --disable-sspi \
@@ -35,4 +28,4 @@ hide_output make install
 
 cd ..
 rm -rf curl-build
-rm -rf curl-$VERSION
+rm -rf curl-*
index 34bbe19d2fac331cec92db088c24190512273174..b48b5c4c00aae59aa0a11917b46dd7daaf561cc4 100755 (executable)
@@ -3,21 +3,14 @@
 set -ex
 source shared.sh
 
-VERSION=1.0.2k
+tar xzf openssl.tar.gz
 
-# This needs to be downloaded directly from S3, it can't go through the CDN.
-# That's because the CDN is backed by CloudFront, which requires SNI and TLSv1
-# (without paying an absurd amount of money).
-URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/openssl-$VERSION.tar.gz
-
-curl $URL | tar xzf -
-
-cd openssl-$VERSION
+cd openssl-*
 hide_output ./config --prefix=/rustroot shared -fPIC
 hide_output make -j$(nproc)
 hide_output make install
 cd ..
-rm -rf openssl-$VERSION
+rm -rf openssl-*
 
 # Make the system cert collection available to the new install.
 ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh
new file mode 100755 (executable)
index 0000000..ca40a8c
--- /dev/null
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+set -ex
+
+OPENSSL_VERSION=1.0.2k
+CURL_VERSION=7.66.0
+
+curl -f https://ci-mirrors.rust-lang.org/rustc/openssl-$OPENSSL_VERSION.tar.gz -o openssl.tar.gz
+curl -f https://ci-mirrors.rust-lang.org/rustc/curl-$CURL_VERSION.tar.xz -o curl.tar.xz
+curl -f https://curl.se/ca/cacert.pem -o cacert.pem
diff --git a/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt b/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt
deleted file mode 100644 (file)
index b85c803..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
-TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
-cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
-WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
-ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
-MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
-h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
-0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
-A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
-T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
-B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
-B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
-KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
-OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
-jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
-qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
-rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
-HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
-hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
-ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
-3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
-NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
-ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
-TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
-jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
-oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
-4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
-mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
-emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
------END CERTIFICATE-----
index ad0e8e9f92808be5c61765834228032b95175dff..4d4953fa0e2a5655c3aa0c871806cd78dfdb0df8 100644 (file)
@@ -39,6 +39,7 @@ ENV RUST_CONFIGURE_ARGS \
 # otherwise normally be. We already test libstd with debug assertions in lots of
 # other contexts as well
 ENV NO_DEBUG_ASSERTIONS=1
+ENV NO_OVERFLOW_CHECKS=1
 
 ENV WASM_TARGETS=wasm32-unknown-unknown
 ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_TARGETS \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-10/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-10/Dockerfile
deleted file mode 100644 (file)
index c341987..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-FROM ubuntu:18.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  g++ \
-  gcc-multilib \
-  make \
-  ninja-build \
-  file \
-  curl \
-  ca-certificates \
-  python2.7 \
-  git \
-  cmake \
-  sudo \
-  gdb \
-  llvm-10-tools \
-  llvm-10-dev \
-  libedit-dev \
-  libssl-dev \
-  pkg-config \
-  zlib1g-dev \
-  xz-utils \
-  nodejs
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-# using llvm-link-shared due to libffi issues -- see #34486
-ENV RUST_CONFIGURE_ARGS \
-      --build=x86_64-unknown-linux-gnu \
-      --llvm-root=/usr/lib/llvm-10 \
-      --enable-llvm-link-shared \
-      --set rust.thin-lto-import-instr-limit=10
-
-ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \
-           # Run the `mir-opt` tests again but this time for a 32-bit target.
-           # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
-           # both 32-bit and 64-bit outputs updated by the PR author, before
-           # the PR is approved and tested for merging.
-           # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
-           # despite having different output on 32-bit vs 64-bit targets.
-           python2.7 ../x.py --stage 2 test src/test/mir-opt \
-                             --host='' --target=i686-unknown-linux-gnu && \
-           # Run the UI test suite again, but in `--pass=check` mode
-           #
-           # This is intended to make sure that both `--pass=check` continues to
-           # work.
-           #
-           python2.7 ../x.py --stage 2 test src/test/ui --pass=check \
-                             --host='' --target=i686-unknown-linux-gnu && \
-           # Run tidy at the very end, after all the other tests.
-           python2.7 ../x.py --stage 2 test src/tools/tidy
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile
new file mode 100644 (file)
index 0000000..df1fbc2
--- /dev/null
@@ -0,0 +1,53 @@
+FROM ubuntu:20.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  gcc-multilib \
+  make \
+  ninja-build \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  llvm-12-tools \
+  llvm-12-dev \
+  libedit-dev \
+  libssl-dev \
+  pkg-config \
+  zlib1g-dev \
+  xz-utils \
+  nodejs
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+# using llvm-link-shared due to libffi issues -- see #34486
+ENV RUST_CONFIGURE_ARGS \
+      --build=x86_64-unknown-linux-gnu \
+      --llvm-root=/usr/lib/llvm-12 \
+      --enable-llvm-link-shared \
+      --set rust.thin-lto-import-instr-limit=10
+
+ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \
+           # Run the `mir-opt` tests again but this time for a 32-bit target.
+           # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
+           # both 32-bit and 64-bit outputs updated by the PR author, before
+           # the PR is approved and tested for merging.
+           # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
+           # despite having different output on 32-bit vs 64-bit targets.
+           python2.7 ../x.py --stage 2 test src/test/mir-opt \
+                             --host='' --target=i686-unknown-linux-gnu && \
+           # Run the UI test suite again, but in `--pass=check` mode
+           #
+           # This is intended to make sure that both `--pass=check` continues to
+           # work.
+           #
+           python2.7 ../x.py --stage 2 test src/test/ui --pass=check \
+                             --host='' --target=i686-unknown-linux-gnu && \
+           # Run tidy at the very end, after all the other tests.
+           python2.7 ../x.py --stage 2 test src/tools/tidy
index adc970c66d6889f154c1dfe0a0d88d4a7a447ef3..ba4e1ca31148cf0d29e7af3456d05d4281df1f0a 100644 (file)
@@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
 # https://github.com/puppeteer/puppeteer/issues/375
 #
 # We also specify the version in case we need to update it to go around cache limitations.
-RUN npm install -g browser-ui-test@0.4.3 --unsafe-perm=true
+RUN npm install -g browser-ui-test@0.4.5 --unsafe-perm=true
 
 ENV RUST_CONFIGURE_ARGS \
   --build=x86_64-unknown-linux-gnu \
index e42b4748fdc78787cc6b78e4062246e8590cc21d..93b4f435d4db777c66e38c1b8a5bf160dd4e2c28 100755 (executable)
@@ -50,7 +50,8 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
       # Look for all source files involves in the COPY command
       copied_files=/tmp/.docker-copied-files.txt
       rm -f "$copied_files"
-      for i in $(sed -n -e 's/^COPY \(.*\) .*$/\1/p' "$docker_dir/$image/Dockerfile"); do
+      for i in $(sed -n -e '/^COPY --from=/! s/^COPY \(.*\) .*$/\1/p' \
+          "$docker_dir/$image/Dockerfile"); do
         # List the file names
         find "$script_dir/$i" -type f >> $copied_files
       done
@@ -70,8 +71,13 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
       echo "Attempting to download $url"
       rm -f /tmp/rustci_docker_cache
       set +e
-      retry curl -y 30 -Y 10 --connect-timeout 30 -f -L -C - -o /tmp/rustci_docker_cache "$url"
-      loaded_images=$(docker load -i /tmp/rustci_docker_cache | sed 's/.* sha/sha/')
+      retry curl --max-time 600 -y 30 -Y 10 --connect-timeout 30 -f -L -C - \
+        -o /tmp/rustci_docker_cache "$url"
+      echo "Loading images into docker"
+      # docker load sometimes hangs in the CI, so time out after 10 minutes with TERM,
+      # KILL after 12 minutes
+      loaded_images=$(/usr/bin/timeout -k 720 600 docker load -i /tmp/rustci_docker_cache \
+        | sed 's/.* sha/sha/')
       set -e
       echo "Downloaded containers:\n$loaded_images"
     fi
index 70c57e07fdeab7faa5b7f17b277c60f5280bc86c..de6b52a5e001c6265617be41fd0262e30b69df77 100755 (executable)
@@ -53,7 +53,7 @@ files_to_extract=(
 for lib in c cxxrt gcc_s m thr util; do
   files_to_extract=("${files_to_extract[@]}" "./lib/lib${lib}.*" "./usr/lib/lib${lib}.*")
 done
-for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat; do
+for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat kvm; do
   files_to_extract=("${files_to_extract[@]}" "./usr/lib/lib${lib}.*")
 done
 
index c9f8692d41887e1546d32836cece40f546f421cf..fbb3042d0d6ad1683d5365af46ecdcb208e9a7d0 100644 (file)
@@ -153,10 +153,6 @@ x--expand-yaml-anchors--remove:
         run: src/ci/scripts/install-sccache.sh
         <<: *step
 
-      - name: select Xcode
-        run: src/ci/scripts/select-xcode.sh
-        <<: *step
-
       - name: install clang
         run: src/ci/scripts/install-clang.sh
         <<: *step
@@ -288,7 +284,7 @@ jobs:
           - name: mingw-check
             <<: *job-linux-xl
 
-          - name: x86_64-gnu-llvm-10
+          - name: x86_64-gnu-llvm-12
             <<: *job-linux-xl
 
           - name: x86_64-gnu-tools
@@ -435,7 +431,7 @@ jobs:
           - name: x86_64-gnu-distcheck
             <<: *job-linux-xl
 
-          - name: x86_64-gnu-llvm-10
+          - name: x86_64-gnu-llvm-12
             env:
               RUST_BACKTRACE: 1
             <<: *job-linux-xl
@@ -452,14 +448,17 @@ jobs:
           #  macOS Builders  #
           ####################
 
+          # Only generate documentation for x86_64-apple-darwin, not other
+          # tier 2 targets produced by this builder.
           - name: dist-x86_64-apple
             env:
-              SCRIPT: ./x.py dist
+              SCRIPT: ./x.py dist --exclude src/doc --exclude extended && ./x.py dist --target=x86_64-apple-darwin src/doc && ./x.py dist extended
               RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.7
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
+              NO_OVERFLOW_CHECKS: 1
               DIST_REQUIRE_ALL_TOOLS: 1
             <<: *job-macos-xl
 
@@ -471,6 +470,7 @@ jobs:
               MACOSX_DEPLOYMENT_TARGET: 10.7
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
+              NO_OVERFLOW_CHECKS: 1
             <<: *job-macos-xl
 
           - name: x86_64-apple
@@ -482,6 +482,7 @@ jobs:
               MACOSX_STD_DEPLOYMENT_TARGET: 10.7
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
+              NO_OVERFLOW_CHECKS: 1
             <<: *job-macos-xl
 
           # This target only needs to support 11.0 and up as nothing else supports the hardware
@@ -498,12 +499,12 @@ jobs:
                 --set rust.jemalloc
                 --set llvm.ninja=false
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              SELECT_XCODE: /Applications/Xcode_12.2.app
               USE_XCODE_CLANG: 1
               MACOSX_DEPLOYMENT_TARGET: 11.0
               MACOSX_STD_DEPLOYMENT_TARGET: 11.0
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
+              NO_OVERFLOW_CHECKS: 1
               DIST_REQUIRE_ALL_TOOLS: 1
               # Corresponds to 16K page size
               #
@@ -671,7 +672,9 @@ jobs:
     strategy:
       matrix:
         include:
-          - *dist-x86_64-linux
+          - &dist-x86_64-linux
+            name: dist-x86_64-linux
+            <<: *job-linux-xl
 
   master:
     name: master
index e35e3e670cc64c0b23c4d936e3eef1bab0977098..29ef13a60fbc431d08c4ea71a81d71b149cbf45b 100755 (executable)
@@ -4,9 +4,13 @@ set -euxo pipefail
 
 rm -rf /tmp/rustc-pgo
 
+# We collect LLVM profiling information and rustc profiling information in
+# separate phases. This increases build time -- though not by a huge amount --
+# but prevents any problems from arising due to different profiling runtimes
+# being simultaneously linked in.
+
 python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
     --stage 2 library/std \
-    --rust-profile-generate=/tmp/rustc-pgo \
     --llvm-profile-generate
 
 # Profile libcore compilation in opt-level=0 and opt-level=3
@@ -15,6 +19,29 @@ RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
 RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
     --crate-type=lib -Copt-level=3 ../library/core/src/lib.rs
 
+# Merge the profile data we gathered for LLVM
+# Note that this uses the profdata from the clang we used to build LLVM,
+# which likely has a different version than our in-tree clang.
+/rustroot/bin/llvm-profdata \
+    merge -o /tmp/llvm-pgo.profdata ./build/$PGO_HOST/llvm/build/profiles
+
+# Rustbuild currently doesn't support rebuilding LLVM when PGO options
+# change (or any other llvm-related options); so just clear out the relevant
+# directories ourselves.
+rm -r ./build/$PGO_HOST/llvm ./build/$PGO_HOST/lld
+
+# Okay, LLVM profiling is done, switch to rustc PGO.
+
+python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
+    --stage 2 library/std \
+    --rust-profile-generate=/tmp/rustc-pgo
+
+# Profile libcore compilation in opt-level=0 and opt-level=3
+RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
+    --crate-type=lib ../library/core/src/lib.rs
+RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
+    --crate-type=lib -Copt-level=3 ../library/core/src/lib.rs
+
 cp -r /tmp/rustc-perf ./
 chown -R $(whoami): ./rustc-perf
 cd rustc-perf
@@ -46,18 +73,13 @@ cd /checkout/obj
 ./build/$PGO_HOST/llvm/bin/llvm-profdata \
     merge -o /tmp/rustc-pgo.profdata /tmp/rustc-pgo
 
-# Merge the profile data we gathered for LLVM
-# Note that this uses the profdata from the clang we used to build LLVM,
-# which likely has a different version than our in-tree clang.
-/rustroot/bin/llvm-profdata \
-    merge -o /tmp/llvm-pgo.profdata ./build/$PGO_HOST/llvm/build/profiles
-
 # Rustbuild currently doesn't support rebuilding LLVM when PGO options
 # change (or any other llvm-related options); so just clear out the relevant
 # directories ourselves.
 rm -r ./build/$PGO_HOST/llvm ./build/$PGO_HOST/lld
 
-# This produces the actual final set of artifacts.
+# This produces the actual final set of artifacts, using both the LLVM and rustc
+# collected profiling data.
 $@ \
     --rust-profile-use=/tmp/rustc-pgo.profdata \
     --llvm-profile-use=/tmp/llvm-pgo.profdata
index b5019d83af45b426e424dd312d068145761398aa..a21b40cfb779f35465e00e3b1f48517c09cf7318 100755 (executable)
@@ -43,7 +43,7 @@ else
     PYTHON="python2"
 fi
 
-if ! isCI || isCiBranch auto || isCiBranch beta; then
+if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests"
 fi
 
@@ -89,6 +89,11 @@ else
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-debug-assertions"
   fi
 
+  # Same for overflow checks
+  if [ "$NO_OVERFLOW_CHECKS" = "" ]; then
+    RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-overflow-checks"
+  fi
+
   # In general we always want to run tests with LLVM assertions enabled, but not
   # all platforms currently support that, so we have an option to disable.
   if [ "$NO_LLVM_ASSERTIONS" = "" ]; then
diff --git a/src/ci/scripts/select-xcode.sh b/src/ci/scripts/select-xcode.sh
deleted file mode 100755 (executable)
index 3b9c77d..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-# This script selects the Xcode instance to use.
-
-set -euo pipefail
-IFS=$'\n\t'
-
-source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
-
-if isMacOS; then
-    if [[ -s "${SELECT_XCODE-}" ]]; then
-        sudo xcode-select -s "${SELECT_XCODE}"
-    fi
-fi
index eb1282ec444db94055fa9531b6f3f803e86bb382..fd9299792852c9a368cb236748781852f75cdac6 160000 (submodule)
@@ -1 +1 @@
-Subproject commit eb1282ec444db94055fa9531b6f3f803e86bb382
+Subproject commit fd9299792852c9a368cb236748781852f75cdac6
index 270fccd339e5972d9c900e788f197e81a0bcd956..51739471276b1776dea27cf562b974ef07e24685 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 270fccd339e5972d9c900e788f197e81a0bcd956
+Subproject commit 51739471276b1776dea27cf562b974ef07e24685
index 2d66852a27c5d0ec50ae021820d1de22caa2b1bd..358e6a61d5f4f0496d0a81e70cdcd25d05307342 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2d66852a27c5d0ec50ae021820d1de22caa2b1bd
+Subproject commit 358e6a61d5f4f0496d0a81e70cdcd25d05307342
index b5c68b02984f74e99d1f1b332029e05f607e2660..a01d151a7250a540a9cb7ccce5956f020c677c21 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b5c68b02984f74e99d1f1b332029e05f607e2660
+Subproject commit a01d151a7250a540a9cb7ccce5956f020c677c21
index 9a60624fcad0140826c44389571dc622917cd632..27f1ff5e440ef78828b68ab882b98e1b10d9af32 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 9a60624fcad0140826c44389571dc622917cd632
+Subproject commit 27f1ff5e440ef78828b68ab882b98e1b10d9af32
index fba15a46ca8efa97e8a955794724ac7ce27805b8..b06008731af0f7d07cd0614e820c8276dfed1c18 160000 (submodule)
@@ -1 +1 @@
-Subproject commit fba15a46ca8efa97e8a955794724ac7ce27805b8
+Subproject commit b06008731af0f7d07cd0614e820c8276dfed1c18
index 8c41835183797a7a11a3bc4f03a66fa7aee47eb5..c251425d1b7ad34a2d05a38dc03bf66d9fdbca28 100644 (file)
@@ -15,6 +15,7 @@
 - [Platform Support](platform-support.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)
 - [Target Tier Policy](target-tier-policy.md)
 - [Targets](targets/index.md)
     - [Built-in Targets](targets/built-in.md)
index 70df5170b21c1a2fa370b855021ee04a4f3c7331..fa38dd54d60c89bc7730daa6c20b1c501df0d6df 100644 (file)
@@ -123,9 +123,9 @@ equivalent.
   <tr>
    <td>Forward-edge control flow protection
    </td>
-   <td>No
+   <td>Yes
    </td>
-   <td>
+   <td>Nightly
    </td>
   </tr>
   <tr>
@@ -465,24 +465,27 @@ implementations such as [LLVM ControlFlowIntegrity
 commercially available [grsecurity/PaX Reuse Attack Protector
 (RAP)](https://grsecurity.net/rap_faq).
 
-The Rust compiler does not support forward-edge control flow protection on
-Linux<sup id="fnref:6" role="doc-noteref"><a href="#fn:6"
-class="footnote">6</a></sup>. There is work currently ongoing to add support
-for the [sanitizers](https://github.com/google/sanitizers)[40], which may or
-may not include support for LLVM CFI.
+The Rust compiler supports forward-edge control flow protection on nightly
+builds[40]-[41] <sup id="fnref:6" role="doc-noteref"><a href="#fn:6"
+class="footnote">6</a></sup>.
 
 ```text
-$ readelf -s target/release/hello-rust | grep __cfi_init
+$ readelf -s -W target/debug/rust-cfi | grep "\.cfi"
+    12: 0000000000005170    46 FUNC    LOCAL  DEFAULT   14 _RNvCsjaOHoaNjor6_8rust_cfi7add_one.cfi
+    15: 00000000000051a0    16 FUNC    LOCAL  DEFAULT   14 _RNvCsjaOHoaNjor6_8rust_cfi7add_two.cfi
+    17: 0000000000005270   396 FUNC    LOCAL  DEFAULT   14 _RNvCsjaOHoaNjor6_8rust_cfi4main.cfi
+...
 ```
-Fig. 15. Checking if LLVM CFI is enabled for a given binary.
+Fig. 15. Checking if LLVM CFI is enabled for a given binary[41].
 
-The presence of the `__cfi_init` symbol (and references to `__cfi_check`)
-indicates that LLVM CFI (i.e., forward-edge control flow protection) is
-enabled for a given binary. Conversely, the absence of the `__cfi_init`
-symbol (and references to `__cfi_check`) indicates that LLVM CFI is not
-enabled for a given binary (see Fig. 15).
+The presence of symbols suffixed with ".cfi" or the `__cfi_init` symbol (and
+references to `__cfi_check`) indicates that LLVM CFI (i.e., forward-edge control
+flow protection) is enabled for a given binary. Conversely, the absence of
+symbols suffixed with ".cfi" or the `__cfi_init` symbol (and references to
+`__cfi_check`) indicates that LLVM CFI is not enabled for a given binary (see
+Fig. 15).
 
-<small id="fn:6">6\. It supports Control Flow Guard (CFG) on Windows (see
+<small id="fn:6">6\. It also supports Control Flow Guard (CFG) on Windows (see
 <https://github.com/rust-lang/rust/issues/68793>). <a href="#fnref:6"
 class="reversefootnote" role="doc-backlink">↩</a></small>
 
@@ -689,5 +692,8 @@ defaults (unrelated to `READ_IMPLIES_EXEC`).
 39. A. Crichton. “Remove the alloc\_jemalloc crate #55238.” GitHub.
     <https://github.com/rust-lang/rust/pull/55238>.
 
-40. J. Aparicio. 2017. “Tracking issue for sanitizer support #39699.”
-    <https://github.com/rust-lang/rust/issues/39699>.
+40. R. de C Valle. “Tracking Issue for LLVM Control Flow Integrity (CFI) Support
+    for Rust #89653.” GitHub. <https://github.com/rust-lang/rust/issues/89653>.
+
+41. “ControlFlowIntegrity.” The Rust Unstable Book.
+    <https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html#controlflowintegrity>.
index bbeab598f2292870baca8e070388fd632881b592..6b0c336b3c7994f47555de6327d7f7fcd4a89e81 100644 (file)
@@ -285,6 +285,7 @@ target | std | host | notes
 `x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
 `x86_64-unknown-hermit` | ? |  |
 `x86_64-unknown-l4re-uclibc` | ? |  |
+[`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * |  | Freestanding/bare-metal x86_64, softfloat
 `x86_64-unknown-none-hermitkernel` | ? |  | HermitCore kernel
 `x86_64-unknown-none-linuxkernel` | * |  | Linux kernel modules
 `x86_64-unknown-openbsd` | ✓ | ✓ | 64-bit OpenBSD
diff --git a/src/doc/rustc/src/platform-support/x86_64-unknown-none.md b/src/doc/rustc/src/platform-support/x86_64-unknown-none.md
new file mode 100644 (file)
index 0000000..afcc480
--- /dev/null
@@ -0,0 +1,76 @@
+# `x86_64-unknown-none`
+
+**Tier: 3**
+
+Freestanding/bare-metal x86-64 binaries in ELF format: firmware, kernels, etc.
+
+## Target maintainers
+
+- Harald Hoyer `harald@profian.com`, https://github.com/haraldh
+- Mike Leany, https://github.com/mikeleany
+
+## Requirements
+
+This target is cross-compiled. There is no support for `std`. There is no
+default allocator, but it's possible to use `alloc` by supplying an allocator.
+
+By default, Rust code generated for this target does not use any vector or
+floating-point registers (e.g. SSE, AVX). This allows the generated code to run
+in environments, such as kernels, which may need to avoid the use of such
+registers or which may have special considerations about the use of such
+registers (e.g. saving and restoring them to avoid breaking userspace code
+using the same registers). You can change code generation to use additional CPU
+features via the `-C target-feature=` codegen options to rustc, or via the
+`#[target_feature]` mechanism within Rust code.
+
+By default, code generated with this target should run on any `x86_64`
+hardware; enabling additional target features may raise this baseline.
+
+Code generated with this target will use the `kernel` code model by default.
+You can change this using the `-C code-model=` option to rustc.
+
+On `x86_64-unknown-none`, `extern "C"` uses the [standard System V calling
+convention](https://gitlab.com/x86-psABIs/x86-64-ABI), without red zones.
+
+This target generated binaries in the ELF format. Any alternate formats or
+special considerations for binary layout will require linker options or linker
+scripts.
+
+## Building the target
+
+You can build Rust with support for the target by adding it to the `target`
+list in `config.toml`:
+
+```toml
+[build]
+build-stage = 1
+target = ["x86_64-unknown-none"]
+```
+
+## 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
+
+As `x86_64-unknown-none` supports a variety of different environments and does
+not support `std`, this target does not support running the Rust testsuite.
+
+## Cross-compilation toolchains and C code
+
+If you want to compile C code along with Rust (such as for Rust crates with C
+dependencies), you will need an appropriate `x86_64` toolchain.
+
+Rust *may* be able to use an `x86_64-linux-gnu-` toolchain with appropriate
+standalone flags to build for this toolchain (depending on the assumptions of
+that toolchain, see below), or you may wish to use a separate
+`x86_64-unknown-none` (or `x86_64-elf-`) toolchain.
+
+On some `x86_64` hosts that use ELF binaries, you *may* be able to use the host
+C toolchain, if it does not introduce assumptions about the host environment
+that don't match the expectations of a standalone environment. Otherwise, you
+may need a separate toolchain for standalone/freestanding development, just as
+when cross-compiling from a non-`x86_64` platform.
index b17ea7cd8f5974c4bcbf4b1fda006a5b181ecf9e..a75b6d3893128a6205907b856b614968718c6616 100644 (file)
@@ -153,7 +153,9 @@ example, if you want your doctests to fail if they produce any warnings, you cou
 These forms of the `#[doc]` attribute are used on individual items, to control how
 they are documented.
 
-## `#[doc(no_inline)]`/`#[doc(inline)]`
+### `inline` and `no_inline`
+
+<span id="docno_inlinedocinline"></span>
 
 These attributes are used on `use` statements, and control where the documentation shows
 up. For example, consider this Rust code:
@@ -219,7 +221,56 @@ Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere.
 One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will
 not eagerly inline it as a module unless you add `#[doc(inline)]`.
 
-## `#[doc(hidden)]`
+### `hidden`
+
+<span id="dochidden"></span>
 
 Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless
 the `strip-hidden` pass is removed.
+
+### `alias`
+
+This attribute adds an alias in the search index.
+
+Let's take an example:
+
+```rust,no_run
+#[doc(alias = "TheAlias")]
+pub struct SomeType;
+```
+
+So now, if you enter "TheAlias" in the search, it'll display `SomeType`.
+Of course, if you enter `SomeType` it'll return `SomeType` as expected!
+
+#### FFI example
+
+This doc attribute is especially useful when writing bindings for a C library.
+For example, let's say we have a C function that looks like this:
+
+```c
+int lib_name_do_something(Obj *obj);
+```
+
+It takes a pointer to an `Obj` type and returns an integer. In Rust, it might
+be written like this:
+
+```ignore (using non-existing ffi types)
+pub struct Obj {
+    inner: *mut ffi::Obj,
+}
+
+impl Obj {
+    pub fn do_something(&mut self) -> i32 {
+        unsafe { ffi::lib_name_do_something(self.inner) }
+    }
+}
+```
+
+The function has been turned into a method to make it more convenient to use.
+However, if you want to look for the Rust equivalent of `lib_name_do_something`,
+you have no way to do so.
+
+To get around this limitation, we just add `#[doc(alias = "lib_name_do_something")]`
+on the `do_something` method and then it's all good!
+Users can now look for `lib_name_do_something` in our crate directly and find
+`Obj::do_something`.
index 917959976411cf700b4781bfb6d7cc73ed61fb75..b3b6422afab427cc26f749ca5d8b142c711518c7 100644 (file)
@@ -134,9 +134,27 @@ Book][unstable-masked] and [its tracking issue][issue-masked].
 
 ## Document primitives
 
+This is for Rust compiler internal use only.
+
 Since primitive types are defined in the compiler, there's no place to attach documentation
-attributes. The `#[doc(primitive)]` attribute is used by the standard library to provide a way to generate
-documentation for primitive types, and requires `#![feature(doc_primitive)]` to enable.
+attributes. The `#[doc(primitive)]` attribute is used by the standard library to provide a way
+to generate documentation for primitive types, and requires `#![feature(doc_primitive)]` to enable.
+
+## Document keywords
+
+This is for Rust compiler internal use only.
+
+Rust keywords are documented in the standard library (look for `match` for example).
+
+To do so, the `#[doc(keyword = "...")]` attribute is used. Example:
+
+```rust
+#![feature(doc_keyword)]
+
+/// Some documentation about the keyword.
+#[doc(keyword = "keyword")]
+mod empty_mod {}
+```
 
 ## Unstable command-line arguments
 
@@ -455,3 +473,27 @@ Calculating code examples follows these rules:
   * static
   * typedef
 2. If one of the previously listed items has a code example, then it'll be counted.
+
+### `--with-examples`: include examples of uses of items as documentation
+
+This option, combined with `--scrape-examples-target-crate` and
+`--scrape-examples-output-path`, is used to implement the functionality in [RFC
+#3123](https://github.com/rust-lang/rfcs/pull/3123). Uses of an item (currently
+functions / call-sites) are found in a crate and its reverse-dependencies, and
+then the uses are included as documentation for that item. This feature is
+intended to be used via `cargo doc --scrape-examples`, but the rustdoc-only
+workflow looks like:
+
+```bash
+$ rustdoc examples/ex.rs -Z unstable-options \
+    --extern foobar=target/deps/libfoobar.rmeta \
+    --scrape-examples-target-crate foobar \
+    --scrape-examples-output-path output.calls
+$ rustdoc src/lib.rs -Z unstable-options --with-examples output.calls
+```
+
+First, the library must be checked to generate an `rmeta`. Then a
+reverse-dependency like `examples/ex.rs` is given to rustdoc with the target
+crate being documented (`foobar`) and a path to output the calls
+(`output.calls`). Then, the generated calls file can be passed via
+`--with-examples` to the subsequent documentation of `foobar`.
diff --git a/src/doc/unstable-book/src/compiler-flags/location-detail.md b/src/doc/unstable-book/src/compiler-flags/location-detail.md
new file mode 100644 (file)
index 0000000..08d937c
--- /dev/null
@@ -0,0 +1,43 @@
+# `location-detail`
+
+The tracking issue for this feature is: [#70580](https://github.com/rust-lang/rust/issues/70580).
+
+------------------------
+
+Option `-Z location-detail=val` controls what location details are tracked when
+using `caller_location`. This allows users to control what location details
+are printed as part of panic messages, by allowing them to exclude any combination
+of filenames, line numbers, and column numbers. This option is intended to provide
+users with a way to mitigate the size impact of `#[track_caller]`.
+
+This option supports a comma separated list of location details to be included. Valid options
+within this list are:
+
+- `file` - the filename of the panic will be included in the panic output
+- `line` - the source line of the panic will be included in the panic output
+- `column` - the source column of the panic will be included in the panic output
+
+Any combination of these three options are supported. If this option is not specified,
+all three are included by default.
+
+An example of a panic output when using `-Z location-detail=line`:
+```text
+panicked at 'Process blink had a fault', <redacted>:323:0
+```
+
+The code size savings from this option are two-fold. First, the `&'static str` values
+for each path to a file containing a panic are removed from the binary. For projects
+with deep directory structures and many files with panics, this can add up. This category
+of savings can only be realized by excluding filenames from the panic output. Second,
+savings can be realized by allowing multiple panics to be fused into a single panicking
+branch. It is often the case that within a single file, multiple panics with the same
+panic message exist -- e.g. two calls to `Option::unwrap()` in a single line, or
+two calls to `Result::expect()` on adjacent lines. If column and line information
+are included in the `Location` struct passed to the panic handler, these branches cannot
+be fused, as the output is different depending on which panic occurs. However if line
+and column information is identical for all panics, these branches can be fused, which
+can lead to substantial code size savings, especially for small embedded binaries with
+many panics.
+
+The savings from this option are amplified when combined with the use of `-Zbuild-std`, as
+otherwise paths for panics within the standard library are still included in your binary.
diff --git a/src/doc/unstable-book/src/compiler-flags/no-unique-section-names.md b/src/doc/unstable-book/src/compiler-flags/no-unique-section-names.md
new file mode 100644 (file)
index 0000000..5c1c7cd
--- /dev/null
@@ -0,0 +1,9 @@
+# `no-unique-section-names`
+
+------------------------
+
+This flag currently applies only to ELF-based targets using the LLVM codegen backend. It prevents the generation of unique ELF section names for each separate code and data item when `-Z function-sections` is also in use, which is the default for most targets. This option can reduce the size of object files, and depending on the linker, the final ELF binary as well.
+
+For example, a function `func` will by default generate a code section called `.text.func`. Normally this is fine because the linker will merge all those `.text.*` sections into a single one in the binary. However, starting with [LLVM 12](https://github.com/llvm/llvm-project/commit/ee5d1a04), the backend will also generate unique section names for exception handling, so you would see a section name of `.gcc_except_table.func` in the object file and potentially in the final ELF binary, which could add significant bloat to programs that contain many functions.
+
+This flag instructs LLVM to use the same `.text` and `.gcc_except_table` section name for each function, and it is analogous to Clang's `-fno-unique-section-names` option.
index 29a267053b47d109e1f3d68154104701ee802e22..b3dbc9a9956795273b3ec854ef72873681057206 100644 (file)
@@ -1,19 +1,24 @@
 # `sanitizer`
 
-The tracking issue for this feature is: [#39699](https://github.com/rust-lang/rust/issues/39699).
+The tracking issues for this feature are:
+
+* [#39699](https://github.com/rust-lang/rust/issues/39699).
+* [#89653](https://github.com/rust-lang/rust/issues/89653).
 
 ------------------------
 
 This feature allows for use of one of following sanitizers:
 
 * [AddressSanitizer][clang-asan] a fast memory error detector.
+* [ControlFlowIntegrity][clang-cfi] LLVM Control Flow Integrity (CFI) provides
+  forward-edge control flow protection.
 * [HWAddressSanitizer][clang-hwasan] a memory error detector similar to
   AddressSanitizer, but based on partial hardware assistance.
 * [LeakSanitizer][clang-lsan] a run-time memory leak detector.
 * [MemorySanitizer][clang-msan] a detector of uninitialized reads.
 * [ThreadSanitizer][clang-tsan] a fast data race detector.
 
-To enable a sanitizer compile with `-Zsanitizer=address`,
+To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
 `-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory` or
 `-Zsanitizer=thread`.
 
@@ -177,6 +182,176 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
 ==39249==ABORTING
 ```
 
+# ControlFlowIntegrity
+
+The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially
+provides forward-edge control flow protection for Rust-compiled code only by
+aggregating function pointers in groups identified by their number of arguments.
+
+Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed
+binaries" (i.e., for when C or C++ and Rust -compiled code share the same
+virtual address space) will be provided in later work by defining and using
+compatible type identifiers (see Type metadata in the design document in the
+tracking issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
+
+LLVM CFI can be enabled with -Zsanitizer=cfi and requires LTO (i.e., -Clto).
+
+## Example
+
+```text
+#![feature(asm, naked_functions)]
+
+use std::mem;
+
+fn add_one(x: i32) -> i32 {
+    x + 1
+}
+
+#[naked]
+pub extern "C" fn add_two(x: i32) {
+    // x + 2 preceeded by a landing pad/nop block
+    unsafe {
+        asm!(
+            "
+             nop
+             nop
+             nop
+             nop
+             nop
+             nop
+             nop
+             nop
+             nop
+             lea rax, [rdi+2]
+             ret
+        ",
+            options(noreturn)
+        );
+    }
+}
+
+fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
+    f(arg) + f(arg)
+}
+
+fn main() {
+    let answer = do_twice(add_one, 5);
+
+    println!("The answer is: {}", answer);
+
+    println!("With CFI enabled, you should not see the next answer");
+    let f: fn(i32) -> i32 = unsafe {
+        // Offsets 0-8 make it land in the landing pad/nop block, and offsets 1-8 are
+        // invalid branch/call destinations (i.e., within the body of the function).
+        mem::transmute::<*const u8, fn(i32) -> i32>((add_two as *const u8).offset(5))
+    };
+    let next_answer = do_twice(f, 5);
+
+    println!("The next answer is: {}", next_answer);
+}
+```
+Fig. 1. Modified example from the [Advanced Functions and
+Closures][rust-book-ch19-05] chapter of the [The Rust Programming
+Language][rust-book] book.
+
+[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
+
+```shell
+$ rustc rust_cfi.rs -o rust_cfi
+$ ./rust_cfi
+The answer is: 12
+With CFI enabled, you should not see the next answer
+The next answer is: 14
+$
+```
+Fig. 2. Build and execution of the modified example with LLVM CFI disabled.
+
+[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
+
+```shell
+$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi
+$ ./rust_cfi
+The answer is: 12
+With CFI enabled, you should not see the next answer
+Illegal instruction
+$
+```
+Fig. 3. Build and execution of the modified example with LLVM CFI enabled.
+
+When LLVM CFI is enabled, if there are any attempts to change/hijack control
+flow using an indirect branch/call to an invalid destination, the execution is
+terminated (see Fig. 3).
+
+```rust
+use std::mem;
+
+fn add_one(x: i32) -> i32 {
+    x + 1
+}
+
+fn add_two(x: i32, _y: i32) -> i32 {
+    x + 2
+}
+
+fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
+    f(arg) + f(arg)
+}
+
+fn main() {
+    let answer = do_twice(add_one, 5);
+
+    println!("The answer is: {}", answer);
+
+    println!("With CFI enabled, you should not see the next answer");
+    let f: fn(i32) -> i32 =
+        unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
+    let next_answer = do_twice(f, 5);
+
+    println!("The next answer is: {}", next_answer);
+}
+```
+Fig. 4. Another modified example from the [Advanced Functions and
+Closures][rust-book-ch19-05] chapter of the [The Rust Programming
+Language][rust-book] book.
+
+[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
+
+```shell
+$ rustc rust_cfi.rs -o rust_cfi
+$ ./rust_cfi
+The answer is: 12
+With CFI enabled, you should not see the next answer
+The next answer is: 14
+$
+```
+Fig. 5. Build and execution of the modified example with LLVM CFI disabled.
+
+[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
+
+```shell
+$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi
+$ ./rust_cfi
+The answer is: 12
+With CFI enabled, you should not see the next answer
+Illegal instruction
+$
+```
+Fig. 6. Build and execution of the modified example with LLVM CFI enabled.
+
+When LLVM CFI is enabled, if there are any attempts to change/hijack control
+flow using an indirect branch/call to a function with different number of
+arguments than intended/passed in the call/branch site, the execution is also
+terminated (see Fig. 6).
+
+Forward-edge control flow protection not only by aggregating function pointers
+in groups identified by their number of arguments, but also their argument
+types, will also be provided in later work by defining and using compatible type
+identifiers (see Type metadata in the design document in the tracking
+issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
+
+[rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html
+[rust-book]: https://doc.rust-lang.org/book/title-page.html
+
 # HWAddressSanitizer
 
 HWAddressSanitizer is a newer variant of AddressSanitizer that consumes much
@@ -404,12 +579,14 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
 
 * [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
 * [AddressSanitizer in Clang][clang-asan]
+* [ControlFlowIntegrity in Clang][clang-cfi]
 * [HWAddressSanitizer in Clang][clang-hwasan]
 * [LeakSanitizer in Clang][clang-lsan]
 * [MemorySanitizer in Clang][clang-msan]
 * [ThreadSanitizer in Clang][clang-tsan]
 
 [clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
+[clang-cfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html
 [clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
 [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
 [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
index 5a2cef24870be49daaff686d45f225e39cfdffd4..84fc6dcc33979d1605ab373e13cb00aa9bd622eb 100644 (file)
@@ -66,7 +66,7 @@ assert_eq!(x, 5);
 This will write the value `5` into the `u64` variable `x`.
 You can see that the string literal we use to specify instructions is actually a template string.
 It is governed by the same rules as Rust [format strings][format-syntax].
-The arguments that are inserted into the template however look a bit different then you may
+The arguments that are inserted into the template however look a bit different than you may
 be familiar with. First we need to specify if the variable is an input or an output of the
 inline assembly. In this case it is an output. We declared this by writing `out`.
 We also need to specify in what kind of register the assembly expects the variable.
@@ -106,7 +106,7 @@ code.
 Second, we can see that inputs are declared by writing `in` instead of `out`.
 
 Third, one of our operands has a type we haven't seen yet, `const`.
-This tells the compiler to expand this argument to value directly inside the assembly template.
+This tells the compiler to expand this argument to value directly inside the assembly template.
 This is only possible for constants and literals.
 
 Fourth, we can see that we can specify an argument number, or name as in any format string.
@@ -257,7 +257,7 @@ unsafe {
 }
 
 println!(
-    "L1 Cache: {}",
+    "L0 Cache: {}",
     ((ebx >> 22) + 1) * (((ebx >> 12) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1)
 );
 ```
@@ -885,5 +885,7 @@ The compiler performs some additional checks on options:
     - You are responsible for switching any target-specific state (e.g. thread-local storage, stack bounds).
     - The set of memory locations that you may access is the intersection of those allowed by the `asm!` blocks you entered and exited.
 - You cannot assume that an `asm!` block will appear exactly once in the output binary. The compiler is allowed to instantiate multiple copies of the `asm!` block, for example when the function containing it is inlined in multiple places.
+- On x86, inline assembly must not end with an instruction prefix (such as `LOCK`) that would apply to instructions generated by the compiler.
+  - The compiler is currently unable to detect this due to the way inline assembly is compiled, but may catch and reject this in the future.
 
 > **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call.
index 945b2a8e9a80e75c8f011041f45f20264ce46a9a..268905bcb5339f9d45a3b12e7beb78fccc8934b8 100644 (file)
@@ -10,7 +10,7 @@ path = "lib.rs"
 arrayvec = { version = "0.7", default-features = false }
 pulldown-cmark = { version = "0.8", default-features = false }
 minifier = "0.0.41"
-rayon = { version = "0.3.0", package = "rustc-rayon" }
+rayon = "1.3.1"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 smallvec = "1.6.1"
index f9d1666977134f70fda11a90096bbd3fd25d7473..ba701f42c660ba7606ada806d4e32c56910f3ddc 100644 (file)
@@ -136,7 +136,7 @@ fn generate_for_trait(
         let f = auto_trait::AutoTraitFinder::new(tcx);
 
         debug!("get_auto_trait_impls({:?})", ty);
-        let auto_traits: Vec<_> = self.cx.auto_traits.iter().cloned().collect();
+        let auto_traits: Vec<_> = self.cx.auto_traits.iter().copied().collect();
         let mut auto_traits: Vec<Item> = auto_traits
             .into_iter()
             .filter_map(|trait_def_id| {
@@ -193,8 +193,8 @@ fn handle_lifetimes<'cx>(
         // to its smaller and larger regions. Note that 'larger' regions correspond
         // to sub-regions in Rust code (e.g., in 'a: 'b, 'a is the larger region).
         for constraint in regions.constraints.keys() {
-            match constraint {
-                &Constraint::VarSubVar(r1, r2) => {
+            match *constraint {
+                Constraint::VarSubVar(r1, r2) => {
                     {
                         let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default();
                         deps1.larger.insert(RegionTarget::RegionVid(r2));
@@ -203,15 +203,15 @@ fn handle_lifetimes<'cx>(
                     let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default();
                     deps2.smaller.insert(RegionTarget::RegionVid(r1));
                 }
-                &Constraint::RegSubVar(region, vid) => {
+                Constraint::RegSubVar(region, vid) => {
                     let deps = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
                     deps.smaller.insert(RegionTarget::Region(region));
                 }
-                &Constraint::VarSubReg(vid, region) => {
+                Constraint::VarSubReg(vid, region) => {
                     let deps = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
                     deps.larger.insert(RegionTarget::Region(region));
                 }
-                &Constraint::RegSubReg(r1, r2) => {
+                Constraint::RegSubReg(r1, r2) => {
                     // The constraint is already in the form that we want, so we're done with it
                     // Desired order is 'larger, smaller', so flip then
                     if region_name(r1) != region_name(r2) {
@@ -513,8 +513,8 @@ fn param_env_to_generics(
                         // as we want to combine them with any 'Output' qpaths
                         // later
 
-                        let is_fn = match &mut b {
-                            &mut GenericBound::TraitBound(ref mut p, _) => {
+                        let is_fn = match b {
+                            GenericBound::TraitBound(ref mut p, _) => {
                                 // Insert regions into the for_generics hash map first, to ensure
                                 // that we don't end up with duplicate bounds (e.g., for<'b, 'b>)
                                 for_generics.extend(p.generic_params.clone());
@@ -576,7 +576,7 @@ fn param_env_to_generics(
                                         rhs,
                                     });
                                     continue; // If something other than a Fn ends up
-                                    // with parenthesis, leave it alone
+                                    // with parentheses, leave it alone
                                 }
                             }
 
@@ -699,8 +699,8 @@ fn is_fn_trait(&self, path: &Path) -> bool {
 }
 
 fn region_name(region: Region<'_>) -> Option<Symbol> {
-    match region {
-        &ty::ReEarlyBound(r) => Some(r.name),
+    match *region {
+        ty::ReEarlyBound(r) => Some(r.name),
         _ => None,
     }
 }
@@ -717,8 +717,8 @@ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
     }
 
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        (match r {
-            &ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
+        (match *r {
+            ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
             _ => None,
         })
         .unwrap_or_else(|| r.super_fold_with(self))
index e11b802a09a3b9d3961083494b9705b99f3535b7..cb70f465f62b13aaba04acc7dd9cf06f9fa46277 100644 (file)
@@ -14,9 +14,7 @@
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
 
-use crate::clean::{
-    self, utils, Attributes, AttributesExt, GetDefId, ItemId, NestedAttributesExt, Type,
-};
+use crate::clean::{self, utils, Attributes, AttributesExt, ItemId, NestedAttributesExt, Type};
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
 
@@ -325,7 +323,7 @@ fn merge_attrs(
     }
 }
 
-/// Builds a specific implementation of a type. The `did` could be a type method or trait method.
+/// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl`.
 crate fn build_impl(
     cx: &mut DocContext<'_>,
     parent_module: impl Into<Option<DefId>>,
@@ -337,6 +335,8 @@ fn merge_attrs(
         return;
     }
 
+    let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impl");
+
     let tcx = cx.tcx;
     let associated_trait = tcx.impl_trait_ref(did);
 
@@ -376,7 +376,7 @@ fn merge_attrs(
     // Only inline impl if the implementing type is
     // reachable in rustdoc generated documentation
     if !did.is_local() {
-        if let Some(did) = for_.def_id() {
+        if let Some(did) = for_.def_id(&cx.cache) {
             if !cx.cache.access_levels.is_public(did) {
                 return;
             }
@@ -464,7 +464,7 @@ fn merge_attrs(
     }
 
     while let Some(ty) = stack.pop() {
-        if let Some(did) = ty.def_id() {
+        if let Some(did) = ty.def_id(&cx.cache) {
             if tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden) {
                 return;
             }
@@ -481,7 +481,11 @@ fn merge_attrs(
     let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs);
     trace!("merged_attrs={:?}", merged_attrs);
 
-    trace!("build_impl: impl {:?} for {:?}", trait_.as_ref().map(|t| t.def_id()), for_.def_id());
+    trace!(
+        "build_impl: impl {:?} for {:?}",
+        trait_.as_ref().map(|t| t.def_id()),
+        for_.def_id(&cx.cache)
+    );
     ret.push(clean::Item::from_def_id_and_attrs_and_parts(
         did,
         None,
index 9d102d6878370dea44d839c83b57e15d9feeafde..9ea3112f178be2ad51a9fc098121dd6237546685 100644 (file)
@@ -216,17 +216,15 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
 impl Clean<Lifetime> for hir::Lifetime {
     fn clean(&self, cx: &mut DocContext<'_>) -> Lifetime {
         let def = cx.tcx.named_region(self.hir_id);
-        match def {
-            Some(
-                rl::Region::EarlyBound(_, node_id, _)
-                | rl::Region::LateBound(_, _, node_id, _)
-                | rl::Region::Free(_, node_id),
-            ) => {
-                if let Some(lt) = cx.lt_substs.get(&node_id).cloned() {
-                    return lt;
-                }
+        if let Some(
+            rl::Region::EarlyBound(_, node_id, _)
+            | rl::Region::LateBound(_, _, node_id, _)
+            | rl::Region::Free(_, node_id),
+        ) = def
+        {
+            if let Some(lt) = cx.lt_substs.get(&node_id).cloned() {
+                return lt;
             }
-            _ => {}
         }
         Lifetime(self.name.ident().name)
     }
@@ -385,7 +383,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
         let self_type = self.self_ty().clean(cx);
         Type::QPath {
             name: cx.tcx.associated_item(self.item_def_id).ident.name,
-            self_def_id: self_type.def_id(),
+            self_def_id: self_type.def_id(&cx.cache),
             self_type: box self_type,
             trait_,
         }
@@ -421,7 +419,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
                     GenericParamDefKind::Type {
                         did: self.def_id,
                         bounds: vec![], // These are filled in from the where-clauses.
-                        default,
+                        default: default.map(Box::new),
                         synthetic,
                     },
                 )
@@ -430,9 +428,9 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
                 self.name,
                 GenericParamDefKind::Const {
                     did: self.def_id,
-                    ty: cx.tcx.type_of(self.def_id).clean(cx),
+                    ty: Box::new(cx.tcx.type_of(self.def_id).clean(cx)),
                     default: match has_default {
-                        true => Some(cx.tcx.const_param_default(self.def_id).to_string()),
+                        true => Some(Box::new(cx.tcx.const_param_default(self.def_id).to_string())),
                         false => None,
                     },
                 },
@@ -462,7 +460,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
                 GenericParamDefKind::Type {
                     did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
                     bounds: self.bounds.clean(cx),
-                    default: default.clean(cx),
+                    default: default.clean(cx).map(Box::new),
                     synthetic,
                 },
             ),
@@ -470,10 +468,10 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
                 self.name.ident().name,
                 GenericParamDefKind::Const {
                     did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
-                    ty: ty.clean(cx),
+                    ty: Box::new(ty.clean(cx)),
                     default: default.map(|ct| {
                         let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
-                        ty::Const::from_anon_const(cx.tcx, def_id).to_string()
+                        Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string())
                     }),
                 },
             ),
@@ -828,7 +826,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Arguments {
                 .iter()
                 .enumerate()
                 .map(|(i, ty)| Argument {
-                    name: name_from_pat(&body.params[i].pat),
+                    name: name_from_pat(body.params[i].pat),
                     type_: ty.clean(cx),
                 })
                 .collect(),
@@ -924,7 +922,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
                     }
                     MethodItem(m, None)
                 }
-                hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref names)) => {
+                hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
                     let (generics, decl) = enter_impl_trait(cx, |cx| {
                         (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
                     });
@@ -936,7 +934,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
                     }
                     TyMethodItem(t)
                 }
-                hir::TraitItemKind::Type(ref bounds, ref default) => {
+                hir::TraitItemKind::Type(bounds, ref default) => {
                     AssocTypeItem(bounds.clean(cx), default.clean(cx))
                 }
             };
@@ -1260,7 +1258,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
             let path = path.clean(cx);
             resolve_type(cx, path)
         }
-        hir::QPath::Resolved(Some(ref qself), ref p) => {
+        hir::QPath::Resolved(Some(ref qself), p) => {
             // Try to normalize `<X as Y>::T` to a type
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
             if let Some(normalized_value) = normalize(cx, ty) {
@@ -1281,7 +1279,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
                 trait_,
             }
         }
-        hir::QPath::TypeRelative(ref qself, ref segment) => {
+        hir::QPath::TypeRelative(ref qself, segment) => {
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
             let res = match ty.kind() {
                 ty::Projection(proj) => Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id),
@@ -1337,7 +1335,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
                 let length = print_const(cx, ct.eval(cx.tcx, param_env));
                 Array(box ty.clean(cx), length)
             }
-            TyKind::Tup(ref tys) => Tuple(tys.clean(cx)),
+            TyKind::Tup(tys) => Tuple(tys.clean(cx)),
             TyKind::OpaqueDef(item_id, _) => {
                 let item = cx.tcx.hir().item(item_id);
                 if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
@@ -1346,8 +1344,8 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
                     unreachable!()
                 }
             }
-            TyKind::Path(_) => clean_qpath(&self, cx),
-            TyKind::TraitObject(ref bounds, ref lifetime, _) => {
+            TyKind::Path(_) => clean_qpath(self, cx),
+            TyKind::TraitObject(bounds, ref lifetime, _) => {
                 let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
                 let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
                 DynTrait(bounds, lifetime)
@@ -1441,7 +1439,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
                 let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
                 ResolvedPath { path, did }
             }
-            ty::Dynamic(ref obj, ref reg) => {
+            ty::Dynamic(obj, ref reg) => {
                 // HACK: pick the first `did` as the `did` of the trait object. Someone
                 // might want to implement "native" support for marker-trait-only
                 // trait objects.
@@ -1481,9 +1479,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
 
                 DynTrait(bounds, lifetime)
             }
-            ty::Tuple(ref t) => {
-                Tuple(t.iter().map(|t| t.expect_ty()).collect::<Vec<_>>().clean(cx))
-            }
+            ty::Tuple(t) => Tuple(t.iter().map(|t| t.expect_ty()).collect::<Vec<_>>().clean(cx)),
 
             ty::Projection(ref data) => data.clean(cx),
 
@@ -1821,9 +1817,9 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Vec<Item> {
                     clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
                 }
                 ItemKind::Macro(ref macro_def) => MacroItem(Macro {
-                    source: display_macro_source(cx, name, &macro_def, def_id, &item.vis),
+                    source: display_macro_source(cx, name, macro_def, def_id, &item.vis),
                 }),
-                ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
+                ItemKind::Trait(is_auto, unsafety, ref generics, bounds, item_ids) => {
                     let items = item_ids
                         .iter()
                         .map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx))
@@ -1887,7 +1883,7 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>
     }
 
     let for_ = impl_.self_ty.clean(cx);
-    let type_alias = for_.def_id().and_then(|did| match tcx.def_kind(did) {
+    let type_alias = for_.def_id(&cx.cache).and_then(|did| match tcx.def_kind(did) {
         DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)),
         _ => None,
     });
@@ -2062,12 +2058,13 @@ fn clean_use_statement(
 impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
     fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let (item, renamed) = self;
-        cx.with_param_env(item.def_id.to_def_id(), |cx| {
+        let def_id = item.def_id.to_def_id();
+        cx.with_param_env(def_id, |cx| {
             let kind = match item.kind {
-                hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
+                hir::ForeignItemKind::Fn(decl, names, ref generics) => {
                     let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
                     let (generics, decl) = enter_impl_trait(cx, |cx| {
-                        (generics.clean(cx), (&**decl, &names[..]).clean(cx))
+                        (generics.clean(cx), (&*decl, &names[..]).clean(cx))
                     });
                     ForeignFunctionItem(Function {
                         decl,
@@ -2112,7 +2109,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> TypeBindingKind {
             hir::TypeBindingKind::Equality { ref ty } => {
                 TypeBindingKind::Equality { ty: ty.clean(cx) }
             }
-            hir::TypeBindingKind::Constraint { ref bounds } => {
+            hir::TypeBindingKind::Constraint { bounds } => {
                 TypeBindingKind::Constraint { bounds: bounds.iter().map(|b| b.clean(cx)).collect() }
             }
         }
index d4cea8b4a9d289cb757b8a699555a69835c1562a..56ae43855de924718c08a49e5c85de296bfb4210 100644 (file)
@@ -113,10 +113,9 @@ fn from(id: DefId) -> Self {
     }
 }
 
+/// The crate currently being documented.
 #[derive(Clone, Debug)]
 crate struct Crate {
-    crate name: Symbol,
-    crate src: FileName,
     crate module: Item,
     crate externs: Vec<ExternalCrate>,
     crate primitives: ThinVec<(DefId, PrimitiveType)>,
@@ -125,6 +124,20 @@ fn from(id: DefId) -> Self {
     crate collapsed: bool,
 }
 
+// `Crate` is frequently moved by-value. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(Crate, 104);
+
+impl Crate {
+    crate fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
+        ExternalCrate::LOCAL.name(tcx)
+    }
+
+    crate fn src(&self, tcx: TyCtxt<'_>) -> FileName {
+        ExternalCrate::LOCAL.src(tcx)
+    }
+}
+
 /// This struct is used to wrap additional information added by rustdoc on a `trait` item.
 #[derive(Clone, Debug)]
 crate struct TraitWithExtraInfo {
@@ -138,6 +151,8 @@ fn from(id: DefId) -> Self {
 }
 
 impl ExternalCrate {
+    const LOCAL: Self = Self { crate_num: LOCAL_CRATE };
+
     #[inline]
     crate fn def_id(&self) -> DefId {
         DefId { krate: self.crate_num, index: CRATE_DEF_INDEX }
@@ -204,7 +219,7 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
             .filter_map(|a| a.value_str())
             .map(to_remote)
             .next()
-            .or(extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
+            .or_else(|| extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
             .unwrap_or(Unknown) // Well, at least we tried.
     }
 
@@ -238,7 +253,7 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
                         hir::ItemKind::Mod(_) => {
                             as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
                         }
-                        hir::ItemKind::Use(ref path, hir::UseKind::Single)
+                        hir::ItemKind::Use(path, hir::UseKind::Single)
                             if item.vis.node.is_pub() =>
                         {
                             as_keyword(path.res.expect_non_local())
@@ -304,7 +319,7 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
                         hir::ItemKind::Mod(_) => {
                             as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
                         }
-                        hir::ItemKind::Use(ref path, hir::UseKind::Single)
+                        hir::ItemKind::Use(path, hir::UseKind::Single)
                             if item.vis.node.is_pub() =>
                         {
                             as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
@@ -381,7 +396,7 @@ impl Item {
         {
             *span
         } else {
-            self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(|| Span::dummy())
+            self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(Span::dummy)
         }
     }
 
@@ -562,7 +577,7 @@ pub fn from_def_id_and_attrs_and_parts(
     }
 
     crate fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
-        self.stability(tcx).as_ref().and_then(|ref s| {
+        self.stability(tcx).as_ref().and_then(|s| {
             let mut classes = Vec::with_capacity(2);
 
             if s.level.is_unstable() {
@@ -774,6 +789,7 @@ fn other_attrs(&self) -> Vec<ast::Attribute> {
     fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
         let sess = tcx.sess;
         let doc_cfg_active = tcx.features().doc_cfg;
+        let doc_auto_cfg_active = tcx.features().doc_auto_cfg;
 
         fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
             let mut iter = it.into_iter();
@@ -784,24 +800,26 @@ fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
             Some(item)
         }
 
-        let mut cfg = if doc_cfg_active {
+        let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
             let mut doc_cfg = self
                 .iter()
                 .filter(|attr| attr.has_name(sym::doc))
                 .flat_map(|attr| attr.meta_item_list().unwrap_or_else(Vec::new))
                 .filter(|attr| attr.has_name(sym::cfg))
                 .peekable();
-            if doc_cfg.peek().is_some() {
+            if doc_cfg.peek().is_some() && doc_cfg_active {
                 doc_cfg
                     .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
                     .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
-            } else {
+            } else if doc_auto_cfg_active {
                 self.iter()
                     .filter(|attr| attr.has_name(sym::cfg))
                     .filter_map(|attr| single(attr.meta_item_list()?))
                     .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
                     .filter(|cfg| !hidden_cfg.contains(cfg))
                     .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
+            } else {
+                Cfg::True
             }
         } else {
             Cfg::True
@@ -820,9 +838,9 @@ fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
                         // #[doc(cfg(...))]
                         if let Some(cfg_mi) = item
                             .meta_item()
-                            .and_then(|item| rustc_expand::config::parse_cfg(&item, sess))
+                            .and_then(|item| rustc_expand::config::parse_cfg(item, sess))
                         {
-                            match Cfg::parse(&cfg_mi) {
+                            match Cfg::parse(cfg_mi) {
                                 Ok(new_cfg) => cfg &= new_cfg,
                                 Err(e) => sess.span_err(e.span, e.msg),
                             }
@@ -934,7 +952,7 @@ fn from_iter<T>(iter: T) -> Self
         T: IntoIterator<Item = &'a DocFragment>,
     {
         iter.into_iter().fold(String::new(), |mut acc, frag| {
-            add_doc_fragment(&mut acc, &frag);
+            add_doc_fragment(&mut acc, frag);
             acc
         })
     }
@@ -1061,12 +1079,12 @@ fn update_need_backline(doc_strings: &mut Vec<DocFragment>) {
 
         let ori = iter.next()?;
         let mut out = String::new();
-        add_doc_fragment(&mut out, &ori);
-        while let Some(new_frag) = iter.next() {
+        add_doc_fragment(&mut out, ori);
+        for new_frag in iter {
             if new_frag.kind != ori.kind || new_frag.parent_module != ori.parent_module {
                 break;
             }
-            add_doc_fragment(&mut out, &new_frag);
+            add_doc_fragment(&mut out, new_frag);
         }
         if out.is_empty() { None } else { Some(out) }
     }
@@ -1079,7 +1097,7 @@ fn update_need_backline(doc_strings: &mut Vec<DocFragment>) {
 
         for new_frag in self.doc_strings.iter() {
             let out = ret.entry(new_frag.parent_module).or_default();
-            add_doc_fragment(out, &new_frag);
+            add_doc_fragment(out, new_frag);
         }
         ret
     }
@@ -1219,13 +1237,13 @@ impl WherePredicate {
     Type {
         did: DefId,
         bounds: Vec<GenericBound>,
-        default: Option<Type>,
+        default: Option<Box<Type>>,
         synthetic: Option<hir::SyntheticTyParamKind>,
     },
     Const {
         did: DefId,
-        ty: Type,
-        default: Option<String>,
+        ty: Box<Type>,
+        default: Option<Box<String>>,
     },
 }
 
@@ -1239,8 +1257,8 @@ impl GenericParamDefKind {
     // any embedded types, but `get_type` seems to be the wrong name for that.
     crate fn get_type(&self) -> Option<Type> {
         match self {
-            GenericParamDefKind::Type { default, .. } => default.clone(),
-            GenericParamDefKind::Const { ty, .. } => Some(ty.clone()),
+            GenericParamDefKind::Type { default, .. } => default.as_deref().cloned(),
+            GenericParamDefKind::Const { ty, .. } => Some((&**ty).clone()),
             GenericParamDefKind::Lifetime { .. } => None,
         }
     }
@@ -1252,6 +1270,10 @@ impl GenericParamDefKind {
     crate kind: GenericParamDefKind,
 }
 
+// `GenericParamDef` is used in many places. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(GenericParamDef, 56);
+
 impl GenericParamDef {
     crate fn is_synthetic_type_param(&self) -> bool {
         match self.kind {
@@ -1366,17 +1388,10 @@ impl Argument {
     DefaultReturn,
 }
 
-impl GetDefId for FnRetTy {
-    fn def_id(&self) -> Option<DefId> {
-        match *self {
-            Return(ref ty) => ty.def_id(),
-            DefaultReturn => None,
-        }
-    }
-
-    fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
-        match *self {
-            Return(ref ty) => ty.def_id_full(cache),
+impl FnRetTy {
+    crate fn as_return(&self) -> Option<&Type> {
+        match self {
+            Return(ret) => Some(ret),
             DefaultReturn => None,
         }
     }
@@ -1450,33 +1465,9 @@ fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
     ImplTrait(Vec<GenericBound>),
 }
 
-crate trait GetDefId {
-    /// Use this method to get the [`DefId`] of a [`clean`] AST node.
-    /// This will return [`None`] when called on a primitive [`clean::Type`].
-    /// Use [`Self::def_id_full`] if you want to include primitives.
-    ///
-    /// [`clean`]: crate::clean
-    /// [`clean::Type`]: crate::clean::Type
-    // FIXME: get rid of this function and always use `def_id_full`
-    fn def_id(&self) -> Option<DefId>;
-
-    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
-    ///
-    /// See [`Self::def_id`] for more.
-    ///
-    /// [clean]: crate::clean
-    fn def_id_full(&self, cache: &Cache) -> Option<DefId>;
-}
-
-impl<T: GetDefId> GetDefId for Option<T> {
-    fn def_id(&self) -> Option<DefId> {
-        self.as_ref().and_then(|d| d.def_id())
-    }
-
-    fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
-        self.as_ref().and_then(|d| d.def_id_full(cache))
-    }
-}
+// `Type` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(Type, 72);
 
 impl Type {
     crate fn primitive_type(&self) -> Option<PrimitiveType> {
@@ -1556,17 +1547,27 @@ fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
             QPath { ref self_type, .. } => return self_type.inner_def_id(cache),
             Generic(_) | Infer | ImplTrait(_) => return None,
         };
-        cache.and_then(|c| Primitive(t).def_id_full(c))
+        cache.and_then(|c| Primitive(t).def_id(c))
     }
-}
 
-impl GetDefId for Type {
-    fn def_id(&self) -> Option<DefId> {
-        self.inner_def_id(None)
+    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
+    ///
+    /// See [`Self::def_id_no_primitives`] for more.
+    ///
+    /// [clean]: crate::clean
+    crate fn def_id(&self, cache: &Cache) -> Option<DefId> {
+        self.inner_def_id(Some(cache))
     }
 
-    fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
-        self.inner_def_id(Some(cache))
+    /// Use this method to get the [`DefId`] of a [`clean`] AST node.
+    /// This will return [`None`] when called on a primitive [`clean::Type`].
+    /// Use [`Self::def_id`] if you want to include primitives.
+    ///
+    /// [`clean`]: crate::clean
+    /// [`clean::Type`]: crate::clean::Type
+    // FIXME: get rid of this function and always use `def_id`
+    crate fn def_id_no_primitives(&self) -> Option<DefId> {
+        self.inner_def_id(None)
     }
 }
 
@@ -2084,16 +2085,6 @@ impl Path {
     crate item_type: Option<Type>,
 }
 
-impl GetDefId for Typedef {
-    fn def_id(&self) -> Option<DefId> {
-        self.type_.def_id()
-    }
-
-    fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
-        self.type_.def_id_full(cache)
-    }
-}
-
 #[derive(Clone, Debug)]
 crate struct OpaqueTy {
     crate bounds: Vec<GenericBound>,
index de43daff6f0d7c8416420d53ee86103a2a4f892a..2fae3163a1a1a4f19509091f6520929e04bf98f0 100644 (file)
     let module = crate::visit_ast::RustdocVisitor::new(cx).visit();
 
     let mut externs = Vec::new();
-    for &cnum in cx.tcx.crates(()).iter() {
+    for &cnum in cx.tcx.crates(()) {
         externs.push(ExternalCrate { crate_num: cnum });
         // Analyze doc-reachability for extern items
         LibEmbargoVisitor::new(cx).visit_lib(cnum);
     }
-    externs.sort_unstable_by_key(|e| e.crate_num);
 
     // Clean the crate, translating the entire librustc_ast AST to one that is
     // understood by rustdoc.
@@ -57,8 +56,6 @@
     }
 
     let local_crate = ExternalCrate { crate_num: LOCAL_CRATE };
-    let src = local_crate.src(cx.tcx);
-    let name = local_crate.name(cx.tcx);
     let primitives = local_crate.primitives(cx.tcx);
     let keywords = local_crate.keywords(cx.tcx);
     {
@@ -80,8 +77,6 @@
     }
 
     Crate {
-        name,
-        src,
         module,
         externs,
         primitives,
@@ -171,8 +166,8 @@ pub(super) fn external_path(
 
 crate fn qpath_to_string(p: &hir::QPath<'_>) -> String {
     let segments = match *p {
-        hir::QPath::Resolved(_, ref path) => &path.segments,
-        hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(),
+        hir::QPath::Resolved(_, path) => &path.segments,
+        hir::QPath::TypeRelative(_, segment) => return segment.ident.to_string(),
         hir::QPath::LangItem(lang_item, ..) => return lang_item.name().to_string(),
     };
 
@@ -217,15 +212,15 @@ pub(super) fn external_path(
         PatKind::Wild | PatKind::Struct(..) => return kw::Underscore,
         PatKind::Binding(_, _, ident, _) => return ident.name,
         PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
-        PatKind::Or(ref pats) => {
+        PatKind::Or(pats) => {
             pats.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(" | ")
         }
-        PatKind::Tuple(ref elts, _) => format!(
+        PatKind::Tuple(elts, _) => format!(
             "({})",
             elts.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(", ")
         ),
-        PatKind::Box(ref p) => return name_from_pat(&**p),
-        PatKind::Ref(ref p, _) => return name_from_pat(&**p),
+        PatKind::Box(p) => return name_from_pat(&*p),
+        PatKind::Ref(p, _) => return name_from_pat(&*p),
         PatKind::Lit(..) => {
             warn!(
                 "tried to get argument name from PatKind::Lit, which is silly in function arguments"
@@ -233,7 +228,7 @@ pub(super) fn external_path(
             return Symbol::intern("()");
         }
         PatKind::Range(..) => return kw::Underscore,
-        PatKind::Slice(ref begin, ref mid, ref end) => {
+        PatKind::Slice(begin, ref mid, end) => {
             let begin = begin.iter().map(|p| name_from_pat(p).to_string());
             let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
             let end = end.iter().map(|p| name_from_pat(p).to_string());
@@ -507,7 +502,7 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &'tcx ty::Const<'tc
 /// so that the channel is consistent.
 ///
 /// Set by `bootstrap::Builder::doc_rust_lang_org_channel` in order to keep tests passing on beta/stable.
-crate const DOC_RUST_LANG_ORG_CHANNEL: &'static str = env!("DOC_RUST_LANG_ORG_CHANNEL");
+crate const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL");
 
 /// Render a sequence of macro arms in a format suitable for displaying to the user
 /// as part of an item declaration.
index ac440a395155c8af38184c533367193eecf73a93..493aa56fce6efe061a2b12ba673628625ba88731 100644 (file)
@@ -25,6 +25,7 @@
 use crate::html::static_files;
 use crate::opts;
 use crate::passes::{self, Condition, DefaultPassOption};
+use crate::scrape_examples::{AllCallLocations, ScrapeExamplesOptions};
 use crate::theme;
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -158,6 +159,10 @@ fn try_from(value: &str) -> Result<Self, Self::Error> {
     crate json_unused_externs: bool,
     /// Whether to skip capturing stdout and stderr of tests.
     crate nocapture: bool,
+
+    /// Configuration for scraping examples from the current crate. If this option is Some(..) then
+    /// the compiler will scrape examples and not generate documentation.
+    crate scrape_examples_options: Option<ScrapeExamplesOptions>,
 }
 
 impl fmt::Debug for Options {
@@ -202,6 +207,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             .field("run_check", &self.run_check)
             .field("no_run", &self.no_run)
             .field("nocapture", &self.nocapture)
+            .field("scrape_examples_options", &self.scrape_examples_options)
             .finish()
     }
 }
@@ -280,6 +286,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     crate emit: Vec<EmitType>,
     /// If `true`, HTML source pages will generate links for items to their definition.
     crate generate_link_to_definition: bool,
+    crate call_locations: AllCallLocations,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -314,13 +321,13 @@ impl Options {
     /// been printed, returns `Err` with the exit code.
     crate fn from_matches(matches: &getopts::Matches) -> Result<Options, i32> {
         // Check for unstable options.
-        nightly_options::check_nightly_options(&matches, &opts());
+        nightly_options::check_nightly_options(matches, &opts());
 
         if matches.opt_present("h") || matches.opt_present("help") {
             crate::usage("rustdoc");
             return Err(0);
         } else if matches.opt_present("version") {
-            rustc_driver::version("rustdoc", &matches);
+            rustc_driver::version("rustdoc", matches);
             return Err(0);
         }
 
@@ -356,10 +363,10 @@ fn println_condition(condition: Condition) {
             return Err(0);
         }
 
-        let color = config::parse_color(&matches);
+        let color = config::parse_color(matches);
         let config::JsonConfig { json_rendered, json_unused_externs, .. } =
-            config::parse_json(&matches);
-        let error_format = config::parse_error_format(&matches, color, json_rendered);
+            config::parse_json(matches);
+        let error_format = config::parse_error_format(matches, color, json_rendered);
 
         let codegen_options = CodegenOptions::build(matches, error_format);
         let debugging_opts = DebuggingOptions::build(matches, error_format);
@@ -367,7 +374,7 @@ fn println_condition(condition: Condition) {
         let diag = new_handler(error_format, None, &debugging_opts);
 
         // check for deprecated options
-        check_deprecated_options(&matches, &diag);
+        check_deprecated_options(matches, &diag);
 
         let mut emit = Vec::new();
         for list in matches.opt_strs("emit") {
@@ -433,8 +440,8 @@ fn println_condition(condition: Condition) {
             .iter()
             .map(|s| SearchPath::from_cli_opt(s, error_format))
             .collect();
-        let externs = parse_externs(&matches, &debugging_opts, error_format);
-        let extern_html_root_urls = match parse_extern_html_roots(&matches) {
+        let externs = parse_externs(matches, &debugging_opts, error_format);
+        let extern_html_root_urls = match parse_extern_html_roots(matches) {
             Ok(ex) => ex,
             Err(err) => {
                 diag.struct_err(err).emit();
@@ -553,7 +560,7 @@ fn println_condition(condition: Condition) {
             }
         }
 
-        let edition = config::parse_crate_edition(&matches);
+        let edition = config::parse_crate_edition(matches);
 
         let mut id_map = html::markdown::IdMap::new();
         let external_html = match ExternalHtml::load(
@@ -562,7 +569,7 @@ fn println_condition(condition: Condition) {
             &matches.opt_strs("html-after-content"),
             &matches.opt_strs("markdown-before-content"),
             &matches.opt_strs("markdown-after-content"),
-            nightly_options::match_is_nightly_build(&matches),
+            nightly_options::match_is_nightly_build(matches),
             &diag,
             &mut id_map,
             edition,
@@ -671,6 +678,10 @@ fn println_condition(condition: Condition) {
             return Err(1);
         }
 
+        let scrape_examples_options = ScrapeExamplesOptions::new(&matches, &diag)?;
+        let with_examples = matches.opt_strs("with-examples");
+        let call_locations = crate::scrape_examples::load_call_locations(with_examples, &diag)?;
+
         let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
 
         Ok(Options {
@@ -737,10 +748,12 @@ fn println_condition(condition: Condition) {
                 ),
                 emit,
                 generate_link_to_definition,
+                call_locations,
             },
             crate_name,
             output_format,
             json_unused_externs,
+            scrape_examples_options,
         })
     }
 
index 074744b3d11e2443cb4f9cf4a2b5a7ce99e8a251..b7251e8f57151cb3024ee2a40b77c2bb7dee9678 100644 (file)
@@ -85,7 +85,7 @@
 
 impl<'tcx> DocContext<'tcx> {
     crate fn sess(&self) -> &'tcx Session {
-        &self.tcx.sess
+        self.tcx.sess
     }
 
     crate fn with_param_env<T, F: FnOnce(&mut Self) -> T>(&mut self, def_id: DefId, f: F) -> T {
@@ -464,7 +464,7 @@ fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler, sp: Span) {
                 _ => continue,
             };
             for name in value.as_str().split_whitespace() {
-                let span = attr.name_value_literal_span().unwrap_or(attr.span());
+                let span = attr.name_value_literal_span().unwrap_or_else(|| attr.span());
                 manual_passes.extend(parse_pass(name, Some(span)));
             }
         }
index a5fab1b3d42170c7f7ccdd527dae9dca37820cf6..d59273db08b4f9f50fe7155816a55340893f3ed2 100644 (file)
 use std::string::ToString;
 use std::sync::mpsc::Sender;
 
-macro_rules! try_err {
-    ($e:expr, $file:expr) => {
-        match $e {
-            Ok(e) => e,
-            Err(e) => return Err(E::new(e, $file)),
-        }
-    };
-}
-
 crate trait PathError {
     fn new<S, P: AsRef<Path>>(e: S, path: P) -> Self
     where
@@ -75,7 +66,7 @@ impl DocFS {
                 });
             });
         } else {
-            try_err!(fs::write(&path, contents), path);
+            fs::write(&path, contents).map_err(|e| E::new(e, path))?;
         }
         Ok(())
     }
index 9e64d200b437339abf5d20ba337c43f0e63bea69..9b32ad979e385572cdd3878cdae54ff712b1b811 100644 (file)
@@ -73,7 +73,7 @@
         search_paths: options.libs.clone(),
         crate_types,
         lint_opts: if !options.display_doctest_warnings { lint_opts } else { vec![] },
-        lint_cap: Some(options.lint_cap.unwrap_or_else(|| lint::Forbid)),
+        lint_cap: Some(options.lint_cap.unwrap_or(lint::Forbid)),
         cg: options.codegen_options.clone(),
         externs: options.externs.clone(),
         unstable_features: options.render_options.unstable_features,
                 .iter()
                 .map(|uexts| uexts.unused_extern_names.iter().collect::<FxHashSet<&String>>())
                 .fold(extern_names, |uextsa, uextsb| {
-                    uextsa.intersection(&uextsb).map(|v| *v).collect::<FxHashSet<&String>>()
+                    uextsa.intersection(&uextsb).copied().collect::<FxHashSet<&String>>()
                 })
                 .iter()
                 .map(|v| (*v).clone())
@@ -423,7 +423,7 @@ fn drop(&mut self) {
 
     // Add a \n to the end to properly terminate the last line,
     // but only if there was output to be printed
-    if out_lines.len() > 0 {
+    if !out_lines.is_empty() {
         out_lines.push("");
     }
 
@@ -1124,7 +1124,7 @@ fn visit_testable<F: FnOnce(&mut Self)>(
         let mut attrs = Attributes::from_ast(ast_attrs, None);
 
         if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) {
-            if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) {
+            if !cfg.matches(&self.sess.parse_sess, Some(self.sess.features_untracked())) {
                 return;
             }
         }
index f84850c0fe1f1c1531ccd4b59d06698fa516cebb..cd0f44e5696fec3e2038dcb5d5a76f24b8fbfbb5 100644 (file)
@@ -20,22 +20,28 @@ fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
             StructItem(mut i) => {
                 let num_fields = i.fields.len();
                 i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                i.fields_stripped |=
-                    num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
+                if !i.fields_stripped {
+                    i.fields_stripped =
+                        num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
+                }
                 StructItem(i)
             }
             UnionItem(mut i) => {
                 let num_fields = i.fields.len();
                 i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                i.fields_stripped |=
-                    num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
+                if !i.fields_stripped {
+                    i.fields_stripped =
+                        num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
+                }
                 UnionItem(i)
             }
             EnumItem(mut i) => {
                 let num_variants = i.variants.len();
                 i.variants = i.variants.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                i.variants_stripped |=
-                    num_variants != i.variants.len() || i.variants.iter().any(|f| f.is_stripped());
+                if !i.variants_stripped {
+                    i.variants_stripped = num_variants != i.variants.len()
+                        || i.variants.iter().any(|f| f.is_stripped());
+                }
                 EnumItem(i)
             }
             TraitItem(mut i) => {
@@ -46,24 +52,42 @@ fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
                 i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
                 ImplItem(i)
             }
-            VariantItem(i) => {
-                let i2 = i.clone(); // this clone is small
-                match i {
-                    Variant::Struct(mut j) => {
-                        let num_fields = j.fields.len();
-                        j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                        j.fields_stripped |= num_fields != j.fields.len()
+            VariantItem(i) => match i {
+                Variant::Struct(mut j) => {
+                    let num_fields = j.fields.len();
+                    j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+                    if !j.fields_stripped {
+                        j.fields_stripped = num_fields != j.fields.len()
                             || j.fields.iter().any(|f| f.is_stripped());
-                        VariantItem(Variant::Struct(j))
-                    }
-                    Variant::Tuple(fields) => {
-                        let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                        VariantItem(Variant::Tuple(fields))
                     }
-                    _ => VariantItem(i2),
+                    VariantItem(Variant::Struct(j))
                 }
-            }
-            x => x,
+                Variant::Tuple(fields) => {
+                    let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+                    VariantItem(Variant::Tuple(fields))
+                }
+                Variant::CLike => VariantItem(Variant::CLike),
+            },
+            ExternCrateItem { src: _ }
+            | ImportItem(_)
+            | FunctionItem(_)
+            | TypedefItem(_, _)
+            | OpaqueTyItem(_)
+            | StaticItem(_)
+            | ConstantItem(_)
+            | TraitAliasItem(_)
+            | TyMethodItem(_)
+            | MethodItem(_, _)
+            | StructFieldItem(_)
+            | ForeignFunctionItem(_)
+            | ForeignStaticItem(_)
+            | ForeignTypeItem
+            | MacroItem(_)
+            | ProcMacroItem(_)
+            | PrimitiveItem(_)
+            | AssocConstItem(_, _)
+            | AssocTypeItem(_, _)
+            | KeywordItem(_) => kind,
         }
     }
 
@@ -86,14 +110,12 @@ fn fold_mod(&mut self, m: Module) -> Module {
     fn fold_crate(&mut self, mut c: Crate) -> Crate {
         c.module = self.fold_item(c.module).unwrap();
 
-        {
-            let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
-            for (k, mut v) in external_traits {
-                v.trait_.items =
-                    v.trait_.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
-                c.external_traits.borrow_mut().insert(k, v);
-            }
+        let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
+        for (k, mut v) in external_traits {
+            v.trait_.items = v.trait_.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
+            c.external_traits.borrow_mut().insert(k, v);
         }
+
         c
     }
 }
index 8b883ffaaf095cb4419f12f96bab71f6807b4002..6b9c9a9669b1a4a4284e9ff6877f0b9e37221d5d 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
 
-use crate::clean::{self, GetDefId, ItemId, PrimitiveType};
+use crate::clean::{self, ItemId, PrimitiveType};
 use crate::config::RenderOptions;
 use crate::fold::DocFolder;
 use crate::formats::item_type::ItemType;
@@ -206,7 +206,9 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                 || i.trait_
                     .as_ref()
                     .map_or(false, |t| self.cache.masked_crates.contains(&t.def_id().krate))
-                || i.for_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
+                || i.for_
+                    .def_id(self.cache)
+                    .map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
             {
                 return None;
             }
@@ -292,7 +294,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                     // inserted later on when serializing the search-index.
                     if item.def_id.index().map_or(false, |idx| idx != CRATE_DEF_INDEX) {
                         let desc = item.doc_value().map_or_else(String::new, |x| {
-                            short_markdown_summary(&x.as_str(), &item.link_names(&self.cache))
+                            short_markdown_summary(x.as_str(), &item.link_names(self.cache))
                         });
                         self.cache.search_index.push(IndexItem {
                             ty: item.type_(),
@@ -454,7 +456,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
 
             if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
                 for bound in generics {
-                    if let Some(did) = bound.def_id() {
+                    if let Some(did) = bound.def_id(self.cache) {
                         dids.insert(did);
                     }
                 }
@@ -462,7 +464,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
             let impl_item = Impl { impl_item: item };
             if impl_item.trait_did().map_or(true, |d| self.cache.traits.contains_key(&d)) {
                 for did in dids {
-                    self.cache.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
+                    self.cache.impls.entry(did).or_insert_with(Vec::new).push(impl_item.clone());
                 }
             } else {
                 let trait_did = impl_item.trait_did().expect("no trait did");
index 955de57dc0e5f3ea9a3b231869ef33bb7fbb3706..793db16faf38517dd5954e98b1bfaab9804bf425 100644 (file)
@@ -48,6 +48,7 @@
     ProcAttribute = 23,
     ProcDerive = 24,
     TraitAlias = 25,
+    Generic = 26,
 }
 
 impl Serialize for ItemType {
@@ -173,6 +174,7 @@ impl ItemType {
             ItemType::ProcAttribute => "attr",
             ItemType::ProcDerive => "derive",
             ItemType::TraitAlias => "traitalias",
+            ItemType::Generic => "generic",
         }
     }
 }
index f2751947c7eb95a6db9b8d8154e11e7e17228f84..c51bda60b73853b1142e2766aa156159fe1c85b6 100644 (file)
@@ -597,7 +597,7 @@ fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
 
 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
 /// rendering function with the necessary arguments for linking to a local path.
-fn resolved_path<'a, 'cx: 'a>(
+fn resolved_path<'cx>(
     w: &mut fmt::Formatter<'_>,
     did: DefId,
     path: &clean::Path,
@@ -696,7 +696,7 @@ fn primitive_link(
 
 /// Helper to render type parameters
 fn tybounds<'a, 'tcx: 'a>(
-    bounds: &'a Vec<clean::PolyTrait>,
+    bounds: &'a [clean::PolyTrait],
     lt: &'a Option<clean::Lifetime>,
     cx: &'a Context<'tcx>,
 ) -> impl fmt::Display + 'a + Captures<'tcx> {
@@ -886,7 +886,7 @@ fn fmt_type<'cx>(
                     if bounds.len() > 1 || trait_lt.is_some() =>
                 {
                     write!(f, "{}{}{}(", amp, lt, m)?;
-                    fmt_type(&ty, f, use_absolute, cx)?;
+                    fmt_type(ty, f, use_absolute, cx)?;
                     write!(f, ")")
                 }
                 clean::Generic(..) => {
@@ -896,11 +896,11 @@ fn fmt_type<'cx>(
                         &format!("{}{}{}", amp, lt, m),
                         cx,
                     )?;
-                    fmt_type(&ty, f, use_absolute, cx)
+                    fmt_type(ty, f, use_absolute, cx)
                 }
                 _ => {
                     write!(f, "{}{}{}", amp, lt, m)?;
-                    fmt_type(&ty, f, use_absolute, cx)
+                    fmt_type(ty, f, use_absolute, cx)
                 }
             }
         }
index 8ed69962875a62b6c05b0ee7ad3e3a6e4fd95b9a..e177a11303643d645ef0a9aac29cfaff9bc54047 100644 (file)
@@ -12,6 +12,7 @@
 use std::collections::VecDeque;
 use std::fmt::{Display, Write};
 
+use rustc_data_structures::fx::FxHashMap;
 use rustc_lexer::{LiteralKind, TokenKind};
 use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
     crate root_path: &'c str,
 }
 
+/// Decorations are represented as a map from CSS class to vector of character ranges.
+/// Each range will be wrapped in a span with that class.
+crate struct DecorationInfo(crate FxHashMap<&'static str, Vec<(u32, u32)>>);
+
 /// Highlights `src`, returning the HTML output.
 crate fn render_with_highlighting(
     src: &str,
@@ -40,6 +45,7 @@
     edition: Edition,
     extra_content: Option<Buffer>,
     context_info: Option<ContextInfo<'_, '_, '_>>,
+    decoration_info: Option<DecorationInfo>,
 ) {
     debug!("highlighting: ================\n{}\n==============", src);
     if let Some((edition_info, class)) = tooltip {
@@ -56,7 +62,7 @@
     }
 
     write_header(out, class, extra_content);
-    write_code(out, &src, edition, context_info);
+    write_code(out, src, edition, context_info, decoration_info);
     write_footer(out, playground_button);
 }
 
@@ -89,17 +95,23 @@ fn write_code(
     src: &str,
     edition: Edition,
     context_info: Option<ContextInfo<'_, '_, '_>>,
+    decoration_info: Option<DecorationInfo>,
 ) {
     // This replace allows to fix how the code source with DOS backline characters is displayed.
     let src = src.replace("\r\n", "\n");
-    Classifier::new(&src, edition, context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP))
-        .highlight(&mut |highlight| {
-            match highlight {
-                Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
-                Highlight::EnterSpan { class } => enter_span(out, class),
-                Highlight::ExitSpan => exit_span(out),
-            };
-        });
+    Classifier::new(
+        &src,
+        edition,
+        context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
+        decoration_info,
+    )
+    .highlight(&mut |highlight| {
+        match highlight {
+            Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
+            Highlight::EnterSpan { class } => enter_span(out, class),
+            Highlight::ExitSpan => exit_span(out),
+        };
+    });
 }
 
 fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
@@ -127,6 +139,7 @@ enum Class {
     PreludeTy,
     PreludeVal,
     QuestionMark,
+    Decoration(&'static str),
 }
 
 impl Class {
@@ -150,6 +163,7 @@ fn as_html(self) -> &'static str {
             Class::PreludeTy => "prelude-ty",
             Class::PreludeVal => "prelude-val",
             Class::QuestionMark => "question-mark",
+            Class::Decoration(kind) => kind,
         }
     }
 
@@ -248,6 +262,30 @@ fn next(&mut self) -> Option<Self::Item> {
     }
 }
 
+/// Custom spans inserted into the source. Eg --scrape-examples uses this to highlight function calls
+struct Decorations {
+    starts: Vec<(u32, &'static str)>,
+    ends: Vec<u32>,
+}
+
+impl Decorations {
+    fn new(info: DecorationInfo) -> Self {
+        // Extract tuples (start, end, kind) into separate sequences of (start, kind) and (end).
+        let (mut starts, mut ends): (Vec<_>, Vec<_>) = info
+            .0
+            .into_iter()
+            .map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi)))
+            .flatten()
+            .unzip();
+
+        // Sort the sequences in document order.
+        starts.sort_by_key(|(lo, _)| *lo);
+        ends.sort();
+
+        Decorations { starts, ends }
+    }
+}
+
 /// Processes program tokens, classifying strings of text by highlighting
 /// category (`Class`).
 struct Classifier<'a> {
@@ -259,13 +297,20 @@ struct Classifier<'a> {
     byte_pos: u32,
     file_span: Span,
     src: &'a str,
+    decorations: Option<Decorations>,
 }
 
 impl<'a> Classifier<'a> {
     /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
     /// file span which will be used later on by the `span_correspondance_map`.
-    fn new(src: &str, edition: Edition, file_span: Span) -> Classifier<'_> {
+    fn new(
+        src: &str,
+        edition: Edition,
+        file_span: Span,
+        decoration_info: Option<DecorationInfo>,
+    ) -> Classifier<'_> {
         let tokens = PeekIter::new(TokenIter { src });
+        let decorations = decoration_info.map(Decorations::new);
         Classifier {
             tokens,
             in_attribute: false,
@@ -275,6 +320,7 @@ fn new(src: &str, edition: Edition, file_span: Span) -> Classifier<'_> {
             byte_pos: 0,
             file_span,
             src,
+            decorations,
         }
     }
 
@@ -356,6 +402,19 @@ fn next(&mut self) -> Option<(TokenKind, &'a str, u32)> {
     /// token is used.
     fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
         loop {
+            if let Some(decs) = self.decorations.as_mut() {
+                let byte_pos = self.byte_pos;
+                let n_starts = decs.starts.iter().filter(|(i, _)| byte_pos >= *i).count();
+                for (_, kind) in decs.starts.drain(0..n_starts) {
+                    sink(Highlight::EnterSpan { class: Class::Decoration(kind) });
+                }
+
+                let n_ends = decs.ends.iter().filter(|i| byte_pos >= **i).count();
+                for _ in decs.ends.drain(0..n_ends) {
+                    sink(Highlight::ExitSpan);
+                }
+            }
+
             if self
                 .tokens
                 .peek()
@@ -416,22 +475,37 @@ fn advance(
             // Assume that '&' or '*' is the reference or dereference operator
             // or a reference or pointer type. Unless, of course, it looks like
             // a logical and or a multiplication operator: `&&` or `* `.
-            TokenKind::Star => match self.peek() {
-                Some(TokenKind::Whitespace) => Class::Op,
+            TokenKind::Star => match self.tokens.peek() {
+                Some((TokenKind::Whitespace, _)) => Class::Op,
+                Some((TokenKind::Ident, "mut")) => {
+                    self.next();
+                    sink(Highlight::Token { text: "*mut", class: Some(Class::RefKeyWord) });
+                    return;
+                }
+                Some((TokenKind::Ident, "const")) => {
+                    self.next();
+                    sink(Highlight::Token { text: "*const", class: Some(Class::RefKeyWord) });
+                    return;
+                }
                 _ => Class::RefKeyWord,
             },
-            TokenKind::And => match lookahead {
-                Some(TokenKind::And) => {
+            TokenKind::And => match self.tokens.peek() {
+                Some((TokenKind::And, _)) => {
                     self.next();
                     sink(Highlight::Token { text: "&&", class: Some(Class::Op) });
                     return;
                 }
-                Some(TokenKind::Eq) => {
+                Some((TokenKind::Eq, _)) => {
                     self.next();
                     sink(Highlight::Token { text: "&=", class: Some(Class::Op) });
                     return;
                 }
-                Some(TokenKind::Whitespace) => Class::Op,
+                Some((TokenKind::Whitespace, _)) => Class::Op,
+                Some((TokenKind::Ident, "mut")) => {
+                    self.next();
+                    sink(Highlight::Token { text: "&mut", class: Some(Class::RefKeyWord) });
+                    return;
+                }
                 _ => Class::RefKeyWord,
             },
 
@@ -657,7 +731,7 @@ fn string<T: Display>(
                 // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
                 match href {
                     LinkFromSrc::Local(span) => context
-                        .href_from_span(*span)
+                        .href_from_span(*span, true)
                         .map(|s| format!("{}{}", context_info.root_path, s)),
                     LinkFromSrc::External(def_id) => {
                         format::href_with_root_path(*def_id, context, Some(context_info.root_path))
@@ -665,7 +739,7 @@ fn string<T: Display>(
                             .map(|(url, _, _)| url)
                     }
                     LinkFromSrc::Primitive(prim) => format::href_with_root_path(
-                        PrimitiveType::primitive_locations(context.tcx())[&prim],
+                        PrimitiveType::primitive_locations(context.tcx())[prim],
                         context,
                         Some(context_info.root_path),
                     )
diff --git a/src/librustdoc/html/highlight/fixtures/decorations.html b/src/librustdoc/html/highlight/fixtures/decorations.html
new file mode 100644 (file)
index 0000000..45f5678
--- /dev/null
@@ -0,0 +1,2 @@
+<span class="example"><span class="kw">let</span> <span class="ident">x</span> <span class="op">=</span> <span class="number">1</span>;</span>
+<span class="kw">let</span> <span class="ident">y</span> <span class="op">=</span> <span class="number">2</span>;
\ No newline at end of file
index 22e650af7e22b1a977928c540adadda782a27c92..b117a12e39f4a45bf1e0938ce9f4eb51e1d13e1c 100644 (file)
 <span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">target_os</span> <span class="op">=</span> <span class="string">&quot;linux&quot;</span>)]</span>
 <span class="kw">fn</span> <span class="ident">main</span>() -&gt; () {
     <span class="kw">let</span> <span class="ident">foo</span> <span class="op">=</span> <span class="bool-val">true</span> <span class="op">&amp;&amp;</span> <span class="bool-val">false</span> <span class="op">|</span><span class="op">|</span> <span class="bool-val">true</span>;
-    <span class="kw">let</span> <span class="kw">_</span>: <span class="kw-2">*</span><span class="kw">const</span> () <span class="op">=</span> <span class="number">0</span>;
+    <span class="kw">let</span> <span class="kw">_</span>: <span class="kw-2">*const</span> () <span class="op">=</span> <span class="number">0</span>;
     <span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">&amp;</span><span class="ident">foo</span>;
     <span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="op">&amp;&amp;</span><span class="ident">foo</span>;
     <span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">*</span><span class="ident">foo</span>;
-    <span class="macro">mac!</span>(<span class="ident">foo</span>, <span class="kw-2">&amp;</span><span class="kw-2">mut</span> <span class="ident">bar</span>);
+    <span class="macro">mac!</span>(<span class="ident">foo</span>, <span class="kw-2">&amp;mut</span> <span class="ident">bar</span>);
     <span class="macro">assert!</span>(<span class="self">self</span>.<span class="ident">length</span> <span class="op">&lt;</span> <span class="ident">N</span> <span class="op">&amp;&amp;</span> <span class="ident">index</span> <span class="op">&lt;</span><span class="op">=</span> <span class="self">self</span>.<span class="ident">length</span>);
     <span class="ident">::std::env::var</span>(<span class="string">&quot;gateau&quot;</span>).<span class="ident">is_ok</span>();
     <span class="attribute">#[<span class="ident">rustfmt::skip</span>]</span>
index 450bbfea1ea863143504f6f0a9ec91b77b5cee80..1fea7e983b4482d4113f6d71b6b1dbde88e35088 100644 (file)
@@ -1,6 +1,7 @@
-use super::write_code;
+use super::{write_code, DecorationInfo};
 use crate::html::format::Buffer;
 use expect_test::expect_file;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_span::create_default_session_globals_then;
 use rustc_span::edition::Edition;
 
@@ -22,7 +23,7 @@ fn test_html_highlighting() {
         let src = include_str!("fixtures/sample.rs");
         let html = {
             let mut out = Buffer::new();
-            write_code(&mut out, src, Edition::Edition2018, None);
+            write_code(&mut out, src, Edition::Edition2018, None, None);
             format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
         };
         expect_file!["fixtures/sample.html"].assert_eq(&html);
@@ -36,7 +37,7 @@ fn test_dos_backline() {
     println!(\"foo\");\r\n\
 }\r\n";
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None);
+        write_code(&mut html, src, Edition::Edition2018, None, None);
         expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
     });
 }
@@ -50,7 +51,7 @@ fn test_keyword_highlight() {
 let y = Self::whatever;";
 
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None);
+        write_code(&mut html, src, Edition::Edition2018, None, None);
         expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner());
     });
 }
@@ -60,7 +61,21 @@ fn test_union_highlighting() {
     create_default_session_globals_then(|| {
         let src = include_str!("fixtures/union.rs");
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None);
+        write_code(&mut html, src, Edition::Edition2018, None, None);
         expect_file!["fixtures/union.html"].assert_eq(&html.into_inner());
     });
 }
+
+#[test]
+fn test_decorations() {
+    create_default_session_globals_then(|| {
+        let src = "let x = 1;
+let y = 2;";
+        let mut decorations = FxHashMap::default();
+        decorations.insert("example", vec![(0, 10)]);
+
+        let mut html = Buffer::new();
+        write_code(&mut html, src, Edition::Edition2018, None, Some(DecorationInfo(decorations)));
+        expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner());
+    });
+}
index 6ed603c96bbf2820a5bf2c43d807e0086ddb569f..71d7cc1a09dce5b9656d6e3c9556b5db38fd6776 100644 (file)
@@ -22,6 +22,8 @@
     /// 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)]
@@ -66,10 +68,8 @@ struct PageLayout<'a> {
     let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
     let style_files = style_files
         .iter()
-        .filter_map(|t| {
-            if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
-        })
-        .filter_map(|t| if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None })
+        .filter_map(|t| t.path.file_stem().map(|stem| (stem, t.disabled)))
+        .filter_map(|t| t.0.to_str().map(|path| (path, t.1)))
         .map(|t| {
             format!(
                 r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
index 9f2e282fce1c386a7ddc32254671a31c5fac29a8..47772651bf9b9e92defd25a9ea1d0b8e32504228 100644 (file)
@@ -178,7 +178,7 @@ fn map_line(s: &str) -> Line<'_> {
         Line::Shown(Cow::Owned(s.replacen("##", "#", 1)))
     } else if let Some(stripped) = trimmed.strip_prefix("# ") {
         // # text
-        Line::Hidden(&stripped)
+        Line::Hidden(stripped)
     } else if trimmed == "#" {
         // We cannot handle '#text' because it could be #[attr].
         Line::Hidden("")
@@ -258,7 +258,7 @@ fn next(&mut self) -> Option<Self::Item> {
         let parse_result = match kind {
             CodeBlockKind::Fenced(ref lang) => {
                 let parse_result =
-                    LangString::parse_without_check(&lang, self.check_error_codes, false);
+                    LangString::parse_without_check(lang, self.check_error_codes, false);
                 if !parse_result.rust {
                     return Some(Event::Html(
                         format!(
@@ -360,6 +360,7 @@ fn dont_escape(c: u8) -> bool {
             edition,
             None,
             None,
+            None,
         );
         Some(Event::Html(s.into_inner().into()))
     }
@@ -668,7 +669,7 @@ fn next(&mut self) -> Option<Self::Item> {
         loop {
             match self.inner.next() {
                 Some((Event::FootnoteReference(ref reference), range)) => {
-                    let entry = self.get_entry(&reference);
+                    let entry = self.get_entry(reference);
                     let reference = format!(
                         "<sup id=\"fnref{0}\"><a href=\"#fn{0}\">{0}</a></sup>",
                         (*entry).1
@@ -765,7 +766,7 @@ fn next(&mut self) -> Option<Self::Item> {
                 // If there are characters between the preceding line ending and
                 // this code block, `str::lines` will return an additional line,
                 // which we subtract here.
-                if nb_lines != 0 && !&doc[prev_offset..offset.start].ends_with("\n") {
+                if nb_lines != 0 && !&doc[prev_offset..offset.start].ends_with('\n') {
                     nb_lines -= 1;
                 }
                 let line = tests.get_line() + nb_lines + 1;
@@ -903,7 +904,7 @@ fn tokens(string: &str) -> impl Iterator<Item = &str> {
         string
             .split(|c| c == ',' || c == ' ' || c == '\t')
             .map(str::trim)
-            .map(|token| if token.chars().next() == Some('.') { &token[1..] } else { token })
+            .map(|token| token.strip_prefix('.').unwrap_or(token))
             .filter(|token| !token.is_empty())
     }
 
@@ -973,7 +974,10 @@ fn parse(
                 }
                 x if extra.is_some() => {
                     let s = x.to_lowercase();
-                    match if s == "compile-fail" || s == "compile_fail" || s == "compilefail" {
+                    if let Some((flag, help)) = if s == "compile-fail"
+                        || s == "compile_fail"
+                        || s == "compilefail"
+                    {
                         Some((
                             "compile_fail",
                             "the code block will either not be tested if not marked as a rust one \
@@ -1006,15 +1010,12 @@ fn parse(
                     } else {
                         None
                     } {
-                        Some((flag, help)) => {
-                            if let Some(ref extra) = extra {
-                                extra.error_invalid_codeblock_attr(
-                                    &format!("unknown attribute `{}`. Did you mean `{}`?", x, flag),
-                                    help,
-                                );
-                            }
+                        if let Some(extra) = extra {
+                            extra.error_invalid_codeblock_attr(
+                                &format!("unknown attribute `{}`. Did you mean `{}`?", x, flag),
+                                help,
+                            );
                         }
-                        None => {}
                     }
                     seen_other_tags = true;
                 }
@@ -1050,13 +1051,10 @@ pub fn into_string(self) -> String {
             return String::new();
         }
         let mut replacer = |broken_link: BrokenLink<'_>| {
-            if let Some(link) =
-                links.iter().find(|link| &*link.original_text == broken_link.reference)
-            {
-                Some((link.href.as_str().into(), link.new_text.as_str().into()))
-            } else {
-                None
-            }
+            links
+                .iter()
+                .find(|link| &*link.original_text == broken_link.reference)
+                .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
         };
 
         let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer));
@@ -1134,13 +1132,10 @@ impl MarkdownSummaryLine<'_> {
         }
 
         let mut replacer = |broken_link: BrokenLink<'_>| {
-            if let Some(link) =
-                links.iter().find(|link| &*link.original_text == broken_link.reference)
-            {
-                Some((link.href.as_str().into(), link.new_text.as_str().into()))
-            } else {
-                None
-            }
+            links
+                .iter()
+                .find(|link| &*link.original_text == broken_link.reference)
+                .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
         };
 
         let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
@@ -1171,13 +1166,10 @@ fn markdown_summary_with_limit(
     }
 
     let mut replacer = |broken_link: BrokenLink<'_>| {
-        if let Some(link) =
-            link_names.iter().find(|link| &*link.original_text == broken_link.reference)
-        {
-            Some((link.href.as_str().into(), link.new_text.as_str().into()))
-        } else {
-            None
-        }
+        link_names
+            .iter()
+            .find(|link| &*link.original_text == broken_link.reference)
+            .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
     };
 
     let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
@@ -1412,7 +1404,7 @@ fn markdown_summary_with_limit(
                 CodeBlockKind::Indented => {
                     // The ending of the offset goes too far sometime so we reduce it by one in
                     // these cases.
-                    if offset.end > offset.start && md.get(offset.end..=offset.end) == Some(&"\n") {
+                    if offset.end > offset.start && md.get(offset.end..=offset.end) == Some("\n") {
                         (
                             LangString::default(),
                             offset.start,
index 9c05c80d55dfea35a5b8c820657ec6950d6a1394..ff1bd5e7ff289565c06076f8f7437743e1427ec4 100644 (file)
@@ -1,14 +1,13 @@
+use std::collections::hash_map::Entry;
 use std::collections::BTreeMap;
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::Symbol;
 use serde::ser::{Serialize, SerializeStruct, Serializer};
 
 use crate::clean;
-use crate::clean::types::{
-    FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate,
-};
+use crate::clean::types::{FnDecl, FnRetTy, GenericBound, Generics, Type, WherePredicate};
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::markdown::short_markdown_summary;
@@ -36,7 +35,7 @@
         if let Some(&(ref fqp, _)) = cache.paths.get(&did) {
             let desc = item
                 .doc_value()
-                .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(&cache)));
+                .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(cache)));
             cache.search_index.push(IndexItem {
                 ty: item.type_(),
                 name: item.name.unwrap().to_string(),
@@ -44,7 +43,7 @@
                 desc,
                 parent: Some(did),
                 parent_idx: None,
-                search_type: get_index_search_type(&item, tcx),
+                search_type: get_index_search_type(item, tcx),
                 aliases: item.attrs.get_doc_aliases(),
             });
         }
@@ -53,7 +52,7 @@
     let crate_doc = krate
         .module
         .doc_value()
-        .map_or_else(String::new, |s| short_markdown_summary(&s, &krate.module.link_names(&cache)));
+        .map_or_else(String::new, |s| short_markdown_summary(&s, &krate.module.link_names(cache)));
 
     let Cache { ref mut search_index, ref paths, .. } = *cache;
 
@@ -72,7 +71,7 @@
     // Set up alias indexes.
     for (i, item) in search_index.iter().enumerate() {
         for alias in &item.aliases[..] {
-            aliases.entry(alias.to_lowercase()).or_insert(Vec::new()).push(i);
+            aliases.entry(alias.to_lowercase()).or_insert_with(Vec::new).push(i);
         }
     }
 
     let mut lastpathid = 0usize;
 
     for item in search_index {
-        item.parent_idx = item.parent.and_then(|defid| {
-            if defid_to_pathid.contains_key(&defid) {
-                defid_to_pathid.get(&defid).copied()
-            } else {
+        item.parent_idx = item.parent.and_then(|defid| match defid_to_pathid.entry(defid) {
+            Entry::Occupied(entry) => Some(*entry.get()),
+            Entry::Vacant(entry) => {
                 let pathid = lastpathid;
-                defid_to_pathid.insert(defid, pathid);
+                entry.insert(pathid);
                 lastpathid += 1;
 
                 if let Some(&(ref fqp, short)) = paths.get(&defid) {
@@ -174,7 +172,7 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     // Collect the index into a string
     format!(
         r#""{}":{}"#,
-        krate.name,
+        krate.name(tcx),
         serde_json::to_string(&CrateData {
             doc: crate_doc,
             items: crate_items,
@@ -194,32 +192,24 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     item: &clean::Item,
     tcx: TyCtxt<'tcx>,
 ) -> Option<IndexItemFunctionType> {
-    let (all_types, ret_types) = match *item.kind {
+    let (mut inputs, mut output) = match *item.kind {
         clean::FunctionItem(ref f) => get_all_types(&f.generics, &f.decl, tcx),
         clean::MethodItem(ref m, _) => get_all_types(&m.generics, &m.decl, tcx),
         clean::TyMethodItem(ref m) => get_all_types(&m.generics, &m.decl, tcx),
         _ => return None,
     };
 
-    let inputs = all_types
-        .iter()
-        .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
-        .filter(|a| a.ty.name.is_some())
-        .collect();
-    let output = ret_types
-        .iter()
-        .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
-        .filter(|a| a.ty.name.is_some())
-        .collect::<Vec<_>>();
+    inputs.retain(|a| a.ty.name.is_some());
+    output.retain(|a| a.ty.name.is_some());
     let output = if output.is_empty() { None } else { Some(output) };
 
     Some(IndexItemFunctionType { inputs, output })
 }
 
-fn get_index_type(clean_type: &clean::Type) -> RenderType {
+fn get_index_type(clean_type: &clean::Type, generics: Vec<TypeWithKind>) -> RenderType {
     RenderType {
         name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()),
-        generics: get_generics(clean_type),
+        generics: if generics.is_empty() { None } else { Some(generics) },
     }
 }
 
@@ -248,23 +238,6 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option
     }
 }
 
-/// Return a list of generic parameters for use in the search index.
-///
-/// This function replaces bounds with types, so that `T where T: Debug` just becomes `Debug`.
-/// It does return duplicates, and that's intentional, since search queries like `Result<usize, usize>`
-/// are supposed to match only results where both parameters are `usize`.
-fn get_generics(clean_type: &clean::Type) -> Option<Vec<String>> {
-    clean_type.generics().and_then(|types| {
-        let r = types
-            .iter()
-            .filter_map(|t| {
-                get_index_type_name(t, false).map(|name| name.as_str().to_ascii_lowercase())
-            })
-            .collect::<Vec<_>>();
-        if r.is_empty() { None } else { Some(r) }
-    })
-}
-
 /// The point of this function is to replace bounds with types.
 ///
 /// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return
@@ -274,33 +247,86 @@ fn get_generics(clean_type: &clean::Type) -> Option<Vec<String>> {
     generics: &Generics,
     arg: &Type,
     tcx: TyCtxt<'tcx>,
-    recurse: i32,
-    res: &mut FxHashSet<(Type, ItemType)>,
-) -> usize {
-    fn insert(res: &mut FxHashSet<(Type, ItemType)>, tcx: TyCtxt<'_>, ty: Type) -> usize {
-        if let Some(kind) = ty.def_id().map(|did| tcx.def_kind(did).into()) {
-            res.insert((ty, kind));
-            1
+    recurse: usize,
+    res: &mut Vec<TypeWithKind>,
+) {
+    fn insert_ty(
+        res: &mut Vec<TypeWithKind>,
+        tcx: TyCtxt<'_>,
+        ty: Type,
+        mut generics: Vec<TypeWithKind>,
+    ) {
+        let is_full_generic = ty.is_full_generic();
+
+        if is_full_generic && generics.len() == 1 {
+            // In this case, no need to go through an intermediate state if the generics
+            // contains only one element.
+            //
+            // For example:
+            //
+            // fn foo<T: Display>(r: Option<T>) {}
+            //
+            // In this case, it would contain:
+            //
+            // ```
+            // [{
+            //     name: "option",
+            //     generics: [{
+            //         name: "",
+            //         generics: [
+            //             name: "Display",
+            //             generics: []
+            //         }]
+            //     }]
+            // }]
+            // ```
+            //
+            // After removing the intermediate (unnecessary) full generic, it'll become:
+            //
+            // ```
+            // [{
+            //     name: "option",
+            //     generics: [{
+            //         name: "Display",
+            //         generics: []
+            //     }]
+            // }]
+            // ```
+            //
+            // To be noted that it can work if there is ONLY ONE generic, otherwise we still
+            // need to keep it as is!
+            res.push(generics.pop().unwrap());
+            return;
+        }
+        let mut index_ty = get_index_type(&ty, generics);
+        if index_ty.name.as_ref().map(|s| s.is_empty()).unwrap_or(true) {
+            return;
+        }
+        if is_full_generic {
+            // We remove the name of the full generic because we have no use for it.
+            index_ty.name = Some(String::new());
+            res.push(TypeWithKind::from((index_ty, ItemType::Generic)));
+        } else if let Some(kind) = ty.def_id_no_primitives().map(|did| tcx.def_kind(did).into()) {
+            res.push(TypeWithKind::from((index_ty, kind)));
         } else if ty.is_primitive() {
             // This is a primitive, let's store it as such.
-            res.insert((ty, ItemType::Primitive));
-            1
-        } else {
-            0
+            res.push(TypeWithKind::from((index_ty, ItemType::Primitive)));
         }
     }
 
     if recurse >= 10 {
         // FIXME: remove this whole recurse thing when the recursion bug is fixed
-        return 0;
+        return;
     }
-    let mut nb_added = 0;
 
-    if let &Type::Generic(arg_s) = arg {
+    if let Type::Generic(arg_s) = *arg {
         if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g {
-            WherePredicate::BoundPredicate { ty, .. } => ty.def_id() == arg.def_id(),
+            WherePredicate::BoundPredicate { ty, .. } => {
+                ty.def_id_no_primitives() == arg.def_id_no_primitives()
+            }
             _ => false,
         }) {
+            let mut ty_generics = Vec::new();
             let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
             for bound in bounds.iter() {
                 if let GenericBound::TraitBound(poly_trait, _) = bound {
@@ -309,41 +335,32 @@ fn insert(res: &mut FxHashSet<(Type, ItemType)>, tcx: TyCtxt<'_>, ty: Type) -> u
                             continue;
                         }
                         if let Some(ty) = x.get_type() {
-                            let adds = get_real_types(generics, &ty, tcx, recurse + 1, res);
-                            nb_added += adds;
-                            if adds == 0 && !ty.is_full_generic() {
-                                nb_added += insert(res, tcx, ty);
-                            }
+                            get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics);
                         }
                     }
                 }
             }
+            insert_ty(res, tcx, arg.clone(), ty_generics);
         }
         if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
+            let mut ty_generics = Vec::new();
             for bound in bound.get_bounds().unwrap_or(&[]) {
                 if let Some(path) = bound.get_trait_path() {
                     let ty = Type::ResolvedPath { did: path.def_id(), path };
-                    let adds = get_real_types(generics, &ty, tcx, recurse + 1, res);
-                    nb_added += adds;
-                    if adds == 0 && !ty.is_full_generic() {
-                        nb_added += insert(res, tcx, ty);
-                    }
+                    get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics);
                 }
             }
+            insert_ty(res, tcx, arg.clone(), ty_generics);
         }
     } else {
-        nb_added += insert(res, tcx, arg.clone());
-        if let Some(gens) = arg.generics() {
-            for gen in gens.iter() {
-                if gen.is_full_generic() {
-                    nb_added += get_real_types(generics, gen, tcx, recurse + 1, res);
-                } else {
-                    nb_added += insert(res, tcx, (*gen).clone());
-                }
+        let mut ty_generics = Vec::new();
+        if let Some(arg_generics) = arg.generics() {
+            for gen in arg_generics.iter() {
+                get_real_types(generics, gen, tcx, recurse + 1, &mut ty_generics);
             }
         }
+        insert_ty(res, tcx, arg.clone(), ty_generics);
     }
-    nb_added
 }
 
 /// Return the full list of types when bounds have been resolved.
@@ -354,35 +371,41 @@ fn insert(res: &mut FxHashSet<(Type, ItemType)>, tcx: TyCtxt<'_>, ty: Type) -> u
     generics: &Generics,
     decl: &FnDecl,
     tcx: TyCtxt<'tcx>,
-) -> (Vec<(Type, ItemType)>, Vec<(Type, ItemType)>) {
-    let mut all_types = FxHashSet::default();
+) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) {
+    let mut all_types = Vec::new();
     for arg in decl.inputs.values.iter() {
         if arg.type_.is_self_type() {
             continue;
         }
-        let mut args = FxHashSet::default();
+        // FIXME: performance wise, it'd be much better to move `args` declaration outside of the
+        // loop and replace this line with `args.clear()`.
+        let mut args = Vec::new();
         get_real_types(generics, &arg.type_, tcx, 0, &mut args);
         if !args.is_empty() {
+            // FIXME: once back to performance improvements, replace this line with:
+            // `all_types.extend(args.drain(..));`.
             all_types.extend(args);
         } else {
-            if let Some(kind) = arg.type_.def_id().map(|did| tcx.def_kind(did).into()) {
-                all_types.insert((arg.type_.clone(), kind));
+            if let Some(kind) = arg.type_.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
+            {
+                all_types.push(TypeWithKind::from((get_index_type(&arg.type_, vec![]), kind)));
             }
         }
     }
 
-    let ret_types = match decl.output {
+    let mut ret_types = Vec::new();
+    match decl.output {
         FnRetTy::Return(ref return_type) => {
-            let mut ret = FxHashSet::default();
-            get_real_types(generics, &return_type, tcx, 0, &mut ret);
-            if ret.is_empty() {
-                if let Some(kind) = return_type.def_id().map(|did| tcx.def_kind(did).into()) {
-                    ret.insert((return_type.clone(), kind));
+            get_real_types(generics, return_type, tcx, 0, &mut ret_types);
+            if ret_types.is_empty() {
+                if let Some(kind) =
+                    return_type.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
+                {
+                    ret_types.push(TypeWithKind::from((get_index_type(return_type, vec![]), kind)));
                 }
             }
-            ret.into_iter().collect()
         }
-        _ => Vec::new(),
+        _ => {}
     };
-    (all_types.into_iter().collect(), ret_types)
+    (all_types, ret_types)
 }
index 011d3cfcf72d7a1171356fdaff2c57d5a84f6ec0..069862efde6409a0a49891cd32263b08b836a5c7 100644 (file)
@@ -6,7 +6,7 @@
 use std::sync::mpsc::{channel, Receiver};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
@@ -22,8 +22,7 @@
     BASIC_KEYWORDS,
 };
 
-use crate::clean;
-use crate::clean::ExternalCrate;
+use crate::clean::{self, ExternalCrate};
 use crate::config::RenderOptions;
 use crate::docfs::{DocFS, PathError};
 use crate::error::Error;
@@ -34,6 +33,8 @@
 use crate::html::format::Buffer;
 use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
 use crate::html::{layout, sources};
+use crate::scrape_examples::AllCallLocations;
+use crate::try_err;
 
 /// Major driving force in all rustdoc rendering. This contains information
 /// about where in the tree-like hierarchy rendering is occurring and controls
@@ -53,6 +54,9 @@
     /// real location of an item. This is used to allow external links to
     /// publicly reused items to redirect to the right location.
     pub(super) render_redirect_pages: bool,
+    /// Tracks section IDs for `Deref` targets so they match in both the main
+    /// body and the sidebar.
+    pub(super) deref_id_map: RefCell<FxHashMap<DefId, String>>,
     /// The map used to ensure all generated 'id=' attributes are unique.
     pub(super) id_map: RefCell<IdMap>,
     /// Shared mutable state.
@@ -69,7 +73,7 @@
 
 // `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Context<'_>, 104);
+rustc_data_structures::static_assert_size!(Context<'_>, 144);
 
 /// Shared mutable state used in [`Context`] and elsewhere.
 crate struct SharedContext<'tcx> {
     crate span_correspondance_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
     /// The [`Cache`] used during rendering.
     crate cache: Cache,
+
+    crate call_locations: AllCallLocations,
 }
 
 impl SharedContext<'_> {
@@ -157,7 +163,7 @@ pub(crate) fn cache(&self) -> &Cache {
     }
 
     pub(super) fn sess(&self) -> &'tcx Session {
-        &self.shared.tcx.sess
+        self.shared.tcx.sess
     }
 
     pub(super) fn derive_id(&self, id: String) -> String {
@@ -185,7 +191,7 @@ fn render_item(&self, it: &clean::Item, is_module: bool) -> String {
         };
         title.push_str(" - Rust");
         let tyname = it.type_();
-        let desc = it.doc_value().as_ref().map(|doc| plain_text_summary(&doc));
+        let desc = it.doc_value().as_ref().map(|doc| plain_text_summary(doc));
         let desc = if let Some(desc) = desc {
             desc
         } else if it.is_crate() {
@@ -291,10 +297,10 @@ fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<NameDoc
     /// may happen, for example, with externally inlined items where the source
     /// of their crate documentation isn't known.
     pub(super) fn src_href(&self, item: &clean::Item) -> Option<String> {
-        self.href_from_span(item.span(self.tcx()))
+        self.href_from_span(item.span(self.tcx()), true)
     }
 
-    crate fn href_from_span(&self, span: clean::Span) -> Option<String> {
+    crate fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Option<String> {
         if span.is_dummy() {
             return None;
         }
@@ -341,16 +347,26 @@ pub(super) fn src_href(&self, item: &clean::Item) -> Option<String> {
             (&*symbol, &path)
         };
 
-        let loline = span.lo(self.sess()).line;
-        let hiline = span.hi(self.sess()).line;
-        let lines =
-            if loline == hiline { loline.to_string() } else { format!("{}-{}", loline, hiline) };
+        let anchor = if with_lines {
+            let loline = span.lo(self.sess()).line;
+            let hiline = span.hi(self.sess()).line;
+            format!(
+                "#{}",
+                if loline == hiline {
+                    loline.to_string()
+                } else {
+                    format!("{}-{}", loline, hiline)
+                }
+            )
+        } else {
+            "".to_string()
+        };
         Some(format!(
-            "{root}src/{krate}/{path}#{lines}",
+            "{root}src/{krate}/{path}{anchor}",
             root = Escape(&root),
             krate = krate,
             path = path,
-            lines = lines
+            anchor = anchor
         ))
     }
 }
@@ -388,10 +404,11 @@ fn init(
             generate_redirect_map,
             show_type_layout,
             generate_link_to_definition,
+            call_locations,
             ..
         } = options;
 
-        let src_root = match krate.src {
+        let src_root = match krate.src(tcx) {
             FileName::Real(ref p) => match p.local_path_if_available().parent() {
                 Some(p) => p.to_path_buf(),
                 None => PathBuf::new(),
@@ -402,16 +419,17 @@ fn init(
         let mut playground = None;
         if let Some(url) = playground_url {
             playground =
-                Some(markdown::Playground { crate_name: Some(krate.name.to_string()), url });
+                Some(markdown::Playground { crate_name: Some(krate.name(tcx).to_string()), url });
         }
         let mut layout = layout::Layout {
             logo: String::new(),
             favicon: String::new(),
             external_html,
             default_settings,
-            krate: krate.name.to_string(),
+            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;
@@ -429,7 +447,7 @@ fn init(
                 }
                 (sym::html_playground_url, Some(s)) => {
                     playground = Some(markdown::Playground {
-                        crate_name: Some(krate.name.to_string()),
+                        crate_name: Some(krate.name(tcx).to_string()),
                         url: s.to_string(),
                     });
                 }
@@ -443,9 +461,9 @@ fn init(
             }
         }
 
-        let (mut krate, local_sources, matches) = collect_spans_and_sources(
+        let (local_sources, matches) = collect_spans_and_sources(
             tcx,
-            krate,
+            &krate,
             &src_root,
             include_sources,
             generate_link_to_definition,
@@ -474,6 +492,7 @@ fn init(
             templates,
             span_correspondance_map: matches,
             cache,
+            call_locations,
         };
 
         // Add the default themes to the `Vec` of stylepaths
@@ -497,12 +516,13 @@ fn init(
             dst,
             render_redirect_pages: false,
             id_map: RefCell::new(id_map),
+            deref_id_map: RefCell::new(FxHashMap::default()),
             shared: Rc::new(scx),
             include_sources,
         };
 
         if emit_crate {
-            krate = sources::render(&mut cx, krate)?;
+            sources::render(&mut cx, &krate)?;
         }
 
         // Build our search index
@@ -520,6 +540,7 @@ fn make_child_renderer(&self) -> Self {
             current: self.current.clone(),
             dst: self.dst.clone(),
             render_redirect_pages: self.render_redirect_pages,
+            deref_id_map: RefCell::new(FxHashMap::default()),
             id_map: RefCell::new(IdMap::new()),
             shared: Rc::clone(&self.shared),
             include_sources: self.include_sources,
index 69c5c2c4abc2a4bcfd085fa68dd07c15c3a9419f..25fef114d95fd8bc67cb857ff9f3670856a4f41d 100644 (file)
 use std::collections::VecDeque;
 use std::default::Default;
 use std::fmt;
+use std::fs;
+use std::iter::Peekable;
 use std::path::PathBuf;
 use std::str;
 use std::string::ToString;
 
 use rustc_ast_pretty::pprust;
 use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::Mutability;
 use rustc_middle::middle::stability;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::{
+    symbol::{kw, sym, Symbol},
+    BytePos, FileName, RealFileName,
+};
 use serde::ser::SerializeSeq;
 use serde::{Serialize, Serializer};
 
-use crate::clean::{self, GetDefId, ItemId, RenderedLink, SelfTy};
+use crate::clean::{self, ItemId, RenderedLink, SelfTy};
 use crate::docfs::PathError;
 use crate::error::Error;
 use crate::formats::cache::Cache;
     href, 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};
+use crate::html::sources;
+use crate::scrape_examples::{CallData, CallLocation};
+use crate::try_none;
 
 /// A pair of name and its optional document.
 crate type NameDoc = (String, Option<String>);
 #[derive(Debug)]
 crate struct RenderType {
     name: Option<String>,
-    generics: Option<Vec<String>>,
+    generics: Option<Vec<TypeWithKind>>,
 }
 
 /// Full type of functions/methods in the search index.
@@ -118,8 +127,8 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
         // If we couldn't figure out a type, just write `null`.
         let mut iter = self.inputs.iter();
         if match self.output {
-            Some(ref output) => iter.chain(output.iter()).any(|ref i| i.ty.name.is_none()),
-            None => iter.any(|ref i| i.ty.name.is_none()),
+            Some(ref output) => iter.chain(output.iter()).any(|i| i.ty.name.is_none()),
+            None => iter.any(|i| i.ty.name.is_none()),
         } {
             serializer.serialize_none()
         } else {
@@ -585,6 +594,14 @@ fn document_full_inner(
             render_markdown(w, cx, &s, item.links(cx), heading_offset);
         }
     }
+
+    let kind = match &*item.kind {
+        clean::ItemKind::StrippedItem(box kind) | kind => kind,
+    };
+
+    if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind {
+        render_call_locations(w, cx, item);
+    }
 }
 
 /// Add extra information about an item such as:
@@ -890,7 +907,7 @@ fn method(
             AssocItemLink::GotoSource(did, provided_methods) => {
                 // We're creating a link from an impl-item to the corresponding
                 // trait-item and need to map the anchored type accordingly.
-                let ty = if provided_methods.contains(&name) {
+                let ty = if provided_methods.contains(name) {
                     ItemType::Method
                 } else {
                     ItemType::TyMethod
@@ -949,7 +966,7 @@ fn method(
             name = name,
             generics = g.print(cx),
             decl = d.full_print(header_len, indent, header.asyncness, cx),
-            notable_traits = notable_traits_decl(&d, cx),
+            notable_traits = notable_traits_decl(d, cx),
             where_clause = print_where_clause(g, cx, indent, end_newline),
         )
     }
@@ -992,7 +1009,7 @@ fn attributes(it: &clean::Item) -> Vec<String> {
         .iter()
         .filter_map(|attr| {
             if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
-                Some(pprust::attribute_to_string(&attr).replace("\n", "").replace("  ", " "))
+                Some(pprust::attribute_to_string(attr).replace("\n", "").replace("  ", " "))
             } else {
                 None
             }
@@ -1025,7 +1042,7 @@ enum AssocItemLink<'a> {
 impl<'a> AssocItemLink<'a> {
     fn anchor(&self, id: &'a str) -> Self {
         match *self {
-            AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(&id)),
+            AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(id)),
             ref other => *other,
         }
     }
@@ -1037,6 +1054,19 @@ fn render_assoc_items(
     containing_item: &clean::Item,
     it: DefId,
     what: AssocItemRender<'_>,
+) {
+    let mut derefs = FxHashSet::default();
+    derefs.insert(it);
+    render_assoc_items_inner(w, cx, containing_item, it, what, &mut derefs)
+}
+
+fn render_assoc_items_inner(
+    w: &mut Buffer,
+    cx: &Context<'_>,
+    containing_item: &clean::Item,
+    it: DefId,
+    what: AssocItemRender<'_>,
+    derefs: &mut FxHashSet<DefId>,
 ) {
     info!("Documenting associated items of {:?}", containing_item.name);
     let cache = cx.cache();
@@ -1046,9 +1076,10 @@ fn render_assoc_items(
     };
     let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
     if !non_trait.is_empty() {
+        let mut tmp_buf = Buffer::empty_from(w);
         let render_mode = match what {
             AssocItemRender::All => {
-                w.write_str(
+                tmp_buf.write_str(
                     "<h2 id=\"implementations\" class=\"small-section-header\">\
                          Implementations<a href=\"#implementations\" class=\"anchor\"></a>\
                     </h2>",
@@ -1056,21 +1087,28 @@ fn render_assoc_items(
                 RenderMode::Normal
             }
             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
+                let id =
+                    cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
+                if let Some(def_id) = type_.def_id(cx.cache()) {
+                    cx.deref_id_map.borrow_mut().insert(def_id, id.clone());
+                }
                 write!(
-                    w,
-                    "<h2 id=\"deref-methods\" class=\"small-section-header\">\
+                    tmp_buf,
+                    "<h2 id=\"{id}\" class=\"small-section-header\">\
                          <span>Methods from {trait_}&lt;Target = {type_}&gt;</span>\
-                         <a href=\"#deref-methods\" class=\"anchor\"></a>\
+                         <a href=\"#{id}\" class=\"anchor\"></a>\
                      </h2>",
+                    id = id,
                     trait_ = trait_.print(cx),
                     type_ = type_.print(cx),
                 );
                 RenderMode::ForDeref { mut_: deref_mut_ }
             }
         };
+        let mut impls_buf = Buffer::empty_from(w);
         for i in &non_trait {
             render_impl(
-                w,
+                &mut impls_buf,
                 cx,
                 i,
                 containing_item,
@@ -1087,24 +1125,33 @@ fn render_assoc_items(
                 },
             );
         }
+        if !impls_buf.is_empty() {
+            w.push_buffer(tmp_buf);
+            w.push_buffer(impls_buf);
+        }
     }
-    if let AssocItemRender::DerefFor { .. } = what {
-        return;
-    }
+
     if !traits.is_empty() {
         let deref_impl =
             traits.iter().find(|t| t.trait_did() == cx.tcx().lang_items().deref_trait());
         if let Some(impl_) = deref_impl {
             let has_deref_mut =
                 traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait());
-            render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
+            render_deref_methods(w, cx, impl_, containing_item, has_deref_mut, derefs);
+        }
+
+        // If we were already one level into rendering deref methods, we don't want to render
+        // anything after recursing into any further deref methods above.
+        if let AssocItemRender::DerefFor { .. } = what {
+            return;
         }
+
         let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
             traits.iter().partition(|t| t.inner_impl().synthetic);
         let (blanket_impl, concrete): (Vec<&&Impl>, _) =
             concrete.into_iter().partition(|t| t.inner_impl().blanket_impl.is_some());
 
-        let mut impls = Buffer::empty_from(&w);
+        let mut impls = Buffer::empty_from(w);
         render_impls(cx, &mut impls, &concrete, containing_item);
         let impls = impls.into_inner();
         if !impls.is_empty() {
@@ -1150,6 +1197,7 @@ fn render_deref_methods(
     impl_: &Impl,
     container_item: &clean::Item,
     deref_mut: bool,
+    derefs: &mut FxHashSet<DefId>,
 ) {
     let cache = cx.cache();
     let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
@@ -1168,19 +1216,19 @@ fn render_deref_methods(
     debug!("Render deref methods for {:#?}, target {:#?}", impl_.inner_impl().for_, target);
     let what =
         AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
-    if let Some(did) = target.def_id_full(cache) {
-        if let Some(type_did) = impl_.inner_impl().for_.def_id_full(cache) {
+    if let Some(did) = target.def_id(cache) {
+        if let Some(type_did) = impl_.inner_impl().for_.def_id(cache) {
             // `impl Deref<Target = S> for S`
-            if did == type_did {
+            if did == type_did || !derefs.insert(did) {
                 // Avoid infinite cycles
                 return;
             }
         }
-        render_assoc_items(w, cx, container_item, did, what);
+        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(w, cx, container_item, did, what);
+                render_assoc_items_inner(w, cx, container_item, did, what, derefs);
             }
         }
     }
@@ -1215,7 +1263,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
 fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
     let mut out = Buffer::html();
 
-    if let Some(did) = decl.output.def_id_full(cx.cache()) {
+    if let Some(did) = decl.output.as_return().and_then(|t| t.def_id(cx.cache())) {
         if let Some(impls) = cx.cache().impls.get(&did) {
             for i in impls {
                 let impl_ = i.inner_impl();
@@ -1317,7 +1365,7 @@ fn doc_impl_item(
             && match render_mode {
                 RenderMode::Normal => true,
                 RenderMode::ForDeref { mut_: deref_mut_ } => {
-                    should_render_item(&item, deref_mut_, cx.tcx())
+                    should_render_item(item, deref_mut_, cx.tcx())
                 }
             };
 
@@ -1550,7 +1598,7 @@ fn render_default_items(
                 &mut impl_items,
                 cx,
                 &t.trait_,
-                &i.inner_impl(),
+                i.inner_impl(),
                 &i.impl_item,
                 parent,
                 render_mode,
@@ -1596,7 +1644,7 @@ fn render_default_items(
                     error_codes: cx.shared.codes,
                     edition: cx.shared.edition(),
                     playground: &cx.shared.playground,
-                    heading_offset: HeadingOffset::H2
+                    heading_offset: HeadingOffset::H4
                 }
                 .into_string()
             );
@@ -1970,7 +2018,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
             if let Some(impl_) =
                 v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait())
             {
-                sidebar_deref_methods(cx, out, impl_, v);
+                let mut derefs = FxHashSet::default();
+                derefs.insert(did);
+                sidebar_deref_methods(cx, out, impl_, v, &mut derefs);
             }
 
             let format_impls = |impls: Vec<&Impl>| {
@@ -2044,7 +2094,13 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
     }
 }
 
-fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &Vec<Impl>) {
+fn sidebar_deref_methods(
+    cx: &Context<'_>,
+    out: &mut Buffer,
+    impl_: &Impl,
+    v: &[Impl],
+    derefs: &mut FxHashSet<DefId>,
+) {
     let c = cx.cache();
 
     debug!("found Deref: {:?}", impl_);
@@ -2058,10 +2114,10 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
         })
     {
         debug!("found target, real_target: {:?} {:?}", target, real_target);
-        if let Some(did) = target.def_id_full(c) {
-            if let Some(type_did) = impl_.inner_impl().for_.def_id_full(c) {
+        if let Some(did) = target.def_id(c) {
+            if let Some(type_did) = impl_.inner_impl().for_.def_id(c) {
                 // `impl Deref<Target = S> for S`
-                if did == type_did {
+                if did == type_did || !derefs.insert(did) {
                     // Avoid infinite cycles
                     return;
                 }
@@ -2069,7 +2125,7 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
         }
         let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait());
         let inner_impl = target
-            .def_id_full(c)
+            .def_id(c)
             .or_else(|| {
                 target.primitive_type().and_then(|prim| c.primitive_locations.get(&prim).cloned())
             })
@@ -2085,9 +2141,17 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
                 })
                 .collect::<Vec<_>>();
             if !ret.is_empty() {
+                let map;
+                let id = if let Some(target_def_id) = real_target.def_id(c) {
+                    map = cx.deref_id_map.borrow();
+                    map.get(&target_def_id).expect("Deref section without derived id")
+                } else {
+                    "deref-methods"
+                };
                 write!(
                     out,
-                    "<h3 class=\"sidebar-title\"><a href=\"#deref-methods\">Methods from {}&lt;Target={}&gt;</a></h3>",
+                    "<h3 class=\"sidebar-title\"><a href=\"#{}\">Methods from {}&lt;Target={}&gt;</a></h3>",
+                    id,
                     Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
                     Escape(&format!("{:#}", real_target.print(cx))),
                 );
@@ -2100,6 +2164,21 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
                 out.push_str("</div>");
             }
         }
+
+        // Recurse into any further impls that might exist for `target`
+        if let Some(target_did) = target.def_id_no_primitives() {
+            if let Some(target_impls) = c.impls.get(&target_did) {
+                if let Some(target_deref_impl) = target_impls.iter().find(|i| {
+                    i.inner_impl()
+                        .trait_
+                        .as_ref()
+                        .map(|t| Some(t.def_id()) == cx.tcx().lang_items().deref_trait())
+                        .unwrap_or(false)
+                }) {
+                    sidebar_deref_methods(cx, out, target_deref_impl, target_impls, derefs);
+                }
+            }
+        }
     }
 }
 
@@ -2143,16 +2222,14 @@ fn get_id_for_impl_on_foreign_type(
 fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
     match *item.kind {
         clean::ItemKind::ImplItem(ref i) => {
-            if let Some(ref trait_) = i.trait_ {
+            i.trait_.as_ref().map(|trait_| {
                 // Alternative format produces no URLs,
                 // so this parameter does nothing.
-                Some((
+                (
                     format!("{:#}", i.for_.print(cx)),
                     get_id_for_impl_on_foreign_type(&i.for_, trait_, cx),
-                ))
-            } else {
-                None
-            }
+                )
+            })
         }
         _ => None,
     }
@@ -2232,10 +2309,7 @@ fn print_sidebar_section(
         let mut res = implementors
             .iter()
             .filter(|i| {
-                i.inner_impl()
-                    .for_
-                    .def_id_full(cache)
-                    .map_or(false, |d| !cache.paths.contains_key(&d))
+                i.inner_impl().for_.def_id(cache).map_or(false, |d| !cache.paths.contains_key(&d))
             })
             .filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
             .collect::<Vec<_>>();
@@ -2327,9 +2401,10 @@ fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean:
     let mut variants = e
         .variants
         .iter()
-        .filter_map(|v| match v.name {
-            Some(ref name) => Some(format!("<a href=\"#variant.{name}\">{name}</a>", name = name)),
-            _ => None,
+        .filter_map(|v| {
+            v.name
+                .as_ref()
+                .map(|name| format!("<a href=\"#variant.{name}\">{name}</a>", name = name))
         })
         .collect::<Vec<_>>();
     if !variants.is_empty() {
@@ -2375,6 +2450,7 @@ fn item_ty_to_strs(ty: ItemType) -> (&'static str, &'static str) {
         ItemType::ProcAttribute => ("attributes", "Attribute Macros"),
         ItemType::ProcDerive => ("derives", "Derive Macros"),
         ItemType::TraitAlias => ("trait-aliases", "Trait aliases"),
+        ItemType::Generic => unreachable!(),
     }
 }
 
@@ -2490,3 +2566,228 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
     }
     out
 }
+
+const MAX_FULL_EXAMPLES: usize = 5;
+const NUM_VISIBLE_LINES: usize = 10;
+
+/// Generates the HTML for example call locations generated via the --scrape-examples flag.
+fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
+    let tcx = cx.tcx();
+    let def_id = item.def_id.expect_def_id();
+    let key = tcx.def_path_hash(def_id);
+    let call_locations = match cx.shared.call_locations.get(&key) {
+        Some(call_locations) => call_locations,
+        _ => {
+            return;
+        }
+    };
+
+    // Generate a unique ID so users can link to this section for a given method
+    let id = cx.id_map.borrow_mut().derive("scraped-examples");
+    write!(
+        w,
+        "<div class=\"docblock scraped-example-list\">\
+          <span></span>\
+          <h5 id=\"{id}\" class=\"section-header\">\
+             <a href=\"#{id}\">Examples found in repository</a>\
+          </h5>",
+        id = id
+    );
+
+    // Create a URL to a particular location in a reverse-dependency's source file
+    let link_to_loc = |call_data: &CallData, loc: &CallLocation| -> (String, String) {
+        let (line_lo, line_hi) = loc.call_expr.line_span;
+        let (anchor, title) = if line_lo == line_hi {
+            ((line_lo + 1).to_string(), format!("line {}", line_lo + 1))
+        } else {
+            (
+                format!("{}-{}", line_lo + 1, line_hi + 1),
+                format!("lines {}-{}", line_lo + 1, line_hi + 1),
+            )
+        };
+        let url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor);
+        (url, title)
+    };
+
+    // Generate the HTML for a single example, being the title and code block
+    let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| -> bool {
+        let contents = match fs::read_to_string(&path) {
+            Ok(contents) => contents,
+            Err(err) => {
+                let span = item.span(tcx).inner();
+                tcx.sess
+                    .span_err(span, &format!("failed to read file {}: {}", path.display(), err));
+                return false;
+            }
+        };
+
+        // To reduce file sizes, we only want to embed the source code needed to understand the example, not
+        // the entire file. So we find the smallest byte range that covers all items enclosing examples.
+        assert!(!call_data.locations.is_empty());
+        let min_loc =
+            call_data.locations.iter().min_by_key(|loc| loc.enclosing_item.byte_span.0).unwrap();
+        let byte_min = min_loc.enclosing_item.byte_span.0;
+        let line_min = min_loc.enclosing_item.line_span.0;
+        let max_loc =
+            call_data.locations.iter().max_by_key(|loc| loc.enclosing_item.byte_span.1).unwrap();
+        let byte_max = max_loc.enclosing_item.byte_span.1;
+        let line_max = max_loc.enclosing_item.line_span.1;
+
+        // The output code is limited to that byte range.
+        let contents_subset = &contents[(byte_min as usize)..(byte_max as usize)];
+
+        // The call locations need to be updated to reflect that the size of the program has changed.
+        // Specifically, the ranges are all subtracted by `byte_min` since that's the new zero point.
+        let (mut byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data
+            .locations
+            .iter()
+            .map(|loc| {
+                let (byte_lo, byte_hi) = loc.call_expr.byte_span;
+                let (line_lo, line_hi) = loc.call_expr.line_span;
+                let byte_range = (byte_lo - byte_min, byte_hi - byte_min);
+                let line_range = (line_lo - line_min, line_hi - line_min);
+                let (line_url, line_title) = link_to_loc(call_data, loc);
+
+                (byte_range, (line_range, line_url, line_title))
+            })
+            .unzip();
+
+        let (_, init_url, init_title) = &line_ranges[0];
+        let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES;
+        let locations_encoded = serde_json::to_string(&line_ranges).unwrap();
+
+        write!(
+            w,
+            "<div class=\"scraped-example {expanded_cls}\" data-locs=\"{locations}\">\
+                <div class=\"scraped-example-title\">\
+                   {name} (<a href=\"{url}\">{title}</a>)\
+                </div>\
+                <div class=\"code-wrapper\">",
+            expanded_cls = if needs_expansion { "" } else { "expanded" },
+            name = call_data.display_name,
+            url = init_url,
+            title = init_title,
+            // The locations are encoded as a data attribute, so they can be read
+            // later by the JS for interactions.
+            locations = Escape(&locations_encoded)
+        );
+
+        if line_ranges.len() > 1 {
+            write!(w, r#"<span class="prev">&pr;</span> <span class="next">&sc;</span>"#);
+        }
+
+        if needs_expansion {
+            write!(w, r#"<span class="expand">&varr;</span>"#);
+        }
+
+        // Look for the example file in the source map if it exists, otherwise return a dummy span
+        let file_span = (|| {
+            let source_map = tcx.sess.source_map();
+            let crate_src = tcx.sess.local_crate_source_file.as_ref()?;
+            let abs_crate_src = crate_src.canonicalize().ok()?;
+            let crate_root = abs_crate_src.parent()?.parent()?;
+            let rel_path = path.strip_prefix(crate_root).ok()?;
+            let files = source_map.files();
+            let file = files.iter().find(|file| match &file.name {
+                FileName::Real(RealFileName::LocalPath(other_path)) => rel_path == other_path,
+                _ => false,
+            })?;
+            Some(rustc_span::Span::with_root_ctxt(
+                file.start_pos + BytePos(byte_min),
+                file.start_pos + BytePos(byte_max),
+            ))
+        })()
+        .unwrap_or(rustc_span::DUMMY_SP);
+
+        // The root path is the inverse of Context::current
+        let root_path = vec!["../"; cx.current.len() - 1].join("");
+
+        let mut decoration_info = FxHashMap::default();
+        decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
+        decoration_info.insert("highlight", byte_ranges);
+
+        sources::print_src(
+            w,
+            contents_subset,
+            call_data.edition,
+            file_span,
+            cx,
+            &root_path,
+            Some(highlight::DecorationInfo(decoration_info)),
+            sources::SourceContext::Embedded { offset: line_min },
+        );
+        write!(w, "</div></div>");
+
+        true
+    };
+
+    // The call locations are output in sequence, so that sequence needs to be determined.
+    // Ideally the most "relevant" examples would be shown first, but there's no general algorithm
+    // for determining relevance. Instead, we prefer the smallest examples being likely the easiest to
+    // understand at a glance.
+    let ordered_locations = {
+        let sort_criterion = |(_, call_data): &(_, &CallData)| {
+            // Use the first location because that's what the user will see initially
+            let (lo, hi) = call_data.locations[0].enclosing_item.byte_span;
+            hi - lo
+        };
+
+        let mut locs = call_locations.into_iter().collect::<Vec<_>>();
+        locs.sort_by_key(sort_criterion);
+        locs
+    };
+
+    let mut it = ordered_locations.into_iter().peekable();
+
+    // An example may fail to write if its source can't be read for some reason, so this method
+    // continues iterating until a write suceeds
+    let write_and_skip_failure = |w: &mut Buffer, it: &mut Peekable<_>| {
+        while let Some(example) = it.next() {
+            if write_example(&mut *w, example) {
+                break;
+            }
+        }
+    };
+
+    // Write just one example that's visible by default in the method's description.
+    write_and_skip_failure(w, &mut it);
+
+    // Then add the remaining examples in a hidden section.
+    if it.peek().is_some() {
+        write!(
+            w,
+            "<details class=\"rustdoc-toggle more-examples-toggle\">\
+                  <summary class=\"hideme\">\
+                     <span>More examples</span>\
+                  </summary>\
+                  <div class=\"more-scraped-examples\">\
+                    <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>\
+                    <div class=\"more-scraped-examples-inner\">"
+        );
+
+        // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
+        // make the page arbitrarily huge!
+        for _ in 0..MAX_FULL_EXAMPLES {
+            write_and_skip_failure(w, &mut it);
+        }
+
+        // For the remaining examples, generate a <ul> containing links to the source files.
+        if it.peek().is_some() {
+            write!(w, r#"<div class="example-links">Additional examples can be found in:<br><ul>"#);
+            it.for_each(|(_, call_data)| {
+                let (url, _) = link_to_loc(&call_data, &call_data.locations[0]);
+                write!(
+                    w,
+                    r#"<li><a href="{url}">{name}</a></li>"#,
+                    url = url,
+                    name = call_data.display_name
+                );
+            });
+            write!(w, "</ul></div>");
+        }
+
+        write!(w, "</div></div></details>");
+    }
+
+    write!(w, "</div>");
+}
index 4cfc57ac99588d5aa859424438111c0a6a8c44f3..d07ef6db4c6b0127e230d267e2d9e2f06be85bcd 100644 (file)
@@ -21,7 +21,7 @@
     render_impl, render_stability_since_raw, write_srclink, AssocItemLink, Context,
     ImplRenderingParameters,
 };
-use crate::clean::{self, GetDefId};
+use crate::clean;
 use crate::formats::item_type::ItemType;
 use crate::formats::{AssocItemRender, Impl, RenderMode};
 use crate::html::escape::Escape;
 
 use serde::Serialize;
 
-const ITEM_TABLE_OPEN: &'static str = "<div class=\"item-table\">";
-const ITEM_TABLE_CLOSE: &'static str = "</div>";
-const ITEM_TABLE_ROW_OPEN: &'static str = "<div class=\"item-row\">";
-const ITEM_TABLE_ROW_CLOSE: &'static str = "</div>";
+const ITEM_TABLE_OPEN: &str = "<div class=\"item-table\">";
+const ITEM_TABLE_CLOSE: &str = "</div>";
+const ITEM_TABLE_ROW_OPEN: &str = "<div class=\"item-row\">";
+const ITEM_TABLE_ROW_CLOSE: &str = "</div>";
 
 // A component in a `use` path, like `string` in std::string::ToString
 #[derive(Serialize)]
@@ -482,24 +482,26 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
         + name.as_str().len()
         + generics_len;
 
-    wrap_item(w, "fn", |w| {
-        render_attributes_in_pre(w, it, "");
-        w.reserve(header_len);
-        write!(
-            w,
-            "{vis}{constness}{asyncness}{unsafety}{abi}fn \
-             {name}{generics}{decl}{notable_traits}{where_clause}",
-            vis = vis,
-            constness = constness,
-            asyncness = asyncness,
-            unsafety = unsafety,
-            abi = abi,
-            name = name,
-            generics = f.generics.print(cx),
-            where_clause = print_where_clause(&f.generics, cx, 0, true),
-            decl = f.decl.full_print(header_len, 0, f.header.asyncness, cx),
-            notable_traits = notable_traits_decl(&f.decl, cx),
-        );
+    wrap_into_docblock(w, |w| {
+        wrap_item(w, "fn", |w| {
+            render_attributes_in_pre(w, it, "");
+            w.reserve(header_len);
+            write!(
+                w,
+                "{vis}{constness}{asyncness}{unsafety}{abi}fn \
+                 {name}{generics}{decl}{notable_traits}{where_clause}",
+                vis = vis,
+                constness = constness,
+                asyncness = asyncness,
+                unsafety = unsafety,
+                abi = abi,
+                name = name,
+                generics = f.generics.print(cx),
+                where_clause = print_where_clause(&f.generics, cx, 0, true),
+                decl = f.decl.full_print(header_len, 0, f.header.asyncness, cx),
+                notable_traits = notable_traits_decl(&f.decl, cx),
+            );
+        });
     });
     document(w, cx, it, None, HeadingOffset::H2)
 }
@@ -740,7 +742,7 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
         }
 
         let (local, foreign) = implementors.iter().partition::<Vec<_>, _>(|i| {
-            i.inner_impl().for_.def_id_full(cache).map_or(true, |d| cache.paths.contains_key(&d))
+            i.inner_impl().for_.def_id(cache).map_or(true, |d| cache.paths.contains_key(&d))
         });
 
         let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
@@ -759,7 +761,7 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
                 render_impl(
                     w,
                     cx,
-                    &implementor,
+                    implementor,
                     it,
                     assoc_link,
                     RenderMode::Normal,
@@ -844,16 +846,18 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
 }
 
 fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::TraitAlias) {
-    wrap_item(w, "trait-alias", |w| {
-        render_attributes_in_pre(w, it, "");
-        write!(
-            w,
-            "trait {}{}{} = {};",
-            it.name.as_ref().unwrap(),
-            t.generics.print(cx),
-            print_where_clause(&t.generics, cx, 0, true),
-            bounds(&t.bounds, true, cx)
-        );
+    wrap_into_docblock(w, |w| {
+        wrap_item(w, "trait-alias", |w| {
+            render_attributes_in_pre(w, it, "");
+            write!(
+                w,
+                "trait {}{}{} = {};",
+                it.name.as_ref().unwrap(),
+                t.generics.print(cx),
+                print_where_clause(&t.generics, cx, 0, true),
+                bounds(&t.bounds, true, cx)
+            );
+        });
     });
 
     document(w, cx, it, None, HeadingOffset::H2);
@@ -866,16 +870,18 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea
 }
 
 fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
-    wrap_item(w, "opaque", |w| {
-        render_attributes_in_pre(w, it, "");
-        write!(
-            w,
-            "type {}{}{where_clause} = impl {bounds};",
-            it.name.as_ref().unwrap(),
-            t.generics.print(cx),
-            where_clause = print_where_clause(&t.generics, cx, 0, true),
-            bounds = bounds(&t.bounds, false, cx),
-        );
+    wrap_into_docblock(w, |w| {
+        wrap_item(w, "opaque", |w| {
+            render_attributes_in_pre(w, it, "");
+            write!(
+                w,
+                "type {}{}{where_clause} = impl {bounds};",
+                it.name.as_ref().unwrap(),
+                t.generics.print(cx),
+                where_clause = print_where_clause(&t.generics, cx, 0, true),
+                bounds = bounds(&t.bounds, false, cx),
+            );
+        });
     });
 
     document(w, cx, it, None, HeadingOffset::H2);
@@ -894,20 +900,37 @@ fn item_typedef(
     t: &clean::Typedef,
     is_associated: bool,
 ) {
-    wrap_item(w, "typedef", |w| {
-        render_attributes_in_pre(w, it, "");
-        if !is_associated {
-            write!(w, "{}", it.visibility.print_with_space(it.def_id, cx));
-        }
-        write!(
-            w,
-            "type {}{}{where_clause} = {type_};",
-            it.name.as_ref().unwrap(),
-            t.generics.print(cx),
-            where_clause = print_where_clause(&t.generics, cx, 0, true),
-            type_ = t.type_.print(cx),
-        );
-    });
+    fn write_content(
+        w: &mut Buffer,
+        cx: &Context<'_>,
+        it: &clean::Item,
+        t: &clean::Typedef,
+        is_associated: bool,
+    ) {
+        wrap_item(w, "typedef", |w| {
+            render_attributes_in_pre(w, it, "");
+            if !is_associated {
+                write!(w, "{}", it.visibility.print_with_space(it.def_id, cx));
+            }
+            write!(
+                w,
+                "type {}{}{where_clause} = {type_};",
+                it.name.as_ref().unwrap(),
+                t.generics.print(cx),
+                where_clause = print_where_clause(&t.generics, cx, 0, true),
+                type_ = t.type_.print(cx),
+            );
+        });
+    }
+
+    // If this is an associated typedef, we don't want to wrap it into a docblock.
+    if is_associated {
+        write_content(w, cx, it, t, is_associated);
+    } else {
+        wrap_into_docblock(w, |w| {
+            write_content(w, cx, it, t, is_associated);
+        });
+    }
 
     document(w, cx, it, None, HeadingOffset::H2);
 
@@ -960,7 +983,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
             if let Some(stability_class) = field.stability_class(cx.tcx()) {
                 write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class);
             }
-            document(w, cx, field, Some(it), HeadingOffset::H2);
+            document(w, cx, field, Some(it), HeadingOffset::H3);
         }
     }
     let def_id = it.def_id.expect_def_id();
@@ -1071,7 +1094,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
             w.write_str("</code>");
             render_stability_since(w, variant, it, cx.tcx());
             w.write_str("</div>");
-            document(w, cx, variant, Some(it), HeadingOffset::H2);
+            document(w, cx, variant, Some(it), HeadingOffset::H3);
             document_non_exhaustive(w, variant);
 
             use crate::clean::Variant;
@@ -1111,7 +1134,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                                 f = field.name.as_ref().unwrap(),
                                 t = ty.print(cx)
                             );
-                            document(w, cx, field, Some(variant), HeadingOffset::H2);
+                            document(w, cx, field, Some(variant), HeadingOffset::H4);
                         }
                         _ => unreachable!(),
                     }
@@ -1136,38 +1159,41 @@ fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Mac
             it.span(cx.tcx()).inner().edition(),
             None,
             None,
+            None,
         );
     });
     document(w, cx, it, None, HeadingOffset::H2)
 }
 
 fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) {
-    let name = it.name.as_ref().expect("proc-macros always have names");
-    match m.kind {
-        MacroKind::Bang => {
-            wrap_item(w, "macro", |w| {
-                write!(w, "{}!() {{ /* proc-macro */ }}", name);
-            });
-        }
-        MacroKind::Attr => {
-            wrap_item(w, "attr", |w| {
-                write!(w, "#[{}]", name);
-            });
-        }
-        MacroKind::Derive => {
-            wrap_item(w, "derive", |w| {
-                write!(w, "#[derive({})]", name);
-                if !m.helpers.is_empty() {
-                    w.push_str("\n{\n");
-                    w.push_str("    // Attributes available to this derive:\n");
-                    for attr in &m.helpers {
-                        writeln!(w, "    #[{}]", attr);
+    wrap_into_docblock(w, |w| {
+        let name = it.name.as_ref().expect("proc-macros always have names");
+        match m.kind {
+            MacroKind::Bang => {
+                wrap_item(w, "macro", |w| {
+                    write!(w, "{}!() {{ /* proc-macro */ }}", name);
+                });
+            }
+            MacroKind::Attr => {
+                wrap_item(w, "attr", |w| {
+                    write!(w, "#[{}]", name);
+                });
+            }
+            MacroKind::Derive => {
+                wrap_item(w, "derive", |w| {
+                    write!(w, "#[derive({})]", name);
+                    if !m.helpers.is_empty() {
+                        w.push_str("\n{\n");
+                        w.push_str("    // Attributes available to this derive:\n");
+                        for attr in &m.helpers {
+                            writeln!(w, "    #[{}]", attr);
+                        }
+                        w.push_str("}\n");
                     }
-                    w.push_str("}\n");
-                }
-            });
+                });
+            }
         }
-    }
+    });
     document(w, cx, it, None, HeadingOffset::H2)
 }
 
@@ -1177,38 +1203,40 @@ fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
 }
 
 fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::Constant) {
-    wrap_item(w, "const", |w| {
-        render_attributes_in_code(w, it);
+    wrap_into_docblock(w, |w| {
+        wrap_item(w, "const", |w| {
+            render_attributes_in_code(w, it);
 
-        write!(
-            w,
-            "{vis}const {name}: {typ}",
-            vis = it.visibility.print_with_space(it.def_id, cx),
-            name = it.name.as_ref().unwrap(),
-            typ = c.type_.print(cx),
-        );
+            write!(
+                w,
+                "{vis}const {name}: {typ}",
+                vis = it.visibility.print_with_space(it.def_id, cx),
+                name = it.name.as_ref().unwrap(),
+                typ = c.type_.print(cx),
+            );
 
-        let value = c.value(cx.tcx());
-        let is_literal = c.is_literal(cx.tcx());
-        let expr = c.expr(cx.tcx());
-        if value.is_some() || is_literal {
-            write!(w, " = {expr};", expr = Escape(&expr));
-        } else {
-            w.write_str(";");
-        }
+            let value = c.value(cx.tcx());
+            let is_literal = c.is_literal(cx.tcx());
+            let expr = c.expr(cx.tcx());
+            if value.is_some() || is_literal {
+                write!(w, " = {expr};", expr = Escape(&expr));
+            } else {
+                w.write_str(";");
+            }
 
-        if !is_literal {
-            if let Some(value) = &value {
-                let value_lowercase = value.to_lowercase();
-                let expr_lowercase = expr.to_lowercase();
+            if !is_literal {
+                if let Some(value) = &value {
+                    let value_lowercase = value.to_lowercase();
+                    let expr_lowercase = expr.to_lowercase();
 
-                if value_lowercase != expr_lowercase
-                    && value_lowercase.trim_end_matches("i32") != expr_lowercase
-                {
-                    write!(w, " // {value}", value = Escape(value));
+                    if value_lowercase != expr_lowercase
+                        && value_lowercase.trim_end_matches("i32") != expr_lowercase
+                    {
+                        write!(w, " // {value}", value = Escape(value));
+                    }
                 }
             }
-        }
+        });
     });
 
     document(w, cx, it, None, HeadingOffset::H2)
@@ -1258,7 +1286,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
                     name = field_name,
                     ty = ty.print(cx)
                 );
-                document(w, cx, field, Some(it), HeadingOffset::H2);
+                document(w, cx, field, Some(it), HeadingOffset::H3);
             }
         }
     }
@@ -1268,30 +1296,34 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
 }
 
 fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Static) {
-    wrap_item(w, "static", |w| {
-        render_attributes_in_code(w, it);
-        write!(
-            w,
-            "{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(),
-            typ = s.type_.print(cx)
-        );
+    wrap_into_docblock(w, |w| {
+        wrap_item(w, "static", |w| {
+            render_attributes_in_code(w, it);
+            write!(
+                w,
+                "{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(),
+                typ = s.type_.print(cx)
+            );
+        });
     });
     document(w, cx, it, None, HeadingOffset::H2)
 }
 
 fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
-    wrap_item(w, "foreigntype", |w| {
-        w.write_str("extern {\n");
-        render_attributes_in_code(w, it);
-        write!(
-            w,
-            "    {}type {};\n}}",
-            it.visibility.print_with_space(it.def_id, cx),
-            it.name.as_ref().unwrap(),
-        );
+    wrap_into_docblock(w, |w| {
+        wrap_item(w, "foreigntype", |w| {
+            w.write_str("extern {\n");
+            render_attributes_in_code(w, it);
+            write!(
+                w,
+                "    {}type {};\n}}",
+                it.visibility.print_with_space(it.def_id, cx),
+                it.name.as_ref().unwrap(),
+            );
+        });
     });
 
     document(w, cx, it, None, HeadingOffset::H2);
@@ -1374,7 +1406,7 @@ fn wrap_into_docblock<F>(w: &mut Buffer, f: F)
 where
     F: FnOnce(&mut Buffer),
 {
-    w.write_str("<div class=\"docblock type-decl\">");
+    w.write_str("<div class=\"docblock item-decl\">");
     f(w);
     w.write_str("</div>")
 }
@@ -1465,7 +1497,7 @@ fn render_union(
     );
     if let Some(g) = g {
         write!(w, "{}", g.print(cx));
-        write!(w, "{}", print_where_clause(&g, cx, 0, true));
+        write!(w, "{}", print_where_clause(g, cx, 0, true));
     }
 
     write!(w, " {{\n{}", tab);
index d517f3ac0e3a9e1a16db7d886a31dc263bedc90b..7803a779727c5b09e8ef033f6ecc343dd41b6c90 100644 (file)
 /// only keep the `lo` and `hi`.
 crate fn collect_spans_and_sources(
     tcx: TyCtxt<'_>,
-    krate: clean::Crate,
+    krate: &clean::Crate,
     src_root: &Path,
     include_sources: bool,
     generate_link_to_definition: bool,
-) -> (clean::Crate, FxHashMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) {
+) -> (FxHashMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) {
     let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() };
 
     if include_sources {
         if generate_link_to_definition {
             tcx.hir().walk_toplevel_module(&mut visitor);
         }
-        let (krate, sources) = sources::collect_local_sources(tcx, src_root, krate);
-        (krate, sources, visitor.matches)
+        let sources = sources::collect_local_sources(tcx, src_root, &krate);
+        (sources, visitor.matches)
     } else {
-        (krate, Default::default(), Default::default())
+        (Default::default(), Default::default())
     }
 }
 
@@ -105,7 +105,7 @@ fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
         }
         for bound in p.bounds {
             if let Some(trait_ref) = bound.trait_ref() {
-                self.handle_path(&trait_ref.path, None);
+                self.handle_path(trait_ref.path, None);
             }
         }
     }
@@ -121,42 +121,33 @@ fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) {
         if !span.overlaps(m.inner) {
             // Now that we confirmed it's a file import, we want to get the span for the module
             // name only and not all the "mod foo;".
-            if let Some(node) = self.tcx.hir().find(id) {
-                match node {
-                    Node::Item(item) => {
-                        self.matches
-                            .insert(item.ident.span, LinkFromSrc::Local(clean::Span::new(m.inner)));
-                    }
-                    _ => {}
-                }
+            if let Some(Node::Item(item)) = self.tcx.hir().find(id) {
+                self.matches.insert(item.ident.span, LinkFromSrc::Local(clean::Span::new(m.inner)));
             }
         }
         intravisit::walk_mod(self, m, id);
     }
 
     fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
-        match expr.kind {
-            ExprKind::MethodCall(segment, method_span, _, _) => {
-                if let Some(hir_id) = segment.hir_id {
-                    let hir = self.tcx.hir();
-                    let body_id = hir.enclosing_body_owner(hir_id);
-                    let typeck_results = self.tcx.sess.with_disabled_diagnostic(|| {
-                        self.tcx.typeck_body(
-                            hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
-                        )
-                    });
-                    if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
-                        self.matches.insert(
-                            method_span,
-                            match hir.span_if_local(def_id) {
-                                Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
-                                None => LinkFromSrc::External(def_id),
-                            },
-                        );
-                    }
+        if let ExprKind::MethodCall(segment, method_span, _, _) = expr.kind {
+            if let Some(hir_id) = segment.hir_id {
+                let hir = self.tcx.hir();
+                let body_id = hir.enclosing_body_owner(hir_id);
+                let typeck_results = self.tcx.sess.with_disabled_diagnostic(|| {
+                    self.tcx.typeck_body(
+                        hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
+                    )
+                });
+                if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
+                    self.matches.insert(
+                        method_span,
+                        match hir.span_if_local(def_id) {
+                            Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
+                            None => LinkFromSrc::External(def_id),
+                        },
+                    );
                 }
             }
-            _ => {}
         }
         intravisit::walk_expr(self, expr);
     }
index e4c2556118aebf359ca84bd0e81fb75582ff6abc..978701746b75b135acde7172be31087d7e1c4fc9 100644 (file)
@@ -17,6 +17,7 @@
 use crate::docfs::PathError;
 use crate::error::Error;
 use crate::html::{layout, static_files};
+use crate::{try_err, try_none};
 
 static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
     map! {
@@ -39,9 +40,9 @@
         "SourceCodePro-Semibold.ttf.woff" => static_files::source_code_pro::SEMIBOLD,
         "SourceCodePro-It.ttf.woff" => static_files::source_code_pro::ITALIC,
         "SourceCodePro-LICENSE.txt" => static_files::source_code_pro::LICENSE,
-        "noto-sans-kr-regular.woff2" => static_files::noto_sans_kr::REGULAR2,
-        "noto-sans-kr-regular.woff" => static_files::noto_sans_kr::REGULAR,
-        "noto-sans-kr-LICENSE.txt" => static_files::noto_sans_kr::LICENSE,
+        "NanumBarunGothic.ttf.woff2" => static_files::nanum_barun_gothic::REGULAR2,
+        "NanumBarunGothic.ttf.woff" => static_files::nanum_barun_gothic::REGULAR,
+        "NanumBarunGothic-LICENSE.txt" => static_files::nanum_barun_gothic::LICENSE,
         "LICENSE-MIT.txt" => static_files::LICENSE_MIT,
         "LICENSE-APACHE.txt" => static_files::LICENSE_APACHE,
         "COPYRIGHT.txt" => static_files::COPYRIGHT,
@@ -128,7 +129,7 @@ fn write_minify(
     ) -> Result<(), Error> {
         if minify {
             let contents = contents.as_ref();
-            let contents = if resource.extension() == Some(&OsStr::new("css")) {
+            let contents = if resource.extension() == Some(OsStr::new("css")) {
                 minifier::css::minify(contents).map_err(|e| {
                     Error::new(format!("failed to minify CSS file: {}", e), resource.path(self))
                 })?
@@ -304,6 +305,15 @@ fn add_background_image_to_css(
         )?;
     }
 
+    if cx.shared.layout.scrape_examples_extension {
+        cx.write_minify(
+            SharedResource::InvocationSpecific { basename: "scrape-examples.js" },
+            static_files::SCRAPE_EXAMPLES_JS,
+            options.enable_minification,
+            &options.emit,
+        )?;
+    }
+
     if let Some(ref css) = cx.shared.layout.css_file_extension {
         let buffer = try_err!(fs::read_to_string(css), css);
         // This varies based on the invocation, so it can't go through the write_minify wrapper.
@@ -446,10 +456,10 @@ fn to_json_string(&self) -> String {
         let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix));
         let make_sources = || {
             let (mut all_sources, _krates) =
-                try_err!(collect(&dst, &krate.name.as_str(), "sourcesIndex"), &dst);
+                try_err!(collect(&dst, &krate.name(cx.tcx()).as_str(), "sourcesIndex"), &dst);
             all_sources.push(format!(
                 "sourcesIndex[\"{}\"] = {};",
-                &krate.name,
+                &krate.name(cx.tcx()),
                 hierarchy.to_json_string()
             ));
             all_sources.sort();
@@ -464,9 +474,10 @@ fn to_json_string(&self) -> String {
 
     // Update the search index and crate list.
     let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix));
-    let (mut all_indexes, mut krates) = try_err!(collect_json(&dst, &krate.name.as_str()), &dst);
+    let (mut all_indexes, mut krates) =
+        try_err!(collect_json(&dst, &krate.name(cx.tcx()).as_str()), &dst);
     all_indexes.push(search_index);
-    krates.push(krate.name.to_string());
+    krates.push(krate.name(cx.tcx()).to_string());
     krates.sort();
 
     // Sort the indexes by crate so the file will be generated identically even
@@ -590,7 +601,7 @@ struct Implementor {
 
         let implementors = format!(
             r#"implementors["{}"] = {};"#,
-            krate.name,
+            krate.name(cx.tcx()),
             serde_json::to_string(&implementors).unwrap()
         );
 
@@ -602,7 +613,7 @@ struct Implementor {
         mydst.push(&format!("{}.{}.js", remote_item_type, remote_path[remote_path.len() - 1]));
 
         let (mut all_implementors, _) =
-            try_err!(collect(&mydst, &krate.name.as_str(), "implementors"), &mydst);
+            try_err!(collect(&mydst, &krate.name(cx.tcx()).as_str(), "implementors"), &mydst);
         all_implementors.push(implementors);
         // Sort the implementors by crate so the file will be generated
         // identically even with rustdoc running in parallel.
index 71c64231a210eb48e92e2b7739b7bc08362df134..c8e93374e63ccd7abf8827a15c5e03cf31ef363d 100644 (file)
@@ -1,11 +1,11 @@
 use crate::clean;
 use crate::docfs::PathError;
 use crate::error::Error;
-use crate::fold::DocFolder;
 use crate::html::format::Buffer;
 use crate::html::highlight;
 use crate::html::layout;
 use crate::html::render::{Context, BASIC_KEYWORDS};
+use crate::visit::DocVisitor;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::ty::TyCtxt;
 use std::fs;
 use std::path::{Component, Path, PathBuf};
 
-crate fn render(cx: &mut Context<'_>, krate: clean::Crate) -> Result<clean::Crate, Error> {
+crate fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), Error> {
     info!("emitting source files");
-    let dst = cx.dst.join("src").join(&*krate.name.as_str());
+
+    let dst = cx.dst.join("src").join(&*krate.name(cx.tcx()).as_str());
     cx.shared.ensure_dir(&dst)?;
-    let mut folder = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() };
-    Ok(folder.fold_crate(krate))
+
+    let mut collector = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() };
+    collector.visit_crate(krate);
+    Ok(())
 }
 
 crate fn collect_local_sources<'tcx>(
     tcx: TyCtxt<'tcx>,
     src_root: &Path,
-    krate: clean::Crate,
-) -> (clean::Crate, FxHashMap<PathBuf, String>) {
+    krate: &clean::Crate,
+) -> FxHashMap<PathBuf, String> {
     let mut lsc = LocalSourcesCollector { tcx, local_sources: FxHashMap::default(), src_root };
-
-    let krate = lsc.fold_crate(krate);
-    (krate, lsc.local_sources)
+    lsc.visit_crate(krate);
+    lsc.local_sources
 }
 
 struct LocalSourcesCollector<'a, 'tcx> {
@@ -42,7 +44,7 @@ struct LocalSourcesCollector<'a, 'tcx> {
 }
 
 fn is_real_and_local(span: clean::Span, sess: &Session) -> bool {
-    span.filename(sess).is_real() && span.cnum(sess) == LOCAL_CRATE
+    span.cnum(sess) == LOCAL_CRATE && span.filename(sess).is_real()
 }
 
 impl LocalSourcesCollector<'_, '_> {
@@ -54,12 +56,13 @@ fn add_local_source(&mut self, item: &clean::Item) {
             return;
         }
         let filename = span.filename(sess);
-        let p = match filename {
-            FileName::Real(ref file) => match file.local_path() {
-                Some(p) => p.to_path_buf(),
-                _ => return,
-            },
-            _ => return,
+        let p = if let FileName::Real(file) = filename {
+            match file.into_local_path() {
+                Some(p) => p,
+                None => return,
+            }
+        } else {
+            return;
         };
         if self.local_sources.contains_key(&*p) {
             // We've already emitted this source
@@ -67,7 +70,7 @@ fn add_local_source(&mut self, item: &clean::Item) {
         }
 
         let mut href = String::new();
-        clean_path(&self.src_root, &p, false, |component| {
+        clean_path(self.src_root, &p, false, |component| {
             href.push_str(&component.to_string_lossy());
             href.push('/');
         });
@@ -79,13 +82,11 @@ fn add_local_source(&mut self, item: &clean::Item) {
     }
 }
 
-impl DocFolder for LocalSourcesCollector<'_, '_> {
-    fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
-        self.add_local_source(&item);
+impl DocVisitor for LocalSourcesCollector<'_, '_> {
+    fn visit_item(&mut self, item: &clean::Item) {
+        self.add_local_source(item);
 
-        // FIXME: if `include_sources` isn't set and DocFolder didn't require consuming the crate by value,
-        // we could return None here without having to walk the rest of the crate.
-        Some(self.fold_item_recur(item))
+        self.visit_item_recur(item)
     }
 }
 
@@ -98,8 +99,12 @@ struct SourceCollector<'a, 'tcx> {
     emitted_local_sources: FxHashSet<PathBuf>,
 }
 
-impl DocFolder for SourceCollector<'_, '_> {
-    fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
+impl DocVisitor for SourceCollector<'_, '_> {
+    fn visit_item(&mut self, item: &clean::Item) {
+        if !self.cx.include_sources {
+            return;
+        }
+
         let tcx = self.cx.tcx();
         let span = item.span(tcx);
         let sess = tcx.sess;
@@ -107,7 +112,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         // If we're not rendering sources, there's nothing to do.
         // If we're including source files, and we haven't seen this file yet,
         // then we need to render it out to the filesystem.
-        if self.cx.include_sources && is_real_and_local(span, sess) {
+        if is_real_and_local(span, sess) {
             let filename = span.filename(sess);
             let span = span.inner();
             let pos = sess.source_map().lookup_source_file(span.lo());
@@ -132,9 +137,8 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                 }
             };
         }
-        // FIXME: if `include_sources` isn't set and DocFolder didn't require consuming the crate by value,
-        // we could return None here without having to walk the rest of the crate.
-        Some(self.fold_item_recur(item))
+
+        self.visit_item_recur(item)
     }
 }
 
@@ -168,7 +172,7 @@ fn emit_source(
         };
 
         // Remove the utf-8 BOM if any
-        let contents = if contents.starts_with('\u{feff}') { &contents[3..] } else { &contents };
+        let contents = contents.strip_prefix('\u{feff}').unwrap_or(&contents);
 
         // Create the intermediate directories
         let mut cur = self.dst.clone();
@@ -204,7 +208,16 @@ fn emit_source(
             &page,
             "",
             |buf: &mut _| {
-                print_src(buf, contents, self.cx.shared.edition(), file_span, &self.cx, &root_path)
+                print_src(
+                    buf,
+                    contents,
+                    self.cx.shared.edition(),
+                    file_span,
+                    self.cx,
+                    &root_path,
+                    None,
+                    SourceContext::Standalone,
+                )
             },
             &self.cx.shared.style_files,
         );
@@ -241,15 +254,22 @@ fn emit_source(
     }
 }
 
+crate enum SourceContext {
+    Standalone,
+    Embedded { offset: usize },
+}
+
 /// Wrapper struct to render the source code of a file. This will do things like
 /// adding line numbers to the left-hand side.
-fn print_src(
+crate fn print_src(
     buf: &mut Buffer,
     s: &str,
     edition: Edition,
     file_span: rustc_span::Span,
     context: &Context<'_>,
     root_path: &str,
+    decoration_info: Option<highlight::DecorationInfo>,
+    source_context: SourceContext,
 ) {
     let lines = s.lines().count();
     let mut line_numbers = Buffer::empty_from(buf);
@@ -261,7 +281,14 @@ fn print_src(
     }
     line_numbers.write_str("<pre class=\"line-numbers\">");
     for i in 1..=lines {
-        writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i, cols);
+        match source_context {
+            SourceContext::Standalone => {
+                writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i, cols)
+            }
+            SourceContext::Embedded { offset } => {
+                writeln!(line_numbers, "<span>{0:1$}</span>", i + offset, cols)
+            }
+        }
     }
     line_numbers.write_str("</pre>");
     highlight::render_with_highlighting(
@@ -273,5 +300,6 @@ fn print_src(
         edition,
         Some(line_numbers),
         Some(highlight::ContextInfo { context, file_span, root_path }),
+        decoration_info,
     );
 }
index 0a196edd53b1dd063900a27a45a598e8e49be2f8..37ea7b000339f0de6d57ed9b62afc5298eaa6f5d 100644 (file)
@@ -13,3 +13,12 @@ rules.
        /* It requires JS to work so no need to display it in this case. */
        display: none;
 }
+
+.sub {
+       /* The search bar and related controls don't work without JS */
+       display: none;
+}
+
+#theme-picker {
+       display: none;
+}
index 11c54876dea30ff07b5c957714d6302ae4884d83..89a763ef6d707fbf79a7117e261c4f4102230e74 100644 (file)
 
 /* Avoid using legacy CJK serif fonts in Windows like Batang. */
 @font-face {
-       font-family: 'Noto Sans KR';
-       src: url("noto-sans-kr-regular.woff2") format("woff2"),
-               url("noto-sans-kr-regular.woff") format("woff");
+       font-family: 'NanumBarunGothic';
+       src: url("NanumBarunGothic.ttf.woff2") format("woff2"),
+               url("NanumBarunGothic.ttf.woff") format("woff");
        font-display: swap;
-       unicode-range: U+AC00-D7AF, U+3130-318F, U+1100-11FF, U+A960-A97F, U+D7B0-D7FF;
+       unicode-range: U+AC00-D7AF, U+1100-11FF, U+3130-318F, U+A960-A97F, U+D7B0-D7FF;
 }
 
 * {
@@ -108,7 +108,7 @@ html {
 /* General structure and fonts */
 
 body {
-       font: 16px/1.4 "Source Serif 4", "Noto Sans KR", serif;
+       font: 16px/1.4 "Source Serif 4", NanumBarunGothic, serif;
        margin: 0;
        position: relative;
        padding: 10px 15px 20px 15px;
@@ -129,9 +129,14 @@ h3 {
 }
 h1, h2, h3, h4, h5, h6 {
        font-weight: 500;
+}
+h1, h2, h3, h4 {
        margin: 20px 0 15px 0;
        padding-bottom: 6px;
 }
+.docblock h3, .docblock h4, h5, h6 {
+       margin: 15px 0 5px 0;
+}
 h1.fqn {
        display: flex;
        border-bottom: 1px dashed;
@@ -144,13 +149,26 @@ h1.fqn {
 h1.fqn > .in-band > a:hover {
        text-decoration: underline;
 }
-h2, h3, h4 {
+/* 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)
+       Underlines elsewhere in the documentation break up visual flow and tend to invert
+       section hierarchies. */
+h2,
+.top-doc h3,
+.top-doc h4,
+.sidebar .others h3 {
        border-bottom: 1px solid;
 }
-h3.code-header, h4.code-header {
+h3.code-header {
+       font-size: 1.1em;
+}
+h4.code-header {
        font-size: 1em;
+}
+h3.code-header, h4.code-header {
        font-weight: 600;
-       border: none;
+       border-bottom-style: none;
        padding: 0;
        margin: 0;
 }
@@ -169,12 +187,6 @@ h3.code-header, h4.code-header {
        margin-bottom: 10px;
        position: relative;
 }
-.impl, .method.trait-impl,
-.type.trait-impl,
-.associatedconstant.trait-impl,
-.associatedtype.trait-impl {
-       padding-left: 15px;
-}
 
 div.impl-items > div {
        padding-left: 0;
@@ -192,7 +204,7 @@ div.impl-items > div:not(.docblock):not(.item-info),
 .content ul.crate a.crate, a.srclink,
 /* This selector is for the items listed in the "all items" page. */
 #main > ul.docblock > li > a {
-       font-family: "Fira Sans", Arial, sans-serif;
+       font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
 }
 
 .content ul.crate a.crate {
@@ -254,7 +266,10 @@ code, pre, a.test-arrow, .code-header {
 pre {
        padding: 14px;
 }
-.type-decl pre {
+.docblock.item-decl {
+       margin-left: 0;
+}
+.item-decl pre {
        overflow-x: auto;
 }
 
@@ -459,6 +474,11 @@ nav.sub {
        overflow-x: auto;
 }
 
+.rustdoc:not(.source) .example-wrap > pre.line-numbers {
+       width: auto;
+       overflow-x: visible;
+}
+
 .rustdoc .example-wrap > pre {
        margin: 0;
 }
@@ -502,14 +522,12 @@ nav.sub {
        white-space: pre-wrap;
 }
 
-.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
-       border-bottom: 1px solid;
-}
-
 .top-doc .docblock h2 { font-size: 1.3em; }
 .top-doc .docblock h3 { font-size: 1.15em; }
 .top-doc .docblock h4,
-.top-doc .docblock h5,
+.top-doc .docblock h5 {
+       font-size: 1.1em;
+}
 .top-doc .docblock h6 {
        font-size: 1em;
 }
@@ -522,7 +540,7 @@ nav.sub {
        position: relative;
 }
 
-.docblock > * {
+.docblock > :not(.information) {
        max-width: 100%;
        overflow-x: auto;
 }
@@ -550,6 +568,7 @@ nav.sub {
        flex-grow: 1;
        margin: 0px;
        padding: 0px;
+       overflow-wrap: anywhere;
 }
 
 .in-band > code, .in-band > .code-header {
@@ -662,13 +681,6 @@ nav.sub {
        left: -19px;
 }
 
-.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant,
-.impl-items > .associatedtype, .content .impl-items details > summary > .type,
-.impl-items details > summary > .associatedconstant,
-.impl-items details > summary > .associatedtype {
-       margin-left: 20px;
-}
-
 .content .impl-items .docblock, .content .impl-items .item-info {
        margin-bottom: .6em;
 }
@@ -739,7 +751,7 @@ a {
 .anchor {
        display: none;
        position: absolute;
-       left: 0;
+       left: -0.5em;
        background: none !important;
 }
 .anchor.field {
@@ -1572,14 +1584,14 @@ details.rustdoc-toggle > summary.hideme::before {
 
 details.rustdoc-toggle > summary:not(.hideme)::before {
        position: absolute;
-       left: -23px;
+       left: -24px;
        top: 3px;
 }
 
 .impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
 .undocumented > details.rustdoc-toggle > summary:not(.hideme)::before {
        position: absolute;
-       left: -2px;
+       left: -24px;
 }
 
 /* When a "hideme" summary is open and the "Expand description" or "Show
@@ -1973,3 +1985,166 @@ details.undocumented[open] > summary::before {
                overflow-wrap: anywhere;
        }
 }
+
+
+/* Begin: styles for --scrape-examples feature */
+
+.scraped-example-title {
+       font-family: 'Fira Sans';
+}
+
+.scraped-example:not(.expanded) .code-wrapper pre.line-numbers {
+       overflow: hidden;
+       max-height: 240px;
+}
+
+.scraped-example:not(.expanded) .code-wrapper .example-wrap pre.rust {
+       overflow-y: hidden;
+       max-height: 240px;
+       padding-bottom: 0;
+}
+
+.scraped-example .code-wrapper .prev {
+       position: absolute;
+       top: 0.25em;
+       right: 2.25em;
+       z-index: 100;
+       cursor: pointer;
+}
+
+.scraped-example .code-wrapper .next {
+       position: absolute;
+       top: 0.25em;
+       right: 1.25em;
+       z-index: 100;
+       cursor: pointer;
+}
+
+.scraped-example .code-wrapper .expand {
+       position: absolute;
+       top: 0.25em;
+       right: 0.25em;
+       z-index: 100;
+       cursor: pointer;
+}
+
+.scraped-example .code-wrapper {
+       position: relative;
+       display: flex;
+       flex-direction: row;
+       flex-wrap: wrap;
+       width: 100%;
+}
+
+.scraped-example:not(.expanded) .code-wrapper:before {
+       content: " ";
+       width: 100%;
+       height: 5px;
+       position: absolute;
+       z-index: 100;
+       top: 0;
+       background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+}
+
+.scraped-example:not(.expanded) .code-wrapper:after {
+       content: " ";
+       width: 100%;
+       height: 5px;
+       position: absolute;
+       z-index: 100;
+       bottom: 0;
+       background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+}
+
+.scraped-example:not(.expanded) .code-wrapper {
+       overflow: hidden;
+       max-height: 240px;
+}
+
+.scraped-example .code-wrapper .line-numbers {
+       margin: 0;
+       padding: 14px 0;
+}
+
+.scraped-example .code-wrapper .line-numbers span {
+       padding: 0 14px;
+}
+
+.scraped-example .code-wrapper .example-wrap {
+       flex: 1;
+       overflow-x: auto;
+       overflow-y: hidden;
+       margin-bottom: 0;
+}
+
+.scraped-example .code-wrapper .example-wrap pre.rust {
+       overflow-x: inherit;
+       width: inherit;
+       overflow-y: hidden;
+}
+
+.scraped-example .example-wrap .rust span.highlight {
+       background: #fcffd6;
+}
+
+.scraped-example .example-wrap .rust span.highlight.focus {
+       background: #f6fdb0;
+}
+
+.more-examples-toggle {
+       margin-top: 10px;
+}
+
+.more-examples-toggle summary {
+       color: #999;
+       font-family: 'Fira Sans';
+}
+
+.more-scraped-examples {
+       margin-left: 25px;
+       display: flex;
+       flex-direction: row;
+       width: calc(100% - 25px);
+}
+
+.more-scraped-examples-inner {
+       /* 20px is width of toggle-line + toggle-line-inner */
+       width: calc(100% - 20px);
+}
+
+.toggle-line {
+       align-self: stretch;
+       margin-right: 10px;
+       margin-top: 5px;
+       padding: 0 4px;
+       cursor: pointer;
+}
+
+.toggle-line:hover .toggle-line-inner {
+       background: #aaa;
+}
+
+.toggle-line-inner {
+       min-width: 2px;
+       background: #ddd;
+       height: 100%;
+}
+
+.more-scraped-examples .scraped-example {
+       margin-bottom: 20px;
+}
+
+.more-scraped-examples .scraped-example:last-child {
+       margin-bottom: 0;
+}
+
+.example-links a {
+       margin-top: 20px;
+       font-family: 'Fira Sans';
+}
+
+.example-links ul {
+       margin-bottom: 0;
+}
+
+/* End: styles for --scrape-examples feature */
index 0fd6462a8f5dd82851928adc60e510088b4664d1..ba7fb3b5456a55425d76939bab0e56775f9da13e 100644 (file)
@@ -220,7 +220,7 @@ body.source .example-wrap pre.rust a {
        background: #333;
 }
 
-.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
+.docblock:not(.item-decl) a:not(.srclink):not(.test-arrow),
 .docblock-short a:not(.srclink):not(.test-arrow), .item-info a,
 #help a {
        color: #39AFD7;
@@ -255,10 +255,6 @@ details.undocumented > summary::before {
        box-shadow: 0 0 0 1px #148099,0 0 0 2px transparent;
 }
 
-.search-input:disabled {
-       background-color: #3e3e3e;
-}
-
 .module-item .stab,
 .import-item .stab {
        color: #000;
@@ -613,3 +609,22 @@ div.files > .selected {
 input:checked + .slider {
        background-color: #ffb454 !important;
 }
+
+.scraped-example .example-wrap .rust span.highlight {
+       background: rgb(91, 59, 1);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+       background: rgb(124, 75, 15);
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
+       background: linear-gradient(to bottom, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
+}
+.scraped-example:not(.expanded) .code-wrapper:after {
+       background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
+}
+.toggle-line-inner {
+       background: #616161;
+}
+.toggle-line:hover .toggle-line-inner {
+       background: ##898989;
+}
index d863701dd73c7a320d570dbb695ec5661c7c2f43..77ac217e6f41dd9f76efc9b9c298ab4bc38d2889 100644 (file)
@@ -181,7 +181,7 @@ body.source .example-wrap pre.rust a {
        background: #333;
 }
 
-.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
+.docblock:not(.item-decl) a:not(.srclink):not(.test-arrow),
 .docblock-short a:not(.srclink):not(.test-arrow), .item-info a,
 #help a {
        color: #D2991D;
@@ -219,10 +219,6 @@ details.undocumented > summary::before {
        border-color: #008dfd;
 }
 
-.search-input:disabled {
-       background-color: #c5c4c4;
-}
-
 #crate-search + .search-input:focus {
        box-shadow: 0 0 8px 4px #078dd8;
 }
@@ -485,3 +481,22 @@ div.files > .selected {
 .setting-line > .title {
        border-bottom-color: #ddd;
 }
+
+.scraped-example .example-wrap .rust span.highlight {
+       background: rgb(91, 59, 1);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+       background: rgb(124, 75, 15);
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
+       background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
+}
+.scraped-example:not(.expanded) .code-wrapper:after {
+       background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
+}
+.toggle-line-inner {
+       background: #616161;
+}
+.toggle-line:hover .toggle-line-inner {
+       background: ##898989;
+}
index 28d2e99a3d07359fa8147753cc14ca3fddf78817..6df137e39141508a88674a94a53c516efc79d9f1 100644 (file)
@@ -176,7 +176,7 @@ body.source .example-wrap pre.rust a {
        background: #eee;
 }
 
-.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
+.docblock:not(.item-decl) a:not(.srclink):not(.test-arrow),
 .docblock-short a:not(.srclink):not(.test-arrow), .item-info a,
 #help a {
        color: #3873AD;
@@ -209,10 +209,6 @@ details.undocumented > summary::before {
        border-color: #66afe9;
 }
 
-.search-input:disabled {
-       background-color: #e6e6e6;
-}
-
 #crate-search + .search-input:focus {
        box-shadow: 0 0 8px #078dd8;
 }
diff --git a/src/librustdoc/html/static/fonts/NanumBarunGothic-LICENSE.txt b/src/librustdoc/html/static/fonts/NanumBarunGothic-LICENSE.txt
new file mode 100644 (file)
index 0000000..0bf4668
--- /dev/null
@@ -0,0 +1,99 @@
+Copyright (c) 2010, NAVER Corporation (https://www.navercorp.com/),
+
+with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic,
+NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen,
+Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco,
+NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight, NanumBarunGothic,
+Naver NanumBarunGothic, NanumSquareRound, NanumBarunPen, MaruBuri
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff b/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff
new file mode 100644 (file)
index 0000000..fb063e8
Binary files /dev/null and b/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff differ
diff --git a/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff2 b/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff2
new file mode 100644 (file)
index 0000000..1866ad4
Binary files /dev/null and b/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff2 differ
diff --git a/src/librustdoc/html/static/fonts/noto-sans-kr-LICENSE.txt b/src/librustdoc/html/static/fonts/noto-sans-kr-LICENSE.txt
deleted file mode 100644 (file)
index 922d5fd..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-Copyright 2014, 2015 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-
-This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
-
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide
-development of collaborative font projects, to support the font creation
-efforts of academic and linguistic communities, and to provide a free and
-open framework in which fonts may be shared and improved in partnership
-with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and
-redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded,
-redistributed and/or sold with any software provided that any reserved
-names are not used by derivative works. The fonts and derivatives,
-however, cannot be released under any other type of license. The
-requirement for fonts to remain under this license does not apply
-to any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this license and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the
-copyright statement(s).
-
-"Original Version" refers to the collection of Font Software components as
-distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to, deleting,
-or substituting -- in part or in whole -- any of the components of the
-Original Version, by changing formats or by porting the Font Software to a
-new environment.
-
-"Author" refers to any designer, engineer, programmer, technical
-writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Font Software, to use, study, copy, merge, embed, modify,
-redistribute, and sell modified and unmodified copies of the Font
-Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components,
-in Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled,
-redistributed and/or sold with any software, provided that each copy
-contains the above copyright notice and this license. These can be
-included either as stand-alone text files, human-readable headers or
-in the appropriate machine-readable metadata fields within text or
-binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font
-Name(s) unless explicit written permission is granted by the corresponding
-Copyright Holder. This restriction only applies to the primary font name as
-presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
-Software shall not be used to promote, endorse or advertise any
-Modified Version, except to acknowledge the contribution(s) of the
-Copyright Holder(s) and the Author(s) or with their explicit written
-permission.
-
-5) The Font Software, modified or unmodified, in part or in whole,
-must be distributed entirely under this license, and must not be
-distributed under any other license. The requirement for fonts to
-remain under this license does not apply to any document created
-using the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/src/librustdoc/html/static/fonts/noto-sans-kr-regular.woff b/src/librustdoc/html/static/fonts/noto-sans-kr-regular.woff
deleted file mode 100644 (file)
index 65e939c..0000000
Binary files a/src/librustdoc/html/static/fonts/noto-sans-kr-regular.woff and /dev/null differ
diff --git a/src/librustdoc/html/static/fonts/noto-sans-kr-regular.woff2 b/src/librustdoc/html/static/fonts/noto-sans-kr-regular.woff2
deleted file mode 100644 (file)
index 8126492..0000000
Binary files a/src/librustdoc/html/static/fonts/noto-sans-kr-regular.woff2 and /dev/null differ
index e396fd9d288db1cc34da37279113f4a65683b0c7..4b55a0a69b66358c2987337484c50e9e76cfd338 100644 (file)
@@ -263,7 +263,9 @@ function hideThemeButtonState() {
                 search_input.placeholder = searchState.input.origPlaceholder;
             });
 
-            search_input.removeAttribute('disabled');
+            if (search_input.value != '') {
+                loadSearch();
+            }
 
             // `crates{version}.js` should always be loaded before this script, so we can use it
             // safely.
@@ -564,6 +566,7 @@ function hideThemeButtonState() {
     // delayed sidebar rendering.
     window.initSidebarItems = function(items) {
         var sidebar = document.getElementsByClassName("sidebar-elems")[0];
+        var others;
         var current = window.sidebarCurrent;
 
         function addSidebarCrates(crates) {
@@ -592,7 +595,7 @@ function hideThemeButtonState() {
                 li.appendChild(link);
                 ul.appendChild(li);
             }
-            sidebar.appendChild(div);
+            others.appendChild(div);
         }
 
         function block(shortty, longty) {
@@ -633,10 +636,14 @@ function hideThemeButtonState() {
                 ul.appendChild(li);
             }
             div.appendChild(ul);
-            sidebar.appendChild(div);
+            others.appendChild(div);
         }
 
         if (sidebar) {
+            others = document.createElement("div");
+            others.className = "others";
+            sidebar.appendChild(others);
+
             var isModule = hasClass(document.body, "mod");
             if (!isModule) {
                 block("primitive", "Primitive Types");
diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js
new file mode 100644 (file)
index 0000000..664b187
--- /dev/null
@@ -0,0 +1,86 @@
+/* global addClass, hasClass, removeClass, onEach */
+
+(function () {
+    // Scroll code block to put the given code location in the middle of the viewer
+    function scrollToLoc(elt, loc) {
+        var wrapper = elt.querySelector(".code-wrapper");
+        var halfHeight = wrapper.offsetHeight / 2;
+        var lines = elt.querySelector('.line-numbers');
+        var offsetMid = (lines.children[loc[0]].offsetTop
+                         + lines.children[loc[1]].offsetTop) / 2;
+        var scrollOffset = offsetMid - halfHeight;
+        lines.scrollTo(0, scrollOffset);
+        elt.querySelector(".rust").scrollTo(0, scrollOffset);
+    }
+
+    function updateScrapedExample(example) {
+        var locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
+        var locIndex = 0;
+        var highlights = example.querySelectorAll('.highlight');
+        var link = example.querySelector('.scraped-example-title a');
+
+        if (locs.length > 1) {
+            // Toggle through list of examples in a given file
+            var onChangeLoc = function(changeIndex) {
+                removeClass(highlights[locIndex], 'focus');
+                changeIndex();
+                scrollToLoc(example, locs[locIndex][0]);
+                addClass(highlights[locIndex], 'focus');
+
+                var url = locs[locIndex][1];
+                var title = locs[locIndex][2];
+
+                link.href = url;
+                link.innerHTML = title;
+            };
+
+            example.querySelector('.prev')
+                .addEventListener('click', function() {
+                    onChangeLoc(function() {
+                        locIndex = (locIndex - 1 + locs.length) % locs.length;
+                    });
+                });
+
+            example.querySelector('.next')
+                .addEventListener('click', function() {
+                    onChangeLoc(function() {
+                        locIndex = (locIndex + 1) % locs.length;
+                    });
+                });
+        }
+
+        var expandButton = example.querySelector('.expand');
+        if (expandButton) {
+            expandButton.addEventListener('click', function () {
+                if (hasClass(example, "expanded")) {
+                    removeClass(example, "expanded");
+                    scrollToLoc(example, locs[0][0]);
+                } else {
+                    addClass(example, "expanded");
+                }
+            });
+        }
+
+        // Start with the first example in view
+        scrollToLoc(example, locs[0][0]);
+    }
+
+    var firstExamples = document.querySelectorAll('.scraped-example-list > .scraped-example');
+    onEach(firstExamples, updateScrapedExample);
+    onEach(document.querySelectorAll('.more-examples-toggle'), function(toggle) {
+        // Allow users to click the left border of the <details> section to close it,
+        // since the section can be large and finding the [+] button is annoying.
+        toggle.querySelector('.toggle-line').addEventListener('click', function() {
+            toggle.open = false;
+        });
+
+        var moreExamples = toggle.querySelectorAll('.scraped-example');
+        toggle.querySelector('summary').addEventListener('click', function() {
+            // Wrapping in setTimeout ensures the update happens after the elements are actually
+            // visible. This is necessary since updateScrapedExample calls scrollToLoc which
+            // depends on offsetHeight, a property that requires an element to be visible to
+            // compute correctly.
+            setTimeout(function() { onEach(moreExamples, updateScrapedExample); });
+        }, {once: true});
+    });
+})();
index 5eb545f758247788aac28d2977098492699d3571..c2ea54abd2ea8390743b1af965dc9b3d17a02ca6 100644 (file)
@@ -299,10 +299,10 @@ window.initSearch = function(rawSearchIndex) {
                     var elems = Object.create(null);
                     var elength = obj[GENERICS_DATA].length;
                     for (var x = 0; x < elength; ++x) {
-                        if (!elems[obj[GENERICS_DATA][x]]) {
-                            elems[obj[GENERICS_DATA][x]] = 0;
+                        if (!elems[obj[GENERICS_DATA][x][NAME]]) {
+                            elems[obj[GENERICS_DATA][x][NAME]] = 0;
                         }
-                        elems[obj[GENERICS_DATA][x]] += 1;
+                        elems[obj[GENERICS_DATA][x][NAME]] += 1;
                     }
                     var total = 0;
                     var done = 0;
@@ -345,6 +345,7 @@ window.initSearch = function(rawSearchIndex) {
         // Check for type name and type generics (if any).
         function checkType(obj, val, literalSearch) {
             var lev_distance = MAX_LEV_DISTANCE + 1;
+            var tmp_lev = MAX_LEV_DISTANCE + 1;
             var len, x, firstGeneric;
             if (obj[NAME] === val.name) {
                 if (literalSearch) {
@@ -354,10 +355,10 @@ window.initSearch = function(rawSearchIndex) {
                             var elems = Object.create(null);
                             len = obj[GENERICS_DATA].length;
                             for (x = 0; x < len; ++x) {
-                                if (!elems[obj[GENERICS_DATA][x]]) {
-                                    elems[obj[GENERICS_DATA][x]] = 0;
+                                if (!elems[obj[GENERICS_DATA][x][NAME]]) {
+                                    elems[obj[GENERICS_DATA][x][NAME]] = 0;
                                 }
-                                elems[obj[GENERICS_DATA][x]] += 1;
+                                elems[obj[GENERICS_DATA][x][NAME]] += 1;
                             }
 
                             var allFound = true;
@@ -382,7 +383,7 @@ window.initSearch = function(rawSearchIndex) {
                     // If the type has generics but don't match, then it won't return at this point.
                     // Otherwise, `checkGenerics` will return 0 and it'll return.
                     if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
-                        var tmp_lev = checkGenerics(obj, val);
+                        tmp_lev = checkGenerics(obj, val);
                         if (tmp_lev <= MAX_LEV_DISTANCE) {
                             return tmp_lev;
                         }
@@ -392,8 +393,8 @@ window.initSearch = function(rawSearchIndex) {
                 if ((!val.generics || val.generics.length === 0) &&
                       obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
                     return obj[GENERICS_DATA].some(
-                        function(name) {
-                            return name === val.name;
+                        function(gen) {
+                            return gen[NAME] === val.name;
                         });
                 }
                 return false;
@@ -404,17 +405,27 @@ window.initSearch = function(rawSearchIndex) {
                 // a levenshtein distance value that isn't *this* good so it goes
                 // into the search results but not too high.
                 lev_distance = Math.ceil((checkGenerics(obj, val) + lev_distance) / 2);
-            } else if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
+            }
+            if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
                 // We can check if the type we're looking for is inside the generics!
                 var olength = obj[GENERICS_DATA].length;
                 for (x = 0; x < olength; ++x) {
-                    lev_distance = Math.min(levenshtein(obj[GENERICS_DATA][x], val.name),
-                                            lev_distance);
+                    tmp_lev = Math.min(levenshtein(obj[GENERICS_DATA][x][NAME], val.name), tmp_lev);
+                }
+                if (tmp_lev !== 0) {
+                    // If we didn't find a good enough result, we go check inside the generics of
+                    // the generics.
+                    for (x = 0; x < olength && tmp_lev !== 0; ++x) {
+                        tmp_lev = Math.min(
+                            checkType(obj[GENERICS_DATA][x], val, literalSearch),
+                            tmp_lev
+                        );
+                    }
                 }
             }
             // Now whatever happens, the returned distance is "less good" so we should mark it
             // as such, and so we add 1 to the distance to make it "less good".
-            return lev_distance + 1;
+            return Math.min(lev_distance, tmp_lev) + 1;
         }
 
         function findArg(obj, val, literalSearch, typeFilter) {
index 924e3f1d29dc99948a509087aa558456bae74d9c..56c5399d074b64c8f5479416a6f1a90a5ce020ec 100644 (file)
 /// Storage, used to store documentation settings.
 crate static STORAGE_JS: &str = include_str!("static/js/storage.js");
 
+/// The file contents of `scraped-examples.js`, which contains functionality related to the
+/// --scrape-examples flag that inserts automatically-found examples of usages of items.
+crate static SCRAPE_EXAMPLES_JS: &str = include_str!("static/js/scrape-examples.js");
+
 /// The file contents of `brush.svg`, the icon used for the theme-switch button.
 crate static BRUSH_SVG: &[u8] = include_bytes!("static/images/brush.svg");
 
     crate static LICENSE: &[u8] = include_bytes!("static/fonts/SourceCodePro-LICENSE.txt");
 }
 
-crate mod noto_sans_kr {
-    /// The file `noto-sans-kr.woff`, the Regular variant of the Noto Sans KR font.
-    crate static REGULAR: &[u8] = include_bytes!("static/fonts/noto-sans-kr-regular.woff");
-
-    /// The file `noto-sans-kr.woff2`, the Regular variant of the Noto Sans KR font.
-    crate static REGULAR2: &[u8] = include_bytes!("static/fonts/noto-sans-kr-regular.woff2");
-
-    /// The file `noto-sans-kr-LICENSE.txt`, the license text of the Noto Sans KR font.
-    crate static LICENSE: &[u8] = include_bytes!("static/fonts/noto-sans-kr-LICENSE.txt");
+/// Files related to the Nanum Barun Gothic font.
+///
+/// These files are used to avoid some legacy CJK serif fonts in Windows.
+///
+/// Note that the Noto Sans KR font, which was used previously but was not very readable on Windows,
+/// has been replaced by the Nanum Barun Gothic font. This is due to Windows' implementation of font
+/// rendering that distorts OpenType fonts too much.
+///
+/// The font files were generated with these commands:
+///
+/// ```sh
+/// pyftsubset NanumBarunGothic.ttf \
+/// --unicodes=U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
+/// --output-file=NanumBarunGothic.ttf.woff --flavor=woff
+/// ```
+/// ```sh
+/// pyftsubset NanumBarunGothic.ttf \
+/// --unicodes=U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
+/// --output-file=NanumBarunGothic.ttf.woff2 --flavor=woff2
+/// ```
+crate mod nanum_barun_gothic {
+    /// The file `NanumBarunGothic.ttf.woff`, the Regular variant of the Nanum Barun Gothic font.
+    crate static REGULAR: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff");
+
+    /// The file `NanumBarunGothic.ttf.woff2`, the Regular variant of the Nanum Barun Gothic font.
+    crate static REGULAR2: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff2");
+
+    /// The file `NanumBarunGothic-LICENSE.txt`, the license text of the Nanum Barun Gothic font.
+    crate static LICENSE: &[u8] = include_bytes!("static/fonts/NanumBarunGothic-LICENSE.txt");
 }
 
 /// Files related to the sidebar in rustdoc sources.
index 38dc3b30e72acd74f6cb19543759f6edcfd74f35..9fafea6914524ad3f8cb6ab503f179a5fbf797d6 100644 (file)
@@ -85,7 +85,6 @@
                     <input {# -#}
                         class="search-input" {# -#}
                         name="search" {# -#}
-                        disabled {# -#}
                         autocomplete="off" {# -#}
                         spellcheck="false" {# -#}
                         placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
     {%- for script in page.static_extra_scripts -%}
     <script src="{{static_root_path | safe}}{{script}}.js"></script> {#- -#}
     {% endfor %}
+    {%- if layout.scrape_examples_extension -%}
+    <script src="{{page.root_path | safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#}
+    {%- endif -%}
     {%- for script in page.extra_scripts -%}
     <script src="{{page.root_path | safe}}{{script}}.js"></script> {#- -#}
     {% endfor %}
index 4098f17db818a576c7741282c7acb57c0029a93f..f740ecdbded74a9a2ed9cdfe01ca99f2f6b5fce4 100644 (file)
@@ -330,10 +330,10 @@ fn from_tcx(kind: clean::GenericParamDefKind, tcx: TyCtxt<'_>) -> Self {
             },
             Type { did: _, bounds, default, synthetic: _ } => GenericParamDefKind::Type {
                 bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
-                default: default.map(|x| x.into_tcx(tcx)),
+                default: default.map(|x| (*x).into_tcx(tcx)),
             },
             Const { did: _, ty, default } => {
-                GenericParamDefKind::Const { ty: ty.into_tcx(tcx), default }
+                GenericParamDefKind::Const { ty: (*ty).into_tcx(tcx), default: default.map(|x| *x) }
             }
         }
     }
@@ -412,7 +412,7 @@ fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
                         .map(|t| {
                             clean::GenericBound::TraitBound(t, rustc_hir::TraitBoundModifier::None)
                         })
-                        .chain(lt.into_iter().map(|lt| clean::GenericBound::Outlives(lt)))
+                        .chain(lt.map(clean::GenericBound::Outlives))
                         .map(|bound| bound.into_tcx(tcx))
                         .collect(),
                 }
@@ -697,6 +697,7 @@ fn from_tcx(kind: ItemType, _tcx: TyCtxt<'_>) -> Self {
             TraitAlias => ItemKind::TraitAlias,
             ProcAttribute => ItemKind::ProcAttribute,
             ProcDerive => ItemKind::ProcDerive,
+            Generic => unreachable!(),
         }
     }
 }
index ff0a6ef6cb74fa8296a7f2e92bda8608cd9cf7e3..7eeb9d1fcaa55114b3b08c06320aa8345dd0e5fd 100644 (file)
 extern crate rustc_lexer;
 extern crate rustc_lint;
 extern crate rustc_lint_defs;
+extern crate rustc_macros;
 extern crate rustc_metadata;
 extern crate rustc_middle;
 extern crate rustc_parse;
 extern crate rustc_passes;
 extern crate rustc_resolve;
+extern crate rustc_serialize;
 extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
@@ -101,17 +103,14 @@ macro_rules! map {
     }}
 }
 
-#[macro_use]
-mod externalfiles;
-
 mod clean;
 mod config;
 mod core;
 mod docfs;
+mod doctest;
 mod doctree;
-#[macro_use]
 mod error;
-mod doctest;
+mod externalfiles;
 mod fold;
 mod formats;
 // used by the error-index generator, so it needs to be public
@@ -120,7 +119,9 @@ macro_rules! map {
 crate mod lint;
 mod markdown;
 mod passes;
+mod scrape_examples;
 mod theme;
+mod visit;
 mod visit_ast;
 mod visit_lib;
 
@@ -619,6 +620,30 @@ fn opts() -> Vec<RustcOptGroup> {
                 "Make the identifiers in the HTML source code pages navigable",
             )
         }),
+        unstable("scrape-examples-output-path", |o| {
+            o.optopt(
+                "",
+                "scrape-examples-output-path",
+                "",
+                "collect function call information and output at the given path",
+            )
+        }),
+        unstable("scrape-examples-target-crate", |o| {
+            o.optmulti(
+                "",
+                "scrape-examples-target-crate",
+                "",
+                "collect function call information for functions from the target crate",
+            )
+        }),
+        unstable("with-examples", |o| {
+            o.optmulti(
+                "",
+                "with-examples",
+                "",
+                "path to function call information (for displaying examples in the documentation)",
+            )
+        }),
     ]
 }
 
@@ -732,6 +757,7 @@ fn main_options(options: config::Options) -> MainResult {
     // FIXME: fix this clone (especially render_options)
     let manual_passes = options.manual_passes.clone();
     let render_options = options.render_options.clone();
+    let scrape_examples_options = options.scrape_examples_options.clone();
     let config = core::create_config(options);
 
     interface::create_compiler_and_run(config, |compiler| {
@@ -747,7 +773,7 @@ fn main_options(options: config::Options) -> MainResult {
             // We need to hold on to the complete resolver, so we cause everything to be
             // cloned for the analysis passes to use. Suboptimal, but necessary in the
             // current architecture.
-            let resolver = core::create_resolver(queries, &sess);
+            let resolver = core::create_resolver(queries, sess);
 
             if sess.has_errors() {
                 sess.fatal("Compilation failed, aborting rustdoc");
@@ -768,6 +794,10 @@ fn main_options(options: config::Options) -> MainResult {
                 });
                 info!("finished with rustc");
 
+                if let Some(options) = scrape_examples_options {
+                    return scrape_examples::run(krate, render_opts, cache, tcx, options);
+                }
+
                 cache.crate_version = crate_version;
 
                 if show_coverage {
index 37faa6742927a2860a543ab97f36f5a42dd92ce7..4e146a07d154a64b3f8d99eedd4b419d8f61d3db 100644 (file)
@@ -1,8 +1,8 @@
 use super::Pass;
 use crate::clean::*;
 use crate::core::DocContext;
-use crate::fold::DocFolder;
 use crate::html::markdown::main_body_opts;
+use crate::visit::DocVisitor;
 use core::ops::Range;
 use pulldown_cmark::{Event, Parser, Tag};
 use regex::Regex;
@@ -39,7 +39,7 @@ fn find_raw_urls(
     ) {
         trace!("looking for raw urls in {}", text);
         // For now, we only check "full" URLs (meaning, starting with "http://" or "https://").
-        for match_ in URL_REGEX.find_iter(&text) {
+        for match_ in URL_REGEX.find_iter(text) {
             let url = match_.as_str();
             let url_range = match_.range();
             f(
@@ -53,16 +53,17 @@ fn find_raw_urls(
 }
 
 crate fn check_bare_urls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
-    BareUrlsLinter { cx }.fold_crate(krate)
+    BareUrlsLinter { cx }.visit_crate(&krate);
+    krate
 }
 
-impl<'a, 'tcx> DocFolder for BareUrlsLinter<'a, 'tcx> {
-    fn fold_item(&mut self, item: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for BareUrlsLinter<'a, 'tcx> {
+    fn visit_item(&mut self, item: &Item) {
         let hir_id = match DocContext::as_local_hir_id(self.cx.tcx, item.def_id) {
             Some(hir_id) => hir_id,
             None => {
                 // If non-local, no need to check anything.
-                return Some(self.fold_item_recur(item));
+                return;
             }
         };
         let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
@@ -106,6 +107,6 @@ fn fold_item(&mut self, item: Item) -> Option<Item> {
             }
         }
 
-        Some(self.fold_item_recur(item))
+        self.visit_item_recur(item)
     }
 }
index 5e3bd41b85c7e060c89d94eb829a30f717f7b1c6..85542ebd9ac559f4c5ddcfc546bdc34b893bcac8 100644 (file)
@@ -1,9 +1,9 @@
 use crate::clean;
 use crate::core::DocContext;
-use crate::fold::{self, DocFolder};
 use crate::html::markdown::{find_testable_code, ErrorCodes};
 use crate::passes::check_doc_test_visibility::{should_have_doc_example, Tests};
 use crate::passes::Pass;
+use crate::visit::DocVisitor;
 use rustc_hir as hir;
 use rustc_lint::builtin::MISSING_DOCS;
 use rustc_middle::lint::LintLevelSource;
@@ -23,7 +23,7 @@
 
 fn calculate_doc_coverage(krate: clean::Crate, ctx: &mut DocContext<'_>) -> clean::Crate {
     let mut calc = CoverageCalculator { items: Default::default(), ctx };
-    let krate = calc.fold_crate(krate);
+    calc.visit_crate(&krate);
 
     calc.print_results();
 
@@ -182,17 +182,18 @@ fn print_table_record(
     }
 }
 
-impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
-    fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
+impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> {
+    fn visit_item(&mut self, i: &clean::Item) {
+        if !i.def_id.is_local() {
+            // non-local items are skipped because they can be out of the users control,
+            // especially in the case of trait impls, which rustdoc eagerly inlines
+            return;
+        }
+
         match *i.kind {
-            _ if !i.def_id.is_local() => {
-                // non-local items are skipped because they can be out of the users control,
-                // especially in the case of trait impls, which rustdoc eagerly inlines
-                return Some(i);
-            }
             clean::StrippedItem(..) => {
                 // don't count items in stripped modules
-                return Some(i);
+                return;
             }
             // docs on `use` and `extern crate` statements are not displayed, so they're not
             // worth counting
@@ -269,6 +270,6 @@ fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
             }
         }
 
-        Some(self.fold_item_recur(i))
+        self.visit_item_recur(i)
     }
 }
index d2b3c5239c778f4b5c83b1b327e8e95b5a810f33..fd2ab0dc97cb2230373a3cfb9832eb6400170336 100644 (file)
@@ -8,9 +8,9 @@
 
 use crate::clean;
 use crate::core::DocContext;
-use crate::fold::DocFolder;
 use crate::html::markdown::{self, RustCodeBlock};
 use crate::passes::Pass;
+use crate::visit::DocVisitor;
 
 crate const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass {
     name: "check-code-block-syntax",
@@ -19,7 +19,8 @@
 };
 
 crate fn check_code_block_syntax(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
-    SyntaxChecker { cx }.fold_crate(krate)
+    SyntaxChecker { cx }.visit_crate(&krate);
+    krate
 }
 
 struct SyntaxChecker<'a, 'tcx> {
@@ -36,7 +37,7 @@ fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeB
         let source = dox[code_block.code].to_owned();
         let sess = ParseSess::with_span_handler(handler, sm);
 
-        let edition = code_block.lang_string.edition.unwrap_or(self.cx.tcx.sess.edition());
+        let edition = code_block.lang_string.edition.unwrap_or_else(|| self.cx.tcx.sess.edition());
         let expn_data = ExpnData::default(
             ExpnKind::AstPass(AstPass::TestHarness),
             DUMMY_SP,
@@ -77,7 +78,7 @@ fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeB
         // The span and whether it is precise or not.
         let (sp, precise_span) = match super::source_span_for_markdown_range(
             self.cx.tcx,
-            &dox,
+            dox,
             &code_block.range,
             &item.attrs,
         ) {
@@ -123,7 +124,7 @@ fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeB
 
             // FIXME(#67563): Provide more context for these errors by displaying the spans inline.
             for message in buffer.messages.iter() {
-                diag.note(&message);
+                diag.note(message);
             }
 
             diag.emit();
@@ -141,8 +142,8 @@ fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeB
     }
 }
 
-impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
-    fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
+impl<'a, 'tcx> DocVisitor for SyntaxChecker<'a, 'tcx> {
+    fn visit_item(&mut self, item: &clean::Item) {
         if let Some(dox) = &item.attrs.collapsed_doc_value() {
             let sp = item.attr_span(self.cx.tcx);
             let extra = crate::html::markdown::ExtraInfo::new_did(
@@ -150,12 +151,12 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                 item.def_id.expect_def_id(),
                 sp,
             );
-            for code_block in markdown::rust_code_blocks(&dox, &extra) {
-                self.check_rust_syntax(&item, &dox, code_block);
+            for code_block in markdown::rust_code_blocks(dox, &extra) {
+                self.check_rust_syntax(&item, dox, code_block);
             }
         }
 
-        Some(self.fold_item_recur(item))
+        self.visit_item_recur(item)
     }
 }
 
index 1f7d6054233dd987b5bb8e0f05b858d3b7791226..7d3010cf3325b327c03f2b67b93d2c7190de34eb 100644 (file)
@@ -7,8 +7,8 @@
 use crate::clean;
 use crate::clean::*;
 use crate::core::DocContext;
-use crate::fold::DocFolder;
 use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString};
+use crate::visit::DocVisitor;
 use crate::visit_ast::inherits_doc_hidden;
 use rustc_hir as hir;
 use rustc_middle::lint::LintLevelSource;
@@ -27,17 +27,17 @@ struct DocTestVisibilityLinter<'a, 'tcx> {
 
 crate fn check_doc_test_visibility(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
     let mut coll = DocTestVisibilityLinter { cx };
-
-    coll.fold_crate(krate)
+    coll.visit_crate(&krate);
+    krate
 }
 
-impl<'a, 'tcx> DocFolder for DocTestVisibilityLinter<'a, 'tcx> {
-    fn fold_item(&mut self, item: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for DocTestVisibilityLinter<'a, 'tcx> {
+    fn visit_item(&mut self, item: &Item) {
         let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
 
         look_for_tests(self.cx, &dox, &item);
 
-        Some(self.fold_item_recur(item))
+        self.visit_item_recur(item)
     }
 }
 
@@ -115,10 +115,10 @@ fn add_test(&mut self, _: String, config: LangString, _: usize) {
 
     let mut tests = Tests { found_tests: 0 };
 
-    find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);
+    find_testable_code(dox, &mut tests, ErrorCodes::No, false, None);
 
     if tests.found_tests == 0 && cx.tcx.sess.is_nightly_build() {
-        if should_have_doc_example(cx, &item) {
+        if should_have_doc_example(cx, item) {
             debug!("reporting error for {:?} (hir_id={:?})", item, hir_id);
             let sp = item.attr_span(cx.tcx);
             cx.tcx.struct_span_lint_hir(
index 318c897bcbdf6f1c395effdc447d09cd689f1a16..8541e6e18816f5c783800fbe23be99e5780cc1fc 100644 (file)
 
 use crate::clean::{self, utils::find_nearest_parent_module, Crate, Item, ItemLink, PrimitiveType};
 use crate::core::DocContext;
-use crate::fold::DocFolder;
 use crate::html::markdown::{markdown_links, MarkdownLink};
 use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
 use crate::passes::Pass;
+use crate::visit::DocVisitor;
 
 mod early;
 crate use early::load_intra_link_crates;
 };
 
 fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
-    LinkCollector {
+    let mut collector = LinkCollector {
         cx,
         mod_ids: Vec::new(),
         kind_side_channel: Cell::new(None),
         visited_links: FxHashMap::default(),
-    }
-    .fold_crate(krate)
+    };
+    collector.visit_crate(&krate);
+    krate
 }
 
 /// Top-level errors emitted by this pass.
@@ -289,7 +290,7 @@ fn variant_field(
     ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
         let tcx = self.cx.tcx;
         let no_res = || ResolutionFailure::NotResolved {
-            module_id: module_id,
+            module_id,
             partial_res: None,
             unresolved: path_str.into(),
         };
@@ -437,7 +438,7 @@ fn resolve_macro(
     fn resolve_path(&self, path_str: &str, ns: Namespace, module_id: DefId) -> Option<Res> {
         let result = self.cx.enter_resolver(|resolver| {
             resolver
-                .resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
+                .resolve_str_path_error(DUMMY_SP, path_str, ns, module_id)
                 .and_then(|(_, res)| res.try_into())
         });
         debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
@@ -543,7 +544,7 @@ fn def_id_to_res(&self, ty_id: DefId) -> Option<Res> {
             ty::Uint(uty) => Res::Primitive(uty.into()),
             ty::Float(fty) => Res::Primitive(fty.into()),
             ty::Str => Res::Primitive(Str),
-            ty::Tuple(ref tys) if tys.is_empty() => Res::Primitive(Unit),
+            ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit),
             ty::Tuple(_) => Res::Primitive(Tuple),
             ty::Array(..) => Res::Primitive(Array),
             ty::Slice(_) => Res::Primitive(Slice),
@@ -816,8 +817,8 @@ fn is_derive_trait_collision<T>(ns: &PerNS<Result<(Res, T), ResolutionFailure<'_
     )
 }
 
-impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
-    fn fold_item(&mut self, item: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
+    fn visit_item(&mut self, item: &Item) {
         use rustc_middle::ty::DefIdTree;
 
         let parent_node =
@@ -911,17 +912,16 @@ fn fold_item(&mut self, item: Item) -> Option<Item> {
             }
         }
 
-        Some(if item.is_mod() {
+        if item.is_mod() {
             if !inner_docs {
                 self.mod_ids.push(item.def_id.expect_def_id());
             }
 
-            let ret = self.fold_item_recur(item);
+            self.visit_item_recur(item);
             self.mod_ids.pop();
-            ret
         } else {
-            self.fold_item_recur(item)
-        })
+            self.visit_item_recur(item)
+        }
     }
 }
 
@@ -978,13 +978,13 @@ fn preprocess_link<'a>(
     }
 
     // Parse and strip the disambiguator from the link, if present.
-    let (disambiguator, path_str, link_text) = match Disambiguator::from_str(&link) {
+    let (disambiguator, path_str, link_text) = match Disambiguator::from_str(link) {
         Ok(Some((d, path, link_text))) => (Some(d), path.trim(), link_text.trim()),
         Ok(None) => (None, link.trim(), link.trim()),
         Err((err_msg, relative_range)) => {
             // Only report error if we would not have ignored this link. See issue #83859.
             if !should_ignore_link_with_disambiguators(link) {
-                let no_backticks_range = range_between_backticks(&ori_link);
+                let no_backticks_range = range_between_backticks(ori_link);
                 let disambiguator_range = (no_backticks_range.start + relative_range.start)
                     ..(no_backticks_range.start + relative_range.end);
                 return Some(Err(PreprocessingError::Disambiguator(disambiguator_range, err_msg)));
@@ -1000,7 +1000,7 @@ fn preprocess_link<'a>(
 
     // Strip generics from the path.
     let path_str = if path_str.contains(['<', '>'].as_slice()) {
-        match strip_generics_from_path(&path_str) {
+        match strip_generics_from_path(path_str) {
             Ok(path) => path,
             Err(err_kind) => {
                 debug!("link has malformed generics: {}", path_str);
@@ -1228,7 +1228,7 @@ fn resolve_link(
                 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);
+                    privacy_error(self.cx, &diag_info, path_str);
                 }
             }
 
@@ -1766,8 +1766,8 @@ fn report_diagnostic(
 
         let span =
             super::source_span_for_markdown_range(tcx, dox, link_range, &item.attrs).map(|sp| {
-                if dox.bytes().nth(link_range.start) == Some(b'`')
-                    && dox.bytes().nth(link_range.end - 1) == Some(b'`')
+                if dox.as_bytes().get(link_range.start) == Some(&b'`')
+                    && dox.as_bytes().get(link_range.end - 1) == Some(&b'`')
                 {
                     sp.with_lo(sp.lo() + BytePos(1)).with_hi(sp.hi() - BytePos(1))
                 } else {
@@ -1868,8 +1868,7 @@ fn split(path: &str) -> Option<(&str, &str)> {
                         };
                         name = start;
                         for ns in [TypeNS, ValueNS, MacroNS] {
-                            if let Some(res) =
-                                collector.check_full_res(ns, &start, module_id, &None)
+                            if let Some(res) = collector.check_full_res(ns, start, module_id, &None)
                             {
                                 debug!("found partial_res={:?}", res);
                                 *partial_res = Some(res);
index cd90528ab9c8a9b6dd18040052680cb08ba4eef2..565bcb8bd1340c4763a24c33a800894f3c9f5f9a 100644 (file)
@@ -34,7 +34,7 @@ fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
         let attrs = crate::clean::Attributes::from_ast(attrs, None);
         for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() {
             debug!(?doc);
-            for link in markdown_links(&doc.as_str()) {
+            for link in markdown_links(doc.as_str()) {
                 debug!(?link.link);
                 let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
                     x.path_str
@@ -46,7 +46,7 @@ fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
                         span,
                         &path_str,
                         TypeNS,
-                        parent_module.unwrap_or(self.current_mod.to_def_id()),
+                        parent_module.unwrap_or_else(|| self.current_mod.to_def_id()),
                     );
                 });
             }
index 319dd7b42b0ee69cb4d2d23d656f79188977aa82..77513b05ff2f94ca982b0649291ce9aab8c46667 100644 (file)
@@ -1,9 +1,10 @@
 use super::Pass;
 use crate::clean::*;
 use crate::core::DocContext;
-use crate::fold::DocFolder;
+use crate::visit::DocVisitor;
 
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir::def_id::DefId;
 use rustc_middle::ty::DefIdTree;
 use rustc_span::symbol::sym;
 
     description: "retrieves trait impls for items in the crate",
 };
 
-crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
-    let (mut krate, synth_impls) = cx.sess().time("collect_synthetic_impls", || {
+crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+    let synth_impls = cx.sess().time("collect_synthetic_impls", || {
         let mut synth = SyntheticImplCollector { cx, impls: Vec::new() };
-        (synth.fold_crate(krate), synth.impls)
+        synth.visit_crate(&krate);
+        synth.impls
     });
 
     let prims: FxHashSet<PrimitiveType> = krate.primitives.iter().map(|p| p.1).collect();
 
     let crate_items = {
         let mut coll = ItemCollector::new();
-        krate = cx.sess().time("collect_items_for_trait_impls", || coll.fold_crate(krate));
+        cx.sess().time("collect_items_for_trait_impls", || coll.visit_crate(&krate));
         coll.items
     };
 
@@ -31,9 +33,7 @@
 
     for &cnum in cx.tcx.crates(()).iter() {
         for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() {
-            cx.tcx.sess.prof.generic_activity("build_extern_trait_impl").run(|| {
-                inline::build_impl(cx, None, did, None, &mut new_items);
-            });
+            inline::build_impl(cx, None, did, None, &mut new_items);
         }
     }
 
     }
 
     let mut cleaner = BadImplStripper { prims, items: crate_items };
+    let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
+
+    // Follow all `Deref` targets of included items and recursively add them as valid
+    fn add_deref_target(
+        map: &FxHashMap<DefId, &Type>,
+        cleaner: &mut BadImplStripper,
+        type_did: DefId,
+    ) {
+        if let Some(target) = map.get(&type_did) {
+            debug!("add_deref_target: type {:?}, target {:?}", type_did, target);
+            if let Some(target_prim) = target.primitive_type() {
+                cleaner.prims.insert(target_prim);
+            } else if let Some(target_did) = target.def_id_no_primitives() {
+                // `impl Deref<Target = S> for S`
+                if target_did == type_did {
+                    // Avoid infinite cycles
+                    return;
+                }
+                cleaner.items.insert(target_did.into());
+                add_deref_target(map, cleaner, target_did);
+            }
+        }
+    }
 
     // scan through included items ahead of time to splice in Deref targets to the "valid" sets
     for it in &new_items {
         if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
-            if cleaner.keep_impl(for_)
-                && trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait()
+            if trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait()
+                && cleaner.keep_impl(for_, true)
             {
                 let target = items
                     .iter()
 
                 if let Some(prim) = target.primitive_type() {
                     cleaner.prims.insert(prim);
-                } else if let Some(did) = target.def_id() {
+                } else if let Some(did) = target.def_id(&cx.cache) {
                     cleaner.items.insert(did.into());
                 }
+                if let Some(for_did) = for_.def_id_no_primitives() {
+                    if type_did_to_deref_target.insert(for_did, target).is_none() {
+                        // Since only the `DefId` portion of the `Type` instances is known to be same for both the
+                        // `Deref` target type and the impl for type positions, this map of types is keyed by
+                        // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
+                        if cleaner.keep_impl_with_def_id(for_did.into()) {
+                            add_deref_target(&type_did_to_deref_target, &mut cleaner, for_did);
+                        }
+                    }
+                }
             }
         }
     }
 
     new_items.retain(|it| {
         if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
-            cleaner.keep_impl(for_)
-                || trait_
-                    .as_ref()
-                    .map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into()))
+            cleaner.keep_impl(
+                for_,
+                trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait(),
+            ) || trait_.as_ref().map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into()))
                 || blanket_impl.is_some()
         } else {
             true
         }
     }
 
-    let items = if let ModuleItem(Module { ref mut items, .. }) = *krate.module.kind {
-        items
+    if let ModuleItem(Module { items, .. }) = &mut *krate.module.kind {
+        items.extend(synth_impls);
+        items.extend(new_items);
     } else {
         panic!("collect-trait-impls can't run");
     };
 
-    items.extend(synth_impls);
-    items.extend(new_items);
     krate
 }
 
@@ -136,8 +168,8 @@ struct SyntheticImplCollector<'a, 'tcx> {
     impls: Vec<Item>,
 }
 
-impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
-    fn fold_item(&mut self, i: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for SyntheticImplCollector<'a, 'tcx> {
+    fn visit_item(&mut self, i: &Item) {
         if i.is_struct() || i.is_enum() || i.is_union() {
             // FIXME(eddyb) is this `doc(hidden)` check needed?
             if !self
@@ -152,7 +184,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             }
         }
 
-        Some(self.fold_item_recur(i))
+        self.visit_item_recur(i)
     }
 }
 
@@ -167,11 +199,11 @@ fn new() -> Self {
     }
 }
 
-impl DocFolder for ItemCollector {
-    fn fold_item(&mut self, i: Item) -> Option<Item> {
+impl DocVisitor for ItemCollector {
+    fn visit_item(&mut self, i: &Item) {
         self.items.insert(i.def_id);
 
-        Some(self.fold_item_recur(i))
+        self.visit_item_recur(i)
     }
 }
 
@@ -181,14 +213,14 @@ struct BadImplStripper {
 }
 
 impl BadImplStripper {
-    fn keep_impl(&self, ty: &Type) -> bool {
+    fn keep_impl(&self, ty: &Type, is_deref: bool) -> bool {
         if let Generic(_) = ty {
             // keep impls made on generics
             true
         } else if let Some(prim) = ty.primitive_type() {
             self.prims.contains(&prim)
-        } else if let Some(did) = ty.def_id() {
-            self.keep_impl_with_def_id(did.into())
+        } else if let Some(did) = ty.def_id_no_primitives() {
+            is_deref || self.keep_impl_with_def_id(did.into())
         } else {
             false
         }
index a3fde92d7655d776e9bb27dbe1bff1ce7c5ee19c..56b222d893262148d94d4e9e794e37022fc90afd 100644 (file)
@@ -1,11 +1,13 @@
 use super::Pass;
 use crate::clean::*;
 use crate::core::DocContext;
-use crate::fold::DocFolder;
 use crate::html::markdown::main_body_opts;
-use core::ops::Range;
+use crate::visit::DocVisitor;
+
 use pulldown_cmark::{Event, Parser, Tag};
+
 use std::iter::Peekable;
+use std::ops::Range;
 use std::str::CharIndices;
 
 crate const CHECK_INVALID_HTML_TAGS: Pass = Pass {
@@ -19,13 +21,11 @@ struct InvalidHtmlTagsLinter<'a, 'tcx> {
 }
 
 crate fn check_invalid_html_tags(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
-    if !cx.tcx.sess.is_nightly_build() {
-        krate
-    } else {
+    if cx.tcx.sess.is_nightly_build() {
         let mut coll = InvalidHtmlTagsLinter { cx };
-
-        coll.fold_crate(krate)
+        coll.visit_crate(&krate);
     }
+    krate
 }
 
 const ALLOWED_UNCLOSED: &[&str] = &[
@@ -165,14 +165,14 @@ fn extract_tags(
     }
 }
 
-impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> {
-    fn fold_item(&mut self, item: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> {
+    fn visit_item(&mut self, item: &Item) {
         let tcx = self.cx.tcx;
         let hir_id = match DocContext::as_local_hir_id(tcx, item.def_id) {
             Some(hir_id) => hir_id,
             None => {
                 // If non-local, no need to check anything.
-                return Some(self.fold_item_recur(item));
+                return;
             }
         };
         let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
@@ -217,6 +217,6 @@ fn fold_item(&mut self, item: Item) -> Option<Item> {
             }
         }
 
-        Some(self.fold_item_recur(item))
+        self.visit_item_recur(item)
     }
 }
index 8b1fd662f85fdef57602ae5c3891b28af3547076..74a9a2da06d36db0b117a930f588435c5dbb91ee 100644 (file)
@@ -2,7 +2,7 @@
 use rustc_middle::middle::privacy::AccessLevels;
 use std::mem;
 
-use crate::clean::{self, GetDefId, Item, ItemIdSet};
+use crate::clean::{self, Item, ItemIdSet};
 use crate::fold::{strip_item, DocFolder};
 
 crate struct Stripper<'a> {
@@ -127,7 +127,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             if imp.trait_.is_none() && imp.items.is_empty() {
                 return None;
             }
-            if let Some(did) = imp.for_.def_id() {
+            if let Some(did) = imp.for_.def_id_no_primitives() {
                 if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
                 {
                     debug!("ImplStripper: impl item for stripped type; removing");
@@ -142,7 +142,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             }
             if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
                 for typaram in generics {
-                    if let Some(did) = typaram.def_id() {
+                    if let Some(did) = typaram.def_id_no_primitives() {
                         if did.is_local() && !self.retained.contains(&did.into()) {
                             debug!(
                                 "ImplStripper: stripped item in trait's generics; removing impl"
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
new file mode 100644 (file)
index 0000000..1b5a750
--- /dev/null
@@ -0,0 +1,300 @@
+//! This module analyzes crates to find call sites that can serve as examples in the documentation.
+
+use crate::clean;
+use crate::config;
+use crate::formats;
+use crate::formats::renderer::FormatRenderer;
+use crate::html::render::Context;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::{
+    self as hir,
+    intravisit::{self, Visitor},
+};
+use rustc_interface::interface;
+use rustc_macros::{Decodable, Encodable};
+use rustc_middle::hir::map::Map;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_serialize::{
+    opaque::{Decoder, FileEncoder},
+    Decodable, Encodable,
+};
+use rustc_session::getopts;
+use rustc_span::{
+    def_id::{CrateNum, DefPathHash, LOCAL_CRATE},
+    edition::Edition,
+    BytePos, FileName, SourceFile,
+};
+
+use std::fs;
+use std::path::PathBuf;
+
+#[derive(Debug, Clone)]
+crate struct ScrapeExamplesOptions {
+    output_path: PathBuf,
+    target_crates: Vec<String>,
+}
+
+impl ScrapeExamplesOptions {
+    crate fn new(
+        matches: &getopts::Matches,
+        diag: &rustc_errors::Handler,
+    ) -> Result<Option<Self>, i32> {
+        let output_path = matches.opt_str("scrape-examples-output-path");
+        let target_crates = matches.opt_strs("scrape-examples-target-crate");
+        match (output_path, !target_crates.is_empty()) {
+            (Some(output_path), true) => Ok(Some(ScrapeExamplesOptions {
+                output_path: PathBuf::from(output_path),
+                target_crates,
+            })),
+            (Some(_), false) | (None, true) => {
+                diag.err(&format!("must use --scrape-examples-output-path and --scrape-examples-target-crate together"));
+                Err(1)
+            }
+            (None, false) => Ok(None),
+        }
+    }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct SyntaxRange {
+    crate byte_span: (u32, u32),
+    crate line_span: (usize, usize),
+}
+
+impl SyntaxRange {
+    fn new(span: rustc_span::Span, file: &SourceFile) -> Self {
+        let get_pos = |bytepos: BytePos| file.original_relative_byte_pos(bytepos).0;
+        let get_line = |bytepos: BytePos| file.lookup_line(bytepos).unwrap();
+
+        SyntaxRange {
+            byte_span: (get_pos(span.lo()), get_pos(span.hi())),
+            line_span: (get_line(span.lo()), get_line(span.hi())),
+        }
+    }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct CallLocation {
+    crate call_expr: SyntaxRange,
+    crate enclosing_item: SyntaxRange,
+}
+
+impl CallLocation {
+    fn new(
+        expr_span: rustc_span::Span,
+        enclosing_item_span: rustc_span::Span,
+        source_file: &SourceFile,
+    ) -> Self {
+        CallLocation {
+            call_expr: SyntaxRange::new(expr_span, source_file),
+            enclosing_item: SyntaxRange::new(enclosing_item_span, source_file),
+        }
+    }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct CallData {
+    crate locations: Vec<CallLocation>,
+    crate url: String,
+    crate display_name: String,
+    crate edition: Edition,
+}
+
+crate type FnCallLocations = FxHashMap<PathBuf, CallData>;
+crate type AllCallLocations = FxHashMap<DefPathHash, FnCallLocations>;
+
+/// Visitor for traversing a crate and finding instances of function calls.
+struct FindCalls<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    map: Map<'tcx>,
+    cx: Context<'tcx>,
+    target_crates: Vec<CrateNum>,
+    calls: &'a mut AllCallLocations,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for FindCalls<'a, 'tcx>
+where
+    'tcx: 'a,
+{
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+        intravisit::NestedVisitorMap::OnlyBodies(self.map)
+    }
+
+    fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
+        intravisit::walk_expr(self, ex);
+
+        let tcx = self.tcx;
+
+        // If we visit an item that contains an expression outside a function body,
+        // then we need to exit before calling typeck (which will panic). See
+        // test/run-make/rustdoc-scrape-examples-invalid-expr for an example.
+        let hir = tcx.hir();
+        let owner = hir.local_def_id_to_hir_id(ex.hir_id.owner);
+        if hir.maybe_body_owned_by(owner).is_none() {
+            return;
+        }
+
+        // Get type of function if expression is a function call
+        let (ty, span) = match ex.kind {
+            hir::ExprKind::Call(f, _) => {
+                let types = tcx.typeck(ex.hir_id.owner);
+
+                match types.node_type_opt(f.hir_id) {
+                    Some(ty) => (ty, ex.span),
+                    None => {
+                        return;
+                    }
+                }
+            }
+            hir::ExprKind::MethodCall(_, _, _, span) => {
+                let types = tcx.typeck(ex.hir_id.owner);
+                let def_id = types.type_dependent_def_id(ex.hir_id).unwrap();
+                (tcx.type_of(def_id), span)
+            }
+            _ => {
+                return;
+            }
+        };
+
+        // If this span comes from a macro expansion, then the source code may not actually show
+        // a use of the given item, so it would be a poor example. Hence, we skip all uses in macros.
+        if span.from_expansion() {
+            trace!("Rejecting expr from macro: {:?}", span);
+            return;
+        }
+
+        // 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));
+        if enclosing_item_span.from_expansion() {
+            trace!("Rejecting expr ({:?}) from macro item: {:?}", span, enclosing_item_span);
+            return;
+        }
+
+        assert!(
+            enclosing_item_span.contains(span),
+            "Attempted to scrape call at [{:?}] whose enclosing item [{:?}] doesn't contain the span of the call.",
+            span,
+            enclosing_item_span
+        );
+
+        // Save call site if the function resolves to a concrete definition
+        if let ty::FnDef(def_id, _) = ty.kind() {
+            if self.target_crates.iter().all(|krate| *krate != def_id.krate) {
+                trace!("Rejecting expr from crate not being documented: {:?}", span);
+                return;
+            }
+
+            let file = tcx.sess.source_map().lookup_char_pos(span.lo()).file;
+            let file_path = match file.name.clone() {
+                FileName::Real(real_filename) => real_filename.into_local_path(),
+                _ => None,
+            };
+
+            if let Some(file_path) = file_path {
+                let abs_path = fs::canonicalize(file_path.clone()).unwrap();
+                let cx = &self.cx;
+                let mk_call_data = || {
+                    let clean_span = crate::clean::types::Span::new(span);
+                    let url = cx.href_from_span(clean_span, false).unwrap();
+                    let display_name = file_path.display().to_string();
+                    let edition = span.edition();
+                    CallData { locations: Vec::new(), url, display_name, edition }
+                };
+
+                let fn_key = tcx.def_path_hash(*def_id);
+                let fn_entries = self.calls.entry(fn_key).or_default();
+
+                trace!("Including expr: {:?}", span);
+                let location = CallLocation::new(span, enclosing_item_span, &file);
+                fn_entries.entry(abs_path).or_insert_with(mk_call_data).locations.push(location);
+            }
+        }
+    }
+}
+
+crate fn run(
+    krate: clean::Crate,
+    renderopts: config::RenderOptions,
+    cache: formats::cache::Cache,
+    tcx: TyCtxt<'_>,
+    options: ScrapeExamplesOptions,
+) -> interface::Result<()> {
+    let inner = move || -> Result<(), String> {
+        // Generates source files for examples
+        let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?;
+
+        // Collect CrateIds corresponding to provided target crates
+        // If two different versions of the crate in the dependency tree, then examples will be collcted from both.
+        let all_crates = tcx
+            .crates(())
+            .iter()
+            .chain([&LOCAL_CRATE])
+            .map(|crate_num| (crate_num, tcx.crate_name(*crate_num)))
+            .collect::<Vec<_>>();
+        let target_crates = options
+            .target_crates
+            .into_iter()
+            .map(|target| all_crates.iter().filter(move |(_, name)| name.as_str() == target))
+            .flatten()
+            .map(|(crate_num, _)| **crate_num)
+            .collect::<Vec<_>>();
+
+        debug!("All crates in TyCtxt: {:?}", all_crates);
+        debug!("Scrape examples target_crates: {:?}", target_crates);
+
+        // Run call-finder on all items
+        let mut calls = FxHashMap::default();
+        let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
+        tcx.hir().visit_all_item_likes(&mut finder.as_deep_visitor());
+
+        // Sort call locations within a given file in document order
+        for fn_calls in calls.values_mut() {
+            for file_calls in fn_calls.values_mut() {
+                file_calls.locations.sort_by_key(|loc| loc.call_expr.byte_span.0);
+            }
+        }
+
+        // Save output to provided path
+        let mut encoder = FileEncoder::new(options.output_path).map_err(|e| e.to_string())?;
+        calls.encode(&mut encoder).map_err(|e| e.to_string())?;
+        encoder.flush().map_err(|e| e.to_string())?;
+
+        Ok(())
+    };
+
+    if let Err(e) = inner() {
+        tcx.sess.fatal(&e);
+    }
+
+    Ok(())
+}
+
+// Note: the Handler must be passed in explicitly because sess isn't available while parsing options
+crate fn load_call_locations(
+    with_examples: Vec<String>,
+    diag: &rustc_errors::Handler,
+) -> Result<AllCallLocations, i32> {
+    let inner = || {
+        let mut all_calls: AllCallLocations = FxHashMap::default();
+        for path in with_examples {
+            let bytes = fs::read(&path).map_err(|e| format!("{} (for path {})", e, path))?;
+            let mut decoder = Decoder::new(&bytes, 0);
+            let calls = AllCallLocations::decode(&mut decoder)?;
+
+            for (function, fn_calls) in calls.into_iter() {
+                all_calls.entry(function).or_default().extend(fn_calls.into_iter());
+            }
+        }
+
+        Ok(all_calls)
+    };
+
+    inner().map_err(|e: String| {
+        diag.err(&format!("failed to load examples: {}", e));
+        1
+    })
+}
diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs
new file mode 100644 (file)
index 0000000..df4d155
--- /dev/null
@@ -0,0 +1,71 @@
+use crate::clean::*;
+
+crate trait DocVisitor: Sized {
+    fn visit_item(&mut self, item: &Item) {
+        self.visit_item_recur(item)
+    }
+
+    /// don't override!
+    fn visit_inner_recur(&mut self, kind: &ItemKind) {
+        match kind {
+            StrippedItem(..) => unreachable!(),
+            ModuleItem(i) => {
+                self.visit_mod(i);
+                return;
+            }
+            StructItem(i) => i.fields.iter().for_each(|x| self.visit_item(x)),
+            UnionItem(i) => i.fields.iter().for_each(|x| self.visit_item(x)),
+            EnumItem(i) => i.variants.iter().for_each(|x| self.visit_item(x)),
+            TraitItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
+            ImplItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
+            VariantItem(i) => match i {
+                Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
+                Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
+                Variant::CLike => {}
+            },
+            ExternCrateItem { src: _ }
+            | ImportItem(_)
+            | FunctionItem(_)
+            | TypedefItem(_, _)
+            | OpaqueTyItem(_)
+            | StaticItem(_)
+            | ConstantItem(_)
+            | TraitAliasItem(_)
+            | TyMethodItem(_)
+            | MethodItem(_, _)
+            | StructFieldItem(_)
+            | ForeignFunctionItem(_)
+            | ForeignStaticItem(_)
+            | ForeignTypeItem
+            | MacroItem(_)
+            | ProcMacroItem(_)
+            | PrimitiveItem(_)
+            | AssocConstItem(_, _)
+            | AssocTypeItem(_, _)
+            | KeywordItem(_) => {}
+        }
+    }
+
+    /// don't override!
+    fn visit_item_recur(&mut self, item: &Item) {
+        match &*item.kind {
+            StrippedItem(i) => self.visit_inner_recur(i),
+            _ => self.visit_inner_recur(&item.kind),
+        }
+    }
+
+    fn visit_mod(&mut self, m: &Module) {
+        m.items.iter().for_each(|i| self.visit_item(i))
+    }
+
+    fn visit_crate(&mut self, c: &Crate) {
+        self.visit_item(&c.module);
+
+        // FIXME: make this a simple by-ref for loop once external_traits is cleaned up
+        let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
+        for (k, v) in external_traits {
+            v.trait_.items.iter().for_each(|i| self.visit_item(i));
+            c.external_traits.borrow_mut().insert(k, v);
+        }
+    }
+}
index 36b1a14f6c1ea488f0d26af3316584a9373ff7e2..5d1f934240f037f0de0e2c18e8252a543f350957 100644 (file)
@@ -9,7 +9,6 @@
 use rustc_hir::CRATE_HIR_ID;
 use rustc_middle::middle::privacy::AccessLevel;
 use rustc_middle::ty::TyCtxt;
-use rustc_span;
 use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -87,13 +86,21 @@ fn store_path(&mut self, did: DefId) {
         // the rexport defines the path that a user will actually see. Accordingly,
         // we add the rexport as an item here, and then skip over the original
         // definition in `visit_item()` below.
+        //
+        // We also skip `#[macro_export] macro_rules!` that have already been inserted,
+        // it can happen if within the same module a `#[macro_export] macro_rules!`
+        // is declared but also a reexport of itself producing two exports of the same
+        // macro in the same module.
+        let mut inserted = FxHashSet::default();
         for export in self.cx.tcx.module_exports(CRATE_DEF_ID).unwrap_or(&[]) {
             if let Res::Def(DefKind::Macro(_), def_id) = export.res {
                 if let Some(local_def_id) = def_id.as_local() {
                     if self.cx.tcx.has_attr(def_id, sym::macro_export) {
-                        let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
-                        let item = self.cx.tcx.hir().expect_item(hir_id);
-                        top_level_module.items.push((item, None));
+                        if inserted.insert(def_id) {
+                            let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
+                            let item = self.cx.tcx.hir().expect_item(hir_id);
+                            top_level_module.items.push((item, None));
+                        }
                     }
                 }
             }
@@ -113,11 +120,9 @@ fn store_path(&mut self, did: DefId) {
                     .unwrap_or(&[])
                     .iter()
                     .filter_map(|attr| {
-                        Some(
-                            Cfg::parse(attr.meta_item()?)
-                                .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg))
-                                .ok()?,
-                        )
+                        Cfg::parse(attr.meta_item()?)
+                            .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg))
+                            .ok()
                     })
                     .collect::<Vec<_>>()
             })
@@ -271,7 +276,7 @@ fn visit_item(
             _ if self.inlining && !is_pub => {}
             hir::ItemKind::GlobalAsm(..) => {}
             hir::ItemKind::Use(_, hir::UseKind::ListStem) => {}
-            hir::ItemKind::Use(ref path, kind) => {
+            hir::ItemKind::Use(path, kind) => {
                 let is_glob = kind == hir::UseKind::Glob;
 
                 // Struct and variant constructors and proc macro stubs always show up alongside
index 372204dbbf703cde43bcd10c0096201ff377cf70..b5a4a3a03fdd7ac1259cfc46b1c39651cf07663e 100644 (file)
   "__comment": "Generated by `./x.py run src/tools/bump-stage0`. Run that command again to update the bootstrap compiler.",
   "dist_server": "https://static.rust-lang.org",
   "compiler": {
-    "date": "2021-09-08",
+    "date": "2021-10-22",
     "version": "beta"
   },
   "rustfmt": {
-    "date": "2021-09-08",
+    "date": "2021-10-23",
     "version": "nightly"
   },
   "checksums_sha256": {
-    "dist/2021-09-08/cargo-beta-aarch64-apple-darwin.tar.gz": "5bc2e21b10c153fd070c1a9b9af8ff68ada71f10953d8261bd8aa5f599878db3",
-    "dist/2021-09-08/cargo-beta-aarch64-apple-darwin.tar.xz": "95082b292ccf8e0fdd637f591dd3180297c48ec13ccbcb3e1a2c115feb17463f",
-    "dist/2021-09-08/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "7de49c4e1db688089dd566647c23233fb4ff21dbb4025a4be37d18b11cc82e2f",
-    "dist/2021-09-08/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "35394e3c08a3dd392958187b091b3bdc576a6bf0d2d139556df21cd3ff1d21cc",
-    "dist/2021-09-08/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "a71153dde967a7816636dce62ba4334baadad4b926b25dc54c068c5cb293df9a",
-    "dist/2021-09-08/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "d4e33616af35dd7564a73e702eb6eab7eae5da7a980f518bd3d34f4cf0d05440",
-    "dist/2021-09-08/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "f76545e48977d2ebad75d3cf745d81ca709d59ca02a6c66ee3d049d8ca145463",
-    "dist/2021-09-08/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "79cf346367022c3a1ba58fd134f8189fa7781e702871d56f60dc1fff9d318570",
-    "dist/2021-09-08/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "7884e6a177a2469f21dee177564e03490fc541e877f0a1858e17162a9037298c",
-    "dist/2021-09-08/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "6fb307038c827d4e915224bc17709929628bdc5eda625644eaa4df992de75718",
-    "dist/2021-09-08/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "a367fc19f65b07cfec4732d3bd13aa662581d9aca886d56c93bad171948c9593",
-    "dist/2021-09-08/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "161eabe9fc1a0031f9fb044da4cc4c2cf376c6a018695f9fa1f5d7ce96c742d1",
-    "dist/2021-09-08/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "35587eeb680443f759c6cc9526186d51e35b08683f9c8a112d692324b62afae4",
-    "dist/2021-09-08/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "8fea8765c22e9751379585d381ad14aa0faab811cfaf40dbb55a60c82146b91e",
-    "dist/2021-09-08/cargo-beta-i686-pc-windows-gnu.tar.gz": "9e7e075e79cfca74b1185067962e3b37118ed32c8258d6746f05891f742226cb",
-    "dist/2021-09-08/cargo-beta-i686-pc-windows-gnu.tar.xz": "50f34954765c542076e7a6d9dbaf3a8e8dbfbabfa95bbc76e95eb1fb52e1227a",
-    "dist/2021-09-08/cargo-beta-i686-pc-windows-msvc.tar.gz": "eb93a58581ff485b44013d3623d0f4afb0fc2e3a3c7ff1898b74faad6f7bf48d",
-    "dist/2021-09-08/cargo-beta-i686-pc-windows-msvc.tar.xz": "1913dd2d4b0c56a6e5ec3686fa03eafc716006cc1fcdcfd81cf1b7984b9532b1",
-    "dist/2021-09-08/cargo-beta-i686-unknown-linux-gnu.tar.gz": "04b3f5ca4f4a24a2555c186600f683730a59f807d3525248c1d8f2f674cd00a6",
-    "dist/2021-09-08/cargo-beta-i686-unknown-linux-gnu.tar.xz": "c730e3f619d69d221277f3b44a188746980eb7a0c79dab9a252cea6bc4a1e54b",
-    "dist/2021-09-08/cargo-beta-mips-unknown-linux-gnu.tar.gz": "94fc426e50671c39d7a272b9636ce43bc3242f1b6a302555914127ab73ce6c65",
-    "dist/2021-09-08/cargo-beta-mips-unknown-linux-gnu.tar.xz": "c44957519099e19edfeceed53b99674d9b98731b20ca7494621fb0dcc6488ed5",
-    "dist/2021-09-08/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "377a998bba44a16bb401bf56c4be2e38f1c40e37f71335f93ba8e54d20d7a3c3",
-    "dist/2021-09-08/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "2406c2ac61d9b494b3a6327d991a6846a18c867fc581892874a2e3e83f4d49fe",
-    "dist/2021-09-08/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "52c7d8009a6ca8701912c9e02c1278dacd2b6c2bdb218416d1e3db2c750b7536",
-    "dist/2021-09-08/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "764820946adfd6594c7c9c4f97cb06d1c639ae2621ded3059d234a0cef97b1dd",
-    "dist/2021-09-08/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "d351cbcd87d10d54bde4311d6fc902a655e8c74ffb16b2a85cfb8e5ad30faeda",
-    "dist/2021-09-08/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "ec7235af6ae25ce30c61d06f94bd398018878b741d8d94edad8e3dbaaad0cc2e",
-    "dist/2021-09-08/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "11d983f439f46a1b49d72b0e8ec1dd5f78c72c23f305476ce3b56ec20167ccc9",
-    "dist/2021-09-08/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "327fcdfcc7679178e734293e23e752d44bf1a4c44a88e5b2d89bfa7f95b7876c",
-    "dist/2021-09-08/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "52f827f09376c0f21419cbff1e56d30337d140c1c097d5a38d4541f65545d3d2",
-    "dist/2021-09-08/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "e9f956aaa4f8428b813d27c43a8602671a27f567d206f769da7b14e5029f5a1f",
-    "dist/2021-09-08/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "b59d4814b99031a9e418fd423833500a3436b65b0696974d1d6a2f7598ecce2d",
-    "dist/2021-09-08/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "5751e2453329e1fe2378cf9e7ade93c75df7a31d4dbeb0f14fde9c3cfbc5d5b1",
-    "dist/2021-09-08/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "a3d97d9efad02108166878a9a30d3485a9f6db0768bbef5c98e86540c6f4901c",
-    "dist/2021-09-08/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "e8c3bf169cdcf9192363c9ace37457a94720d36ff1b607e178796dac933f652f",
-    "dist/2021-09-08/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "51fc38135a45870bd01bbcee4b69f5e7055424b1cfa36d4c0272613baf3185c2",
-    "dist/2021-09-08/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "bc392d660368c856ab1bc96b603699d492f03b226a0d60812a1bb19ca6c05ff3",
-    "dist/2021-09-08/cargo-beta-x86_64-apple-darwin.tar.gz": "ea1804dfe7b806368f278adcb887e4aa023ff7f533bee84541415cb0862ed836",
-    "dist/2021-09-08/cargo-beta-x86_64-apple-darwin.tar.xz": "69fa3524d2bb2bbbf0c0a4e18ecbec3eeae791f9b60547d6adf0fa20123c4a41",
-    "dist/2021-09-08/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "611c3653a03ca05effb06b5857b77cb24fd87ae5f1d294df980c96a57b8a9a74",
-    "dist/2021-09-08/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "cca04b2298bea6b447daa806af2313da4797072d27ecc3202bd0633b5a1d5fb4",
-    "dist/2021-09-08/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "763d4ec911a374d348468a38d07caa8d559330c6179f5cd40b5a54ccdb355580",
-    "dist/2021-09-08/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "37d24786e764c3af201cba07ef88a27fac97d150d7711cfdbb625e957b9f0139",
-    "dist/2021-09-08/cargo-beta-x86_64-unknown-freebsd.tar.gz": "f39494da3f92c39be50579f26d7f09d8e5f985e3566f8742aacc1446ab9f92c1",
-    "dist/2021-09-08/cargo-beta-x86_64-unknown-freebsd.tar.xz": "b65f8024b47d4784ab59e4722e522e54442852bbe16906760f2708e2b0d0fe65",
-    "dist/2021-09-08/cargo-beta-x86_64-unknown-illumos.tar.gz": "072bb564f73a97bdc6d58970735191d8da0831926dcd155a946f0fde1f382a02",
-    "dist/2021-09-08/cargo-beta-x86_64-unknown-illumos.tar.xz": "fc6a9c6d4cceeac868b37e200ed193981b8d70e8408d8e4b4765e149a9075c3a",
-    "dist/2021-09-08/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "8074fc6912e4bdbae269a334f21d0ead7bb0f28344ad67d71f65487baf21cc35",
-    "dist/2021-09-08/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "32a8471b2fb91b62aeda637bdb1368c67d1b17daaeea2592517666393857af16",
-    "dist/2021-09-08/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "19dbfab31784d0615d0e84c526e98d9f47332492744bd1ab4fc7434c0762c5ad",
-    "dist/2021-09-08/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "510734acf369b92a3f1eb30921a96f393ae207af7dffe6a83df66c350bd1a510",
-    "dist/2021-09-08/cargo-beta-x86_64-unknown-netbsd.tar.gz": "85e2fb4ab2ca3eff3ce98ab1c74c996a6b9cd2c20ff3f47c8624e261ac254195",
-    "dist/2021-09-08/cargo-beta-x86_64-unknown-netbsd.tar.xz": "2b1cff0bfa9bcece19e61f4be680ebaa05663e918fc9f3a20516efd91244e1c6",
-    "dist/2021-09-08/rust-std-beta-aarch64-apple-darwin.tar.gz": "54386650675047126f2b418485a5b2ca8bf3b568231fe54914512ae09809276e",
-    "dist/2021-09-08/rust-std-beta-aarch64-apple-darwin.tar.xz": "c7613b2089562353502560a6521139dfd7fd58a96c772877cf2ea7bfd62920d4",
-    "dist/2021-09-08/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "a80e59fa3885f73973d9c3eb50628718eda015b1e62f328152ee95971acb10c2",
-    "dist/2021-09-08/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "b0b65575680186ae6c032fabad5dd4352d17ec2d29ecc22771ab9f86a54b90e8",
-    "dist/2021-09-08/rust-std-beta-aarch64-apple-ios.tar.gz": "22fdfea8abb345a32ca47ce658c601c36d7838cf22383a34470db643a14e89b3",
-    "dist/2021-09-08/rust-std-beta-aarch64-apple-ios.tar.xz": "3a145167eb7bd82e59df7bd009f69f4951efb1487cf002c584625c24be35f4c0",
-    "dist/2021-09-08/rust-std-beta-aarch64-fuchsia.tar.gz": "97d1614ad18e71a09326d65ec4bb631c9974f4d3c63c9438b180646579227f7d",
-    "dist/2021-09-08/rust-std-beta-aarch64-fuchsia.tar.xz": "aabd6f6c8548b6576986f6fa2632ced035f0ad504da05d3dfd92ab0202104ff9",
-    "dist/2021-09-08/rust-std-beta-aarch64-linux-android.tar.gz": "5e67121330fd7e095f86c5dc71bd5180ec1669ad819ccf0bb4b38b46f35bcf94",
-    "dist/2021-09-08/rust-std-beta-aarch64-linux-android.tar.xz": "b3d72ba51cca485d742117c70915a5e57404d3f8c80356c8df388eba913e136d",
-    "dist/2021-09-08/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "f3eaf16070eb770d464a844e72257cca4ccce4ee2c380f276e82d259d8781326",
-    "dist/2021-09-08/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "846480e3eaf8d21fb4d99659a68e71259da613e54cfd098470c139e38ea5a447",
-    "dist/2021-09-08/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "198be5989e4d2d479582ef2002ec3041105555cbb86488ba563fce35ae1c5c18",
-    "dist/2021-09-08/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "706148bf9e562cf61d6f882a330e0fd150eb0593136a370cf559c54b6723f4c1",
-    "dist/2021-09-08/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "8e2718c2509c3db0696599dbd93f7a9c846228374ec0e24bf9f7b876a7714d71",
-    "dist/2021-09-08/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "e44e11ca1ac94d2335c19891fc8b85394b3935a86fa51c8a2c558faf8606c7bc",
-    "dist/2021-09-08/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "9439bb56b5c11e9fab00e02e7f931c4582a6dbb3aeb7b20e5ad0fe5420dd27d0",
-    "dist/2021-09-08/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "5e3187685291d52c500aba70de657478e08b5a69ecbf381f2ae41cb78cfd82d3",
-    "dist/2021-09-08/rust-std-beta-aarch64-unknown-none.tar.gz": "69c5da7ba93aeb93f8f7a6b581f1895b427c377c8f624274cf2691cacf845acc",
-    "dist/2021-09-08/rust-std-beta-aarch64-unknown-none.tar.xz": "8d66841c5e9e20d35b3791bbd10fb97e73b7abf602fee52a939a7096e0040eb0",
-    "dist/2021-09-08/rust-std-beta-arm-linux-androideabi.tar.gz": "4901f22f057d78331d298c23b66a39b2caa39580b19adc007fa8a4780483b27c",
-    "dist/2021-09-08/rust-std-beta-arm-linux-androideabi.tar.xz": "ba5d5016a625f433dc2fdacb3a1c462a08cdf9cdfcd202a966f16386e58362cb",
-    "dist/2021-09-08/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "0ea2986826d17ea1baeecda1c73af27e41830d22aa10722ac18e1427a3c11295",
-    "dist/2021-09-08/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "11e8397c3b6cc2f0ce7c8d725e8bc8dd0a7b7c800174ca3f4da6ee4c32e338e9",
-    "dist/2021-09-08/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "019fb984e383342a3ec4069f7f62bbc33c9b9609202b571ae32fe6b0ddd2dd60",
-    "dist/2021-09-08/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "e86d5310c9181ccfd432bc93e6715d109f26608bea97fee0d9f0d2efaaa7126a",
-    "dist/2021-09-08/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "1a7c7bf25c54c9a394a671d7f23e5cb08d6501b25bbb687159a208dfa16b0d33",
-    "dist/2021-09-08/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "e8deaf7cf0031d73e93ac1f61713836a0413f644639f8f602d234bd583c660c2",
-    "dist/2021-09-08/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "0d72ae75cc1b59146dd799cb85a8c60ea9c4169f53f17b8eeb74da644bad0e21",
-    "dist/2021-09-08/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "1dd8c951a7e13e68686e9a9a3eb0ecdae83fb178454a0ace9c649b5b47fc9a50",
-    "dist/2021-09-08/rust-std-beta-armebv7r-none-eabi.tar.gz": "8b4b4163b746618c2dde450a7151ccdbfaf9732311fb959d11336bd78bfa8d25",
-    "dist/2021-09-08/rust-std-beta-armebv7r-none-eabi.tar.xz": "fa6ef79c9a3ac07c0cebe908eebab2a32f578f0838c0f939bf8f4136aed7a499",
-    "dist/2021-09-08/rust-std-beta-armebv7r-none-eabihf.tar.gz": "487c64e8251564373437f94b5e94d81bec50b61e77c39c691ce912cf95236d0d",
-    "dist/2021-09-08/rust-std-beta-armebv7r-none-eabihf.tar.xz": "2bae0e0b2383ee6182ce8df4dd26993aaa56aa4dd89e6cac1982a48414ca5d5c",
-    "dist/2021-09-08/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "bb5ca2b48383b27d181d90e4802cd387cacab9c00fca853c0deeb317270851b0",
-    "dist/2021-09-08/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "f7bf769be48434faddf3dbed8264b1ab5dbbb3657f5b71640ad9330b3340ca29",
-    "dist/2021-09-08/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "c88db813417a1263408cc3bffeaf03b45db7b2c0a89c8441b3f4e7514473a0c3",
-    "dist/2021-09-08/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "3c5a3ea4ce9a6826dd3fc1eaae8615701bf3b5c53d56fe6948432229f027ac1c",
-    "dist/2021-09-08/rust-std-beta-armv7-linux-androideabi.tar.gz": "3d45d64267149d222337421be4cd5207812125f9b2df253f507f0cc2cba37219",
-    "dist/2021-09-08/rust-std-beta-armv7-linux-androideabi.tar.xz": "ee71e74b369b42a9c2258bf5d9c8c7119ee65b8951d4655c477a4593ec2cf3fa",
-    "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "949bce55fc6047a37f8ea26e21cc69557ad66a45c688442f2be06a8cab503358",
-    "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "28ec52f486459b436c0097db2b400a202ad1280591f2612cadf4daec1ef4e4a8",
-    "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "0f7782f0b6874c858de7171d255f12fe309e9255ad55a6406577feae3702fbc0",
-    "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "cf3bc863ecd6da3fb45c3d2f5b6741d57ff778b1bb2e4f0d05480c9aab480bbf",
-    "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "35e3647a940d2e2e37ed3a5b7c1a789f94b7f1a256f0bd339630bb7b0342c2e0",
-    "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "ed1ec913fd3e821501e52be1d3cdac3fbe5a6c00acd17204b1891aa5fa3e6f93",
-    "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "2fc9f5791717cc876d155f4cbb672dabf9fa308ac67636e50a75a5b5ea11369f",
-    "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "91ac6c321d172cfb62e6772c2c7340110fb9801a8d44814b69b477f611f09c58",
-    "dist/2021-09-08/rust-std-beta-armv7a-none-eabi.tar.gz": "69661706ec6749f851d6a967f69fc8e4de8e5a58da2a771129b22202918f6ce8",
-    "dist/2021-09-08/rust-std-beta-armv7a-none-eabi.tar.xz": "45275aea14a3f4547e0e2f11ce2cf364ac2c749cf0df467a54e27b39b65a5fe2",
-    "dist/2021-09-08/rust-std-beta-armv7r-none-eabi.tar.gz": "63ea71e69e36d916baca6eb42b4b4b6f2f69870063526533a2699f66fc0cb317",
-    "dist/2021-09-08/rust-std-beta-armv7r-none-eabi.tar.xz": "2d6f4ca658991a7b426d50330371922888706944eb3c1603288d4be2fa4f5457",
-    "dist/2021-09-08/rust-std-beta-armv7r-none-eabihf.tar.gz": "3d27ea42bd3a419ccf7f28b9ff040e077f3e963948924f996aaf718abeeb1709",
-    "dist/2021-09-08/rust-std-beta-armv7r-none-eabihf.tar.xz": "8f6bc34715629354b4d9f71d7a8693171b667604d237b433f7444df1228d2a36",
-    "dist/2021-09-08/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "f83bdc7e73590beab7ec915bb7a3a7531e485d7f73cf9c65150102748207d874",
-    "dist/2021-09-08/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "1068750fb0b4a7ec35b5674a6c7fb0368b043bee6df0fbe360f521c7c2f08b94",
-    "dist/2021-09-08/rust-std-beta-i586-pc-windows-msvc.tar.gz": "506bd86d803953bb086e057c6b2ee1fd9ffa0e08a0d7162189119cd21668cc0f",
-    "dist/2021-09-08/rust-std-beta-i586-pc-windows-msvc.tar.xz": "b608aff18260165b51acbc06d551c5eb003928f2c7551f83a1ac1782442826ac",
-    "dist/2021-09-08/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "c90eca1f2326cfa916e225199e2526719fc9b6f18e2b789366a9668a52eba339",
-    "dist/2021-09-08/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "ab382cc6c67bceaf76555a2c71c5f26e46802fe7c2713e173744b14371b742a5",
-    "dist/2021-09-08/rust-std-beta-i586-unknown-linux-musl.tar.gz": "dd52e44df6cd8bbac61d484e574d363125662fef270695e962900995a05818b3",
-    "dist/2021-09-08/rust-std-beta-i586-unknown-linux-musl.tar.xz": "e9c4bba480b748625898dc047b950a142ccda9e9fe1e329365741f09f640e843",
-    "dist/2021-09-08/rust-std-beta-i686-linux-android.tar.gz": "bb2e1dea2aae2f726420d8a5cd112f1bed6e06e95053f10c6497b1be878b180e",
-    "dist/2021-09-08/rust-std-beta-i686-linux-android.tar.xz": "df15194a40cce8c574b219164b75590ad9c55c03ab811682ebe89db004c651f4",
-    "dist/2021-09-08/rust-std-beta-i686-pc-windows-gnu.tar.gz": "c7b38618dda1cd13d52c59bb9a4632458aa7b20d90b01478fb506801c3fb41eb",
-    "dist/2021-09-08/rust-std-beta-i686-pc-windows-gnu.tar.xz": "83390b595e3273f0b02e05878064429a1815f18bceb7e0d77a63c5caecaebfeb",
-    "dist/2021-09-08/rust-std-beta-i686-pc-windows-msvc.tar.gz": "e7c6c8e5ae9d02e9f3c33b174862d1d6e0caf357c7c3cd510e63cc3472db816b",
-    "dist/2021-09-08/rust-std-beta-i686-pc-windows-msvc.tar.xz": "feb49ed3fdf25d7703134afefc3c04b0ed23d87adc02945bccac4b30c425fa16",
-    "dist/2021-09-08/rust-std-beta-i686-unknown-freebsd.tar.gz": "f633cb1bd2636eceaa87d98a214aa73907502aa92d4cb1a1869870c9bc6ad23a",
-    "dist/2021-09-08/rust-std-beta-i686-unknown-freebsd.tar.xz": "cd61b7dfe7ead85a79469008717bc52cb76572fc9688f82a50f07b0c7e0fafb2",
-    "dist/2021-09-08/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "b22f1285e8d179a372060916bc2a6d609499231f805b5cec2ef8d1e5d0c70d71",
-    "dist/2021-09-08/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "24fd3c052bdec08615e54438fbccd9e43c9956d25b1bfce6f3640eb164aa6f5d",
-    "dist/2021-09-08/rust-std-beta-i686-unknown-linux-musl.tar.gz": "df63f460486eeb9a11ed53c35814495e931492aed5abe44a841cd7a43a9e3719",
-    "dist/2021-09-08/rust-std-beta-i686-unknown-linux-musl.tar.xz": "3ba2d402c01b099b89518acded3734a552f64a330a7d21732ce641cf25cd5c8d",
-    "dist/2021-09-08/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "4cc5b2cfa6747155a0e0c6a7a835abd464bc9610fd071197af1ac50ab8f2fa1c",
-    "dist/2021-09-08/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "28f70f287f4cceba042b9574b16ce0403d73785bc6261c9a6739d770d5f354f9",
-    "dist/2021-09-08/rust-std-beta-mips-unknown-linux-musl.tar.gz": "04a8dc4e8144330f326dba5182928cf91c50c4b3513df0b67d55d601d3524a7e",
-    "dist/2021-09-08/rust-std-beta-mips-unknown-linux-musl.tar.xz": "06a91efa4f8ab42c3a0f9c2ae9279da87bb2a239f1032d1faa3583febace37cc",
-    "dist/2021-09-08/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "887728123ccd4bb75f4d42bffc1d2b7f46d8bdc4554a77b12578507cb44e7fd5",
-    "dist/2021-09-08/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "987598a67a36f428fa8fb21e0239aa345e952a1e6c64fefcc2fe2feda56bb864",
-    "dist/2021-09-08/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "2110b1b7456366668e093d27013d7002e302c6ecccff63c147c0346cd9a452b7",
-    "dist/2021-09-08/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "d6f16eca6526aeeef3ec7d0a9948ff5da3b7eff6e4bb9203a9546037df1f8d55",
-    "dist/2021-09-08/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "36a510c2a8fbc751416183b88680685c232646289504d2e2422e5208cd11670b",
-    "dist/2021-09-08/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "2f2a7a533d30cdb437bf31d18fb547680d646ec1765ca6c5fe16e449dbf3b613",
-    "dist/2021-09-08/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "09472066c8403c059e9d34ac2f7a4387e61726c45dd5ff2bc03b85543d8376c0",
-    "dist/2021-09-08/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "83c4a0f9ed4fa2884d1d193b79693c3af4e9c8603b9a1f3bd6eb827ba09a5466",
-    "dist/2021-09-08/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "739998734f48c9591b7aed3452d8425e2c916d202341ff63931fa473e3eb9a25",
-    "dist/2021-09-08/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "83be5e72fc8597f51c6b2cc216d90c8dba6be509b44fa25f3d7d285e1c54c7c0",
-    "dist/2021-09-08/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "0a02455697ac62af66b359d5b73436ce7b18274abd18ffa13b7f0f9c1df72f82",
-    "dist/2021-09-08/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "1cc6fe6ecfe4c10c2957806e56c1a0aa256ef5bb3ad4ca47f24aae42cf0fc0e3",
-    "dist/2021-09-08/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "f90d70acfa78388fe8e54a62f4fd9e773bd1455b036f6af13a5feec072de11e8",
-    "dist/2021-09-08/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "d2c491b6fb62bc5279447e7f5d96fbb679a225ec13d6c96c8f80cad859b0f5f8",
-    "dist/2021-09-08/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "17e9bca285df96b3bcd48297c89c096aab6b545d783e261103f7b364c214c09d",
-    "dist/2021-09-08/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "d4a8679af46449daa4db0acc23bda23aa5c8f35fb2ca9d0e065b35e30d6fc649",
-    "dist/2021-09-08/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "845cab4436d36b6eb2a914ab7c48bd49626a04053eee918fbbb78aba1d1e0a4a",
-    "dist/2021-09-08/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "b399647f0d9e8458570e8a9ab11b30d7258fa396ab019037b5bb391dbe65ead7",
-    "dist/2021-09-08/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "6c84662ba3c210b9d7c3332473cdc95dcf3e238d9c9010581accfafa37cdf4f8",
-    "dist/2021-09-08/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "594aba2abb126a615c93bb5c7927eb5a2ccdbe4c54c22bfdfa9cacf99e268889",
-    "dist/2021-09-08/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "439f5d5f1d2ee9db18c6e3b0bb831b037234852067a91f1a15bca38ca38b7a0b",
-    "dist/2021-09-08/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "227fa2ff323d20a2a8c29e0167fac78c7b88b8db3368b009b75d4a1cd49b7b29",
-    "dist/2021-09-08/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "5055560e4dc3df90bf127bb5133c8d2d0ba662c1b1b20d63453cd60ee3e04947",
-    "dist/2021-09-08/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "df1267905fe5a23c2ddc47fc0ade249bd663e6d3e8982193cb2a2a638e747e5c",
-    "dist/2021-09-08/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "2a702d0d0a0e2cf17a42eac549bd751eadc4398182f42590e3322cc7420b4cd1",
-    "dist/2021-09-08/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "98e5d336ee07556ff0fe01f89f9059cb977fa36d5f87ee8633aebb5fa6c8762b",
-    "dist/2021-09-08/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "de64e6d171a2c11e16142b1e964c0f0e0d6e4bab2e9e9d5d8121ee77fbdb60de",
-    "dist/2021-09-08/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "1dbb24b1ed6510f098f63933a596f1f58907c22320eb79394dce341af7d7b59a",
-    "dist/2021-09-08/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "66af911664286500164db018c0aad12a85da035fc1e2d6cffbe7603ff0145624",
-    "dist/2021-09-08/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "e8abd1f9f7344842af5f6a85d75404c1589fd17efbe5a8008ab52f082b7b3772",
-    "dist/2021-09-08/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "a9f06d8862f9bb805f438b1c01464dd7a9cd07ecd04b1246727ac290891da54f",
-    "dist/2021-09-08/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "6143b4b36bbdd1c56b978e9a2afc012163610fac7b8fb9bd9f24abb4e970b21d",
-    "dist/2021-09-08/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "5cb4c0616056f36c7cfe446fa97e146fd5c525be1de8bbdb5017ad0d07a9561d",
-    "dist/2021-09-08/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "9d2397f9d70956ddd50b37f8a7dba71d3cea9df5fa128e35d92cb162d7f938d4",
-    "dist/2021-09-08/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "b7e0fe340919a37cf8daeb1a747392c53fce4dafc84331f998479c3c12572973",
-    "dist/2021-09-08/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "464b2601346e014b2f5a9cc64dd32897be915742a5c75eeacf82691277c4f8de",
-    "dist/2021-09-08/rust-std-beta-sparcv9-sun-solaris.tar.gz": "40c61118e3e85343f6ea3059e41e3d2e3108f540331d8114948447307eea9b5f",
-    "dist/2021-09-08/rust-std-beta-sparcv9-sun-solaris.tar.xz": "3dfb77e1315a8367b4a5665ae9419843a8cb953ce4726b35307e7c7199514616",
-    "dist/2021-09-08/rust-std-beta-thumbv6m-none-eabi.tar.gz": "66632c7fad29f275ccfed907e395db12e621b17909e5e026d192f0b552fd4be1",
-    "dist/2021-09-08/rust-std-beta-thumbv6m-none-eabi.tar.xz": "a308cdebc35d65d8208fe2b2dc7b45dfb1a64405478d86b82bfb28115174a129",
-    "dist/2021-09-08/rust-std-beta-thumbv7em-none-eabi.tar.gz": "c342b21b5f61dcddea74b89f60f1d0d0622c5aedc79550d316b8744b522bda6f",
-    "dist/2021-09-08/rust-std-beta-thumbv7em-none-eabi.tar.xz": "a3b00a6b9b3fb8942700f91d32077520185a7c21d25620193cbe2e730a021f64",
-    "dist/2021-09-08/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "18f15f7e2ffe97f7be99e246144e6b9ad7445b1b66382112e71e08137a36b840",
-    "dist/2021-09-08/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "16eb54bf02813d45c6ff328ec7db8f16daf0e57dedfad7247249af2ec5133d4b",
-    "dist/2021-09-08/rust-std-beta-thumbv7m-none-eabi.tar.gz": "14bdada81be2379b2ead0212cc34add3ace87bd222532ada2a00b603180db946",
-    "dist/2021-09-08/rust-std-beta-thumbv7m-none-eabi.tar.xz": "f6cfa6bdcee91a6cab748fced0d2be7642b83cbe7d5fdcdf638fc3e86277d17e",
-    "dist/2021-09-08/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "e11e35a643c0a9983fb1f1e8f60ac073a4ee48c4a9f3e757f4fb55ea8364046d",
-    "dist/2021-09-08/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "2ee5fc11fb01f84e2346a17745c935f75d400a2448ec49d9e3535c98c3d67a73",
-    "dist/2021-09-08/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "61b26681fdb6957c3acd9aa32b011605786bed196cd71334d966ad9289efbb2f",
-    "dist/2021-09-08/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "bfd3391ebdc20690ede1a8a606f59df9009a473962deb04d3a89b266d0a89949",
-    "dist/2021-09-08/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "ae8d90bdd3d2faa2623ec30935e3e93bf3af6ad036eaae72bc8a3d086f7cd054",
-    "dist/2021-09-08/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "66ce451e2a0830808aa996b4643fa6ca6d89a072467d9df659ad4e202b73d561",
-    "dist/2021-09-08/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "1afbb6a4ee9ec38b7ad1c67c3df3371d188b831ffdb58ae96227e5c9a017f5d9",
-    "dist/2021-09-08/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "8c1e0000926fb4ff370763396e69aef70ed7871c33f01bc2d429abf31ee8d211",
-    "dist/2021-09-08/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "169852e1ae03792a8f492954258d08bc1483615e7121d587476ac4fc065c79a1",
-    "dist/2021-09-08/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "1da32effe4416f0cd5448a9061d57dd2f4b541f737a7036d20d78fd44f715ddb",
-    "dist/2021-09-08/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "39d22c8ff2620d4e6569eb75c86d4135a288bba00dcc479f4371a1e7e52fee4b",
-    "dist/2021-09-08/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "c34b1abdb8e3f3f913564a472b18dc52b239d7e327a4bd89d9bd0290d0b31635",
-    "dist/2021-09-08/rust-std-beta-wasm32-unknown-unknown.tar.gz": "ae284aa5819407e8daf022fbbf1f5d279366077faf25a6653d9c518ab3fe710e",
-    "dist/2021-09-08/rust-std-beta-wasm32-unknown-unknown.tar.xz": "be7a5b763db13ab1582a5f98fe7fb9ab1facdd645a7fe4544e0cbec9d1c58e76",
-    "dist/2021-09-08/rust-std-beta-wasm32-wasi.tar.gz": "ac9f39cb7924f48fc29d666dfda3c6001b6880d6efd956acfa734389ef7b5dbe",
-    "dist/2021-09-08/rust-std-beta-wasm32-wasi.tar.xz": "04d20256cea7b2394f72f6c0895a9d249fbd641fcaf616a628ad703e79c950a2",
-    "dist/2021-09-08/rust-std-beta-x86_64-apple-darwin.tar.gz": "c304a11e2361b42f80fb9c6f239cbfbd2b7ffdcf00fe49ac94e3a6d4a9d2d2b3",
-    "dist/2021-09-08/rust-std-beta-x86_64-apple-darwin.tar.xz": "35d51256fc42481b8265a02d756bb9bd84a23240156ed1fdf84ee3adaa77b8c2",
-    "dist/2021-09-08/rust-std-beta-x86_64-apple-ios.tar.gz": "6eec11897fe08b43fece4a1cf0ecec1ca247b3d01656b4a2a159815fbe13c626",
-    "dist/2021-09-08/rust-std-beta-x86_64-apple-ios.tar.xz": "faddd6de72f17f669e38dc2e9ef5cdd4b729cdbccaae6a7711c54b173d86bfd2",
-    "dist/2021-09-08/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "6741696a588c4e723d279e388d446271b773c6029a823c5e2135a08a018c6083",
-    "dist/2021-09-08/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "a62d276ad6a4832cadd3ef4c587cc77f588774b93b2807dc1ab9e0acff037838",
-    "dist/2021-09-08/rust-std-beta-x86_64-fuchsia.tar.gz": "38a61746734681a97e84419709bd3ebc722207db656737e7be75479e0d991f9f",
-    "dist/2021-09-08/rust-std-beta-x86_64-fuchsia.tar.xz": "b85bbcd1353315e5c4eef82707912566f6a1f94f706350ae0474a29ff33b603e",
-    "dist/2021-09-08/rust-std-beta-x86_64-linux-android.tar.gz": "de32ea66a8228857a34f39d8d47e6cb32a4db9efd73100e97afe12bf58f6d520",
-    "dist/2021-09-08/rust-std-beta-x86_64-linux-android.tar.xz": "e2f89e63a379ba8182acf1b4fba33f790e0cdf4675bc46239840ecde613b1835",
-    "dist/2021-09-08/rust-std-beta-x86_64-pc-solaris.tar.gz": "6136d0607905fe49617a8171896bfada258eb84cb00e8042fd67bef29732a714",
-    "dist/2021-09-08/rust-std-beta-x86_64-pc-solaris.tar.xz": "00a98839ab7d2302feeaa0fdbedc169bfb2bd7229c27aa274954efc73b52c4f3",
-    "dist/2021-09-08/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "2f711c4a26ed3b876e64e256bf1b4040552e80a06bec352a9d3479ed8ed6aca9",
-    "dist/2021-09-08/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "e479e495292512d67414d3056c322ea368559a0d95d827f944bae7382bea4e4a",
-    "dist/2021-09-08/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "ce43642d886784242a3914b799b1a77b60df642af2a41f75eac186b7f1b6104e",
-    "dist/2021-09-08/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "a83d236d59f04f3a51a6a34ccf7b79b4b2f269dc50e147d61e1e9c4a57925835",
-    "dist/2021-09-08/rust-std-beta-x86_64-sun-solaris.tar.gz": "a8e7f979fc8ad5bdaa4ea2965c305a3296dfe88ffa235cdb7aea8234e4a46138",
-    "dist/2021-09-08/rust-std-beta-x86_64-sun-solaris.tar.xz": "72ed0fb32e53b283c6a0e1752d231915b98504164965f7e2b5f06d8550e4c338",
-    "dist/2021-09-08/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "1f5535f9d44afdacf059681587239bf4d21985f1dfbd3ace94c864c2d7616a42",
-    "dist/2021-09-08/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "5faf349a9cc231c144c52de40f2a487a935c6f6146614547e64cabb26f037a23",
-    "dist/2021-09-08/rust-std-beta-x86_64-unknown-illumos.tar.gz": "0ae64780c9a944a32bc51b5efef9f0818025a423819ef60fdc799945d52bfd73",
-    "dist/2021-09-08/rust-std-beta-x86_64-unknown-illumos.tar.xz": "b3308afe75af668878959db95b039c6e1c4416badf67ee650b07f5cf07f14ab2",
-    "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "f8078421bde37f74dd0ffe0ea44704778baca779e502cb760371340a6bfa15a5",
-    "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "cc26d8fd139b35e13cf75c2942727bba7899a874d95f865c127b0c3af15707cd",
-    "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "6e0ef50cb8c4ce19d7de517ad51581c4d80043fa489278c0ba984a5d408269db",
-    "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "5c9380fb472de93ebfe59b21f2a74b5f19a632ef6eccf77a89cf0b26ce2054a7",
-    "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "264c78d59e71d4fa232f6f10713ee61d94c270e493eabad7318877afa46b7327",
-    "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "af3e5b1883e8fa7d49e64ce8754d656d2992eba33b8ec5f92245f2a82793abf4",
-    "dist/2021-09-08/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "0797448414c3421577705e725814dbf833a44b0930875fe418aa1eed9ebf6121",
-    "dist/2021-09-08/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "bd3ec2d0fde1e11a75bfc3b684c2d564bd5068519d1c5a382ae09379337236c9",
-    "dist/2021-09-08/rust-std-beta-x86_64-unknown-redox.tar.gz": "449ea2e6ed2e1b4d656f8da8390f2e22cbbe40713e5f91cbc85971f36488402d",
-    "dist/2021-09-08/rust-std-beta-x86_64-unknown-redox.tar.xz": "5424c5b4aa5588de73734dcd43cd1ff9bf0e0ba244749a1519afc94c8f2057e2",
-    "dist/2021-09-08/rustc-beta-aarch64-apple-darwin.tar.gz": "b14f7853a9353b71d7babeeb136fbb595b5c23144ac1bd72e70b74227a1685ca",
-    "dist/2021-09-08/rustc-beta-aarch64-apple-darwin.tar.xz": "af2ab319357b3b4a2810a52c824f8f308d2c3f41ea1ed30ba9ef9ff6a4769dde",
-    "dist/2021-09-08/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "c09a6bdbe6dccbdcd366a695d54be4e0a472fa1ca5bf30bf7eaf389534e2f70c",
-    "dist/2021-09-08/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "9fad7bc10840340081cd29166aa788843a9950e293d6ced71a26e36bf0eafe9e",
-    "dist/2021-09-08/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "d20cdcc681b0506e73ccd0b484a7b7394a08615d2d195318d0f2c5af3063581b",
-    "dist/2021-09-08/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "07d0b4393149f854dca2d622a6ac8d6cb9fc62d2d24977bcf50cdc1824fe6a32",
-    "dist/2021-09-08/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "dbe81393d5253521adceda8027b103edef45a031120e92f2e9e89564e85863c2",
-    "dist/2021-09-08/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "40edabc1e00f228815c88798543f55081e3dfe352f88753f5592479de9236b4b",
-    "dist/2021-09-08/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "114dce61c5bf25be9f3cb33cd0c7500b1a60f5cbebef27547458312b8ddb8f4d",
-    "dist/2021-09-08/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "abc9130f7116badf9949f5a3ecd6820787e40bb590ebbd5c867b05cedfbdce5f",
-    "dist/2021-09-08/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "cbebd112f0dd96258ed19b25762af60c9bac30669ae229d6b8456049779c890f",
-    "dist/2021-09-08/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "cff6cbf35aba285cfb5f5d2f8a9dee5edefc7c22843ae0198e693993d556fcae",
-    "dist/2021-09-08/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "c20cf9a2e72f712f02ed867e9c4babe02d7ff22d62eb96cb127054010b6731b6",
-    "dist/2021-09-08/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "aa1b6cd4f9153fba338eb5c8a90ace06d742c97e659c3ffbca75125e5477b828",
-    "dist/2021-09-08/rustc-beta-i686-pc-windows-gnu.tar.gz": "3308d1e3ee0ae40f8db301601c73bf6eace168b570e9ab952760e28bd970a240",
-    "dist/2021-09-08/rustc-beta-i686-pc-windows-gnu.tar.xz": "0a019f66979c2542bf9fb268bad143cd55deac6f1502a4393464bb26a1e21c76",
-    "dist/2021-09-08/rustc-beta-i686-pc-windows-msvc.tar.gz": "31016537cedf38ef83e29a6125445946834a06ec2fda51ef799566baeb47211d",
-    "dist/2021-09-08/rustc-beta-i686-pc-windows-msvc.tar.xz": "a997b98b7a28358bd4ed394ddd3af62e5b19d7a33a61f55bf973b06fb9b95fe5",
-    "dist/2021-09-08/rustc-beta-i686-unknown-linux-gnu.tar.gz": "ddfba3dfb711db2ebb4cd7149172a738200b8e38a98f7ec5e5bbc81515be5453",
-    "dist/2021-09-08/rustc-beta-i686-unknown-linux-gnu.tar.xz": "5b0435f652dc749216735fc06599a3c6916a867ab82dc126d0cde872855dac83",
-    "dist/2021-09-08/rustc-beta-mips-unknown-linux-gnu.tar.gz": "6408766f8c58c13ba51347375dc5ed0fb7c247c8aee9b8a89e3369c70541c397",
-    "dist/2021-09-08/rustc-beta-mips-unknown-linux-gnu.tar.xz": "18a41553893aa8ff4c80fef252e8ba80c383d2809a57123fe89e89172a5839c5",
-    "dist/2021-09-08/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "28078984a80c4cb0e65391ae213390059a9eebff028209861d23c82b4db0a11c",
-    "dist/2021-09-08/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "277cfaafab145858ee5102a657c597abbdfa33ed2d6f1c8806f218bad91b2d8f",
-    "dist/2021-09-08/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "8c8c92719f3d299047089031cb29ce209e2954466415449d37d474e88a732d8e",
-    "dist/2021-09-08/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "d055a61cd0ec951edbc703180c190ef4dbed3391d1b2472668340642e205fecb",
-    "dist/2021-09-08/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "95433c7dc0437f61a024276c10a0654128bd0e873597932297140f82e34ad201",
-    "dist/2021-09-08/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "a3660c9909e3821537a275e37121950d6adbc87b85959e80fd7b72c6e3b7b944",
-    "dist/2021-09-08/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "07384f5fba55ad572753fc85ad6b2d231d94b31f009defb694c8632b38eeeb62",
-    "dist/2021-09-08/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "f0985ea483fbad75a9cff021db6c230c5c322eff942da667a0dd6cb3e37bb2c6",
-    "dist/2021-09-08/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "81a7ddf94bf62f45dde9199df8b28ac9971d23b1817906e119ca4ea32000b08d",
-    "dist/2021-09-08/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "7ce055fd68b1c5e3c48c9f03289cd4eb3af619cc30a7103056b20fe842a92db8",
-    "dist/2021-09-08/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "6b853d5c2fd2dc61d89c26bf5b365f48a9c535dd30aa672f28f254af8fbcc9e3",
-    "dist/2021-09-08/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "32c659ea9578759020f291099f16b1d12eebae30e07d35568e69cd0721576c24",
-    "dist/2021-09-08/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "a73a918ec89b759f19b605df527471acbbcfd2e3debcd0601d7a3956f645bcf0",
-    "dist/2021-09-08/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "eabdfdac435195844bdfaaa5f8bf6b57cf045742c6180c3ff0822bd85fac40f5",
-    "dist/2021-09-08/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "a626ed9d5ce779e7fd8ab17d4dc83130a57200669730851bc68eb01d88bade7d",
-    "dist/2021-09-08/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "67f195e60d88b3e0f1a702f7ba0cefded2dca6ffc03ede1f9b6e4fd38592eb6d",
-    "dist/2021-09-08/rustc-beta-x86_64-apple-darwin.tar.gz": "01e5b6d7153866ada9d3c1caee5c95da58296acd7007aa93338171cc349af304",
-    "dist/2021-09-08/rustc-beta-x86_64-apple-darwin.tar.xz": "a0b87b79f87e97a746ad311f2bf36ee9d5784f504f844427415e4a983ea4a0ac",
-    "dist/2021-09-08/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "54ff5dfa917a5ebbaf77185d4efff9700d248dd66746dcb3942e29917495dd3b",
-    "dist/2021-09-08/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "2d9dddd6b9a3ef6c5bb0758dbee171f08882292ba17e1f98445a9cf196f9c02c",
-    "dist/2021-09-08/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "359690df63e15260f028d6838f4f5007f828c4a977cc657513b8ab6900f1d126",
-    "dist/2021-09-08/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "6d8d2b9d5964fe690d4f6fd7ee643bce5f049d19e33c7f3b580502ba83ce5ea5",
-    "dist/2021-09-08/rustc-beta-x86_64-unknown-freebsd.tar.gz": "5e47aa933805000f806984b09222808636eddcb58ea0b95913eae6c4f0ce913c",
-    "dist/2021-09-08/rustc-beta-x86_64-unknown-freebsd.tar.xz": "4e01128800f479a96597ce7eee9d2e76a5128ae1c13a4e0e2eb52e36d43cf559",
-    "dist/2021-09-08/rustc-beta-x86_64-unknown-illumos.tar.gz": "51cdd463ec6402dac5a4b0ab3b0e303ad97ba49c2a63e1cfa2d8036d060fd67a",
-    "dist/2021-09-08/rustc-beta-x86_64-unknown-illumos.tar.xz": "498cca6f9826a9180759a0446627e2e6dba50b6bf1051044e6e09dc714d7b3e7",
-    "dist/2021-09-08/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "59314c4c868e57a76f7cb4dd80cd9a7e6230b87080784db44349420c950efddc",
-    "dist/2021-09-08/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "8b3e2cdba3ff86144029f7c7446825dff79937ed8a30df15a33a779e9f694227",
-    "dist/2021-09-08/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "56dc8f8914bbe5beaa1e369fdc22d99ef98c9d864e24f5b7d64cf6188c400b1c",
-    "dist/2021-09-08/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "66cf18df72034540d756b29d69a4148123029ff512fc831a786fe15a9641382b",
-    "dist/2021-09-08/rustc-beta-x86_64-unknown-netbsd.tar.gz": "2315fd067e858501b4df44f2a4d042cef3f70b7314ee6cfe24749849b8d386ae",
-    "dist/2021-09-08/rustc-beta-x86_64-unknown-netbsd.tar.xz": "62b429e67f24365963b0744e9b4807ae2cb7aa280a5e425882e4894a2d3225fb",
-    "dist/2021-09-08/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "691922fb32f3da37532bb9be974ad1717af521ec2b71bca4bbb5e57f3c4cc3fa",
-    "dist/2021-09-08/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "2c9667209094b7a603d50d3dc684c505b2ab855c64dcd8b23fe09248a6e13cee",
-    "dist/2021-09-08/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "daee571bf222bb7addf0d495991acf3f5001b69bb97d31bb43f0466b4e43c600",
-    "dist/2021-09-08/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "f6d31e21f798427c5483256d54b25b6dca1d61ff8c601384c62648959ebbce25",
-    "dist/2021-09-08/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "98b2eaf259a1bfdc70e40a52e891920dec7fc6132ad8d2420f91655c793ea340",
-    "dist/2021-09-08/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "a97c1c2646f9628fcc92818d21f4925568681976727686701116d0e6a71693a7",
-    "dist/2021-09-08/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "a4df0726fba466a5180471d3e63735c2b5ee9794e9f42026b1e8ae404dd43ab6",
-    "dist/2021-09-08/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "92846ab58a75bddc0270c9f42234a6585edc9a382e2018baa776aa74bb13e444",
-    "dist/2021-09-08/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "a8dbc2a00d359c95f05b0b3cf08a12b6df9f888157ba57fa9ba4a134cf271075",
-    "dist/2021-09-08/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "44b17a06b015f9701291cec7e60b0932c5ebc29244f4a6e35736e9f5ccf47c41",
-    "dist/2021-09-08/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "ee54b0a25f061c29ea22977c7d36d6fa6bf85abee3b108135b53bcb37028af0b",
-    "dist/2021-09-08/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "0a721d2526a78f7e70f9a6c49d156b1c18cd627c066bc8f09b084910864ec252",
-    "dist/2021-09-08/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "584ba68113add6e113cffb5c93a8000cfea16d621ba337dc68cd4d106f5e2759",
-    "dist/2021-09-08/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "e450429fcd37f15b6e200f62d9cb4790b39b7227e0246b667c82fa3b9ecf1b75",
-    "dist/2021-09-08/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "e0aa68b96699402e7cc09329055826f63ac9899cf22828d56cf393476a70405a",
-    "dist/2021-09-08/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "6f10f279f81c35c718446e837f5f22fb61841c45f5172abb2d0d4a035065edcd",
-    "dist/2021-09-08/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "aeb05fcb66830d395bf9a819a05a44f179cad3f35016f76fa60a4959f9e3c69e",
-    "dist/2021-09-08/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "351ee1490533ac9fa00a21c6db6087cb498b0034cb21358d29a8b944bf0f77e3",
-    "dist/2021-09-08/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "418b0481fd2b074e9a0f195b9e07f888652642aced34136044bad997f7500802",
-    "dist/2021-09-08/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "90d04308cbfc845462687206bf13182d907afebd02bdf88cca9a27eb8f1e7e28",
-    "dist/2021-09-08/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "0d2f54c9927ac9de3c00f8f703d52d8310d1b36baa84dbcddf1159759b4bff06",
-    "dist/2021-09-08/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "7f2b33077267e6ae064b12c7d0082115ea7f011f168f0d0e3ad9dc7ac9d39705",
-    "dist/2021-09-08/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "bdc9fa2cdb295e453460f1bf7b12efaa673955c27b01f22df626de989c3e1a28",
-    "dist/2021-09-08/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "bacd376fe18068010ada3e52c531de5a07dcc8232f988feb9e90be59986efb3b",
-    "dist/2021-09-08/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "fdc93a8295c563be29793d36b6b1e25f579d187b7e234ced6f17b1fe3c1fac02",
-    "dist/2021-09-08/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "289fd400d4959968c0ffccd787d613943c8534527913d0dbed69e8a7251ca32c",
-    "dist/2021-09-08/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "2e655b764843cea5f0e70e2a5b2a0f13dd5fa65c4055f42c547e36372af08296",
-    "dist/2021-09-08/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "07f6657648d1d7033030e9e2d05bfb9ea0022e63ae72320074a3d09ac9639d09",
-    "dist/2021-09-08/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "b78878ec58d6b932d3d1f8e1fefdb7871b1404c701ab0d2f8645246b458ba650",
-    "dist/2021-09-08/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "dfa79cb51708794d2c814bff6a60a63ca5358df3670179f9a9ae828811e72ad8",
-    "dist/2021-09-08/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "017de1a82a0e3988d1216771082b5d0e3e083dc51d4a0f0266f1e610bac166da",
-    "dist/2021-09-08/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "a0a46a62b9af14d2147939967e545ad812d9acebe3d1ed861321a6dfd8d554ca",
-    "dist/2021-09-08/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "54dff0daec5dd2a2ab23cf4e92bf9b2d71839c37144b52e5b5aa899ddf027bda",
-    "dist/2021-09-08/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "e743e45dc695e0bd9a1ce5fdd183f89951a329ec433bb510d37c47b435152a7b",
-    "dist/2021-09-08/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "0e04ae69e03d9e7e8d1d60a265c7ed3c3608a19aaef6ad4aa7ae2b280d3552b8",
-    "dist/2021-09-08/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "6ec865bd38b0fde2c9c823f4cb110b96c2aac4f7976cc2a6be48ffa214aa4bc7",
-    "dist/2021-09-08/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "3b833517415dee73b1e0d381df441a96856e3bac77f101545624c382aad7902c",
-    "dist/2021-09-08/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "7a8a447cc2167d0a998ad3858dfec88beb8658043655087d208affbc94aa3e62",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "20de8ad3aa7507dd9657c4a4b959c38cc7f732a87bb757183033f78a96288e45",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "99561b207ba61b455d1522d95143ca4ccc6474187be2f38f1ebff2ed63d0092e",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "145eb25cc3b295060c5f5a354ea2321cd39df17ea4e3a5c73c3eea105f7454a4",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "356ede5cd8a7d51f9e25a54c329b1be1da7d6fe418cbe86fdae9c8bcd9970ac4",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "0cc0f10763b73c5e4c8bdcd15a563d7e9d705b192ed6e8edc50dd6a71b874761",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "d734aefabe95fa03710dc75e9851c8f2e654f19cec1381ecb18281837d19db38",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "e1c28472a81312560ca36719f0b61b7212a07d63e85d745f97cd8e3b9ea8f191",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "4d6a62738f842e54666c608a466c64f896097ffa65d10d30361704e4b8496eed",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "75b21690480f6214ed174ca86297d9a41f37731560adf5782ccd7116b0df583a",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "5c08f45f557da789d39bf203dfbcf2667f4196dedad327a19dc3ad5bb783079d",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "a7d579672b94978e8427584f7e9d2b6534f320719252db46fc6ee85082d646ff",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "6ffbdb558b9d25e9d923534413b25dc99bb5b9cc92b4774d5255cf70ec20b20d",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "fba0e7bc1401b830223b5207b63808e28403f48d1591c7d47c1681519c1883f7",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "644b3acc47cd7bbbb5405683ce94e7f32a8313ad265da753026bdb6c3687b608",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "3f152caa88299ab8aca2c6d39a5e36af995b95e3394c7d514ed94e87f7c61fa3",
-    "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "5f92b4d12a9eaa50b29b81a3dff1959e59966f362b67c346b74403138fdb320d"
+    "dist/2021-10-22/cargo-beta-aarch64-apple-darwin.tar.gz": "b81ef641492ff2f03a93c8fbfbcfa78db2f6574d1998569d68dd2ba0e08ee186",
+    "dist/2021-10-22/cargo-beta-aarch64-apple-darwin.tar.xz": "925090782ad982202ca554a84e9d4a7b190f94b0b220c23e73235383d6ca367d",
+    "dist/2021-10-22/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "eba42edfebc85c744f4c6874337847748df65e430915f47238a93b1b7e96840a",
+    "dist/2021-10-22/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "fd04a8c4058ff287ea0256fd9f33a4b04b4f098d6911e8d827525cdeda6f169e",
+    "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "c7abbf1f265435cc9f6f0773d30321fc99353e0ddbf0004d00f47433eb3aaab1",
+    "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "3363dfdcd7106841edbd9029676ac339ff54c142921d71d92e308bee2ee33066",
+    "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "fbc5d5f70a36fc73f4d34d101aef4be78e38b5009ebf690fe46ba32eff6c1fce",
+    "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "220f23f50645532df4e5a4b1d6d894ce66a6ee2e5576fdf552081644a74a1c8f",
+    "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "94b42b8639ce541c1a355991f20d9934c72e766b6200d742d2d5b3b2f499f782",
+    "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "e32e9df3ab261fe20c363406d655fdaeeefc9dbb3d69da4551cdf9c22c418eb2",
+    "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "301c303ec0db0e342ecce4e259e79810e082766bac8f9907c353bdf490177863",
+    "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "d6f9409076ab4e2dac5ac5c07bac6be30e83e281df9efe2fa68386928e2e6faf",
+    "dist/2021-10-22/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "a4a82d48b2b1e6a49c0a765f9ee4d01e7ce4b0543128745d13cf4684c56eca8c",
+    "dist/2021-10-22/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c9ca524ba0e76d9fe38f0e4af337d14b97fd97dcd83d80ebf4725b5b03bea3ac",
+    "dist/2021-10-22/cargo-beta-i686-pc-windows-gnu.tar.gz": "973eabda91963d58a9cdd1491bcea15834874fbca018287fb7f5c8bdcdf323d1",
+    "dist/2021-10-22/cargo-beta-i686-pc-windows-gnu.tar.xz": "cbbc14d1ef0e4579167fce4a5fac43b22c87882049a3d0edfbace9fc5c103ad3",
+    "dist/2021-10-22/cargo-beta-i686-pc-windows-msvc.tar.gz": "ef090943f6c90bb3327225e0256e73762ca2f73ae5d0d07b2c828709077e1132",
+    "dist/2021-10-22/cargo-beta-i686-pc-windows-msvc.tar.xz": "42708683ba5ad855880ec69d92192bd9f99ebf102beaf6c53680cb8733fba9e7",
+    "dist/2021-10-22/cargo-beta-i686-unknown-linux-gnu.tar.gz": "b6c260ba19734482439bf6d12b8e87e82f269f1bec447ec85e59372ef6489eec",
+    "dist/2021-10-22/cargo-beta-i686-unknown-linux-gnu.tar.xz": "fb6036ff910d075fb5e483000af641328e6d7d01c33255c099ed1b0302239918",
+    "dist/2021-10-22/cargo-beta-mips-unknown-linux-gnu.tar.gz": "71e4e5fcf055251089ac0d37b5ad873eaee6aa0380438cd68f140a16d3a37cd1",
+    "dist/2021-10-22/cargo-beta-mips-unknown-linux-gnu.tar.xz": "b89acabf106b10c5c3421574bea83d8baf1f29d040c40d5522f85e2e6afa6373",
+    "dist/2021-10-22/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "f544ea08d2f6086dc49c4d635116f3b4b804e5b68251e5fad433d538ae5e8226",
+    "dist/2021-10-22/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "54b0cbb4292cc4733a704017775e5cd4a9be34d53a4c666d6fc556472b508e1c",
+    "dist/2021-10-22/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "5e81253ec483f096e23ed98f939220b029814c041b4b72b93e994cead3dc4f4c",
+    "dist/2021-10-22/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "1a66beee5ccfd8b0fb4de52bccd11a0057248ac7fe8daf4f4d6fe0c0088044ea",
+    "dist/2021-10-22/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "2a6cc2e98ed575df64661595b6e1ec2814ed79fb63fe697c0201193eb52d70e0",
+    "dist/2021-10-22/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "ab3f70ea6977306c26c9cc368d64a116716f9ac6ad1a55eed23ddac894e7717b",
+    "dist/2021-10-22/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "ddd840c0c19077b4b45dc85920a2b2a37f176795b3d9390f1faccd44aa3d55e5",
+    "dist/2021-10-22/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "f5c9f1df082a7c48a63e786e5104d31e616c31d47514e9233b4a86d24700159c",
+    "dist/2021-10-22/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "4d39fac4d45dd73221b93b1d1351988ab4bf07ab04187a815467ab9b992f9490",
+    "dist/2021-10-22/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "3b6b0d38a3644028ca76347d5b82da6bac6e761a235516bf5b321d12ba909519",
+    "dist/2021-10-22/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0d5992a6e66207e4ead98d5bd627c181a052775f03ebdd2a0313574092a12abc",
+    "dist/2021-10-22/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "217940928d5c22553f910f3abf7b56bc832ddcd36282cb85c4b8142f9411147f",
+    "dist/2021-10-22/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "67ce7cb12cbd06e114a2f5dedd1d94c844f091ab05a764579dccf30e6158ea46",
+    "dist/2021-10-22/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "2cb17c66bdfcfeb567bb021c25c33a8c2b8df1366601d09fd9332278517a2f4c",
+    "dist/2021-10-22/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "e25a7fa310019a3457b317c9e3fe052602c82a25939c2ea8c012ff6016c622d9",
+    "dist/2021-10-22/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "1722ef69ea949c365f6b64735ee31dc92082db1177b94f0086b8aca790378398",
+    "dist/2021-10-22/cargo-beta-x86_64-apple-darwin.tar.gz": "f171fb45017640db15d437198b25758c49649b64338118501905f48ce957b93f",
+    "dist/2021-10-22/cargo-beta-x86_64-apple-darwin.tar.xz": "59c5f8ce9fa9dbf3e96dd8a38a52b8bff0ff0d97c081b1d343a654257df1e500",
+    "dist/2021-10-22/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "4f219f3661a03330b33d33cebadd5eac759968e1c4c3449f0f27433e715ab55e",
+    "dist/2021-10-22/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "5aed2d9631a2aa3fe016ae5e2ee312aa5357ce470c26c01171d14a159af7750c",
+    "dist/2021-10-22/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "c9dfb9c486cedac794cab6ac524805c10d2853c15416f3037ff4a5098514427a",
+    "dist/2021-10-22/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "a1e0aca8a32700e62fbc73b17dbb0be711db4e9caf535440b08bb1465d6a9c9c",
+    "dist/2021-10-22/cargo-beta-x86_64-unknown-freebsd.tar.gz": "61c041ba51632c029d916f274ed8ff92f1f7b23b5e9641591828e6251e205f6b",
+    "dist/2021-10-22/cargo-beta-x86_64-unknown-freebsd.tar.xz": "b61464e9e1c2e820a237f1f3d91cae8b0e62cda16dea51b32a8cf695b7a5707c",
+    "dist/2021-10-22/cargo-beta-x86_64-unknown-illumos.tar.gz": "1f9b7e500b22c34fa3080e4a15397a3a3827797c237d21459841055b5cb6cbaa",
+    "dist/2021-10-22/cargo-beta-x86_64-unknown-illumos.tar.xz": "97aba07cede4a9228ff1b937b8e884b23e9e246afe39b9d68896e6b4a346d972",
+    "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "c82bf6a11f468ba1d865a3cdc036b03f01e63a23272512583afa9dd9bbf95824",
+    "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "2efde3ef57e877f7a0aaba264ec14bc94d0cf3e4451b072c004c37e3f86288a9",
+    "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "17df9a194a8cd80871981fbde5fc333794e36a4ab219aafa7849ffeaf07d95c1",
+    "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "54fd84ff5bdf3221b151945ceacd71f51e71898927fe4b57887a0eba5d3e3676",
+    "dist/2021-10-22/cargo-beta-x86_64-unknown-netbsd.tar.gz": "0bd987dd970f98b297afbb7cf4906b1d2045ad09df929e8ebd291125e3c36126",
+    "dist/2021-10-22/cargo-beta-x86_64-unknown-netbsd.tar.xz": "054af5ef3148902a8fe07c2c445ea98a526f63203c13b849ba464d17145afe07",
+    "dist/2021-10-22/rust-std-beta-aarch64-apple-darwin.tar.gz": "2228315b5b7280a7ea9b3acfdfa1a8f0921391f67d792f32f53c1b303565a20b",
+    "dist/2021-10-22/rust-std-beta-aarch64-apple-darwin.tar.xz": "777d4c1c6bd3430771280dad79aaa16a6903901875529391e4779f0c2fadb0d8",
+    "dist/2021-10-22/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "1d2a74d8ff44feae6551613c182a87d078c0d4cc8f5117c6a3763f28d0af306e",
+    "dist/2021-10-22/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "67ab7519c7182a582fbd3e477b8bbbcba143a76e442cef94a47f0a03fa36ed05",
+    "dist/2021-10-22/rust-std-beta-aarch64-apple-ios.tar.gz": "2c2a8ca955cc99e86823bf7ede5492b04ea28c182a94d0f59b0d542f10128e88",
+    "dist/2021-10-22/rust-std-beta-aarch64-apple-ios.tar.xz": "bfd421654ad72aaff2610a104d0ea2afec579803ed16ac70ab594067cac292aa",
+    "dist/2021-10-22/rust-std-beta-aarch64-fuchsia.tar.gz": "b06020ac4aa9b5236d1888a59e2dc3519ac63c760ed0ef47b706466df437d5ba",
+    "dist/2021-10-22/rust-std-beta-aarch64-fuchsia.tar.xz": "92ffbe22d8fe9474aef42cd3bbe4808c4afa212a3f65f07828b39848dc03a1f9",
+    "dist/2021-10-22/rust-std-beta-aarch64-linux-android.tar.gz": "55aa7b2b3b79aba674bfc496efba37400086e192e6c7fa8483f5501ba31e68a8",
+    "dist/2021-10-22/rust-std-beta-aarch64-linux-android.tar.xz": "6219a156e46b7056a9046ab5a58af1a5386024b2961528a54fe6b1c3ec09a91f",
+    "dist/2021-10-22/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "f43fecdf75ac81f8b18ba5ec59625ce93b0debd27c0016edd76d5058e8182118",
+    "dist/2021-10-22/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "a032b56685b2b8431068565d652e5a174dbc9febe6de96945c037b96359d5cfe",
+    "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "bdb7d197cc36c774fe4d59a1c86b46325e93d82462c1cbe87e8ab415aba78e4c",
+    "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "061cb27b6d5b8e416457137334969733cd0727afe75d63d7954ccf547b7edc51",
+    "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "895d936a579c9642efcfdca400662264b8ba84ab9130f88e4dcd11c968a81e4d",
+    "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "29f3aa4005c64fa28f99af20221956ad21aff4a37c5cab9723959ddebb3c2b9d",
+    "dist/2021-10-22/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "b1e326b0ab30a2f9172a55272926cfa62dca9fbc2c590579f6c7685b8b4ad789",
+    "dist/2021-10-22/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "616fa68272334400c9110cf5a2cbd7d5c6e462cef8d2c5bc443c3ef6e9843e3b",
+    "dist/2021-10-22/rust-std-beta-aarch64-unknown-none.tar.gz": "ec7d513787434a3cf2d523dcff7e37c28cff4b09b13be93c024729cbbbb5aa83",
+    "dist/2021-10-22/rust-std-beta-aarch64-unknown-none.tar.xz": "5a396cc0499690193879d10da333f5a3acc6586f1c216f751a1e62bf1a8b6618",
+    "dist/2021-10-22/rust-std-beta-arm-linux-androideabi.tar.gz": "f9baf9d74b094cabdab59c1eaaf5238caa175e7865c3497c34eba68be5b2d756",
+    "dist/2021-10-22/rust-std-beta-arm-linux-androideabi.tar.xz": "0c5f14f311e29233057ea466123ef9c33e3fffdc798358f0f339ce3869ffe9e4",
+    "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "e3c2ffd3d69ba9035048fad22103989ec97b892de955a94015e16578e42481e9",
+    "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "3e716d6aab270f764233f50a25a33d37a6d34c2dea23b3cd1aa5733c72c13958",
+    "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "65b74540b47fcf7fc8a88cbc5cfe54ad67c1060722c37af7e31bebe2b3c204ed",
+    "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "4bf4f75f7c4ed171ef7705764f71eb899763205a9a4727343b96cb209691a97c",
+    "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "be073a69a1e9de0f87511a5a8b3454b3a2d24319571c25f347f7213c872a54bf",
+    "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "57be5edb2c00745235dc486b4e6e6f0e6b40edf16481405abe3ac360190040e1",
+    "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "53c39c89d7b19e45e1a4f32b07eac8214a7d5d277a83e4a88d7ab8820bf2de86",
+    "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "b9f058907117e3f1921fb5ee73e04c6114154870067dc8791382f3099aeb5c0a",
+    "dist/2021-10-22/rust-std-beta-armebv7r-none-eabi.tar.gz": "bc3d93dd7381749a7d24eb904c7fa74aa6e2a575ad1af5ef7e34ffa07e91105e",
+    "dist/2021-10-22/rust-std-beta-armebv7r-none-eabi.tar.xz": "b605ced5cb597a2973417f4de55fb39cfe12b1209c4249ced9232091395d8e91",
+    "dist/2021-10-22/rust-std-beta-armebv7r-none-eabihf.tar.gz": "315432af4541ceabb14891da9ab6af6717bba88f1caaf216053f75405ff8997f",
+    "dist/2021-10-22/rust-std-beta-armebv7r-none-eabihf.tar.xz": "aa643ea7978ea7911e50ab65ba0af7bf018a4bf9ded1da8e161ee7ab13decbfa",
+    "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "3f780d36c780b1379fde18fbcd6a1f75efa766b56a4aa6933c9bb88dcd4f4ba8",
+    "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "d0c87b4127f10c85368254377013053747c10d2d7dafae2f5643a3526f938f48",
+    "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "fb4a610676f9102dd206a1762be6bf7838b3eb0fa08629df8199573246bfc38e",
+    "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "192d9bf1354737dc576bfdcc310c936e065039f39303370008dd0fe3d3e8ec65",
+    "dist/2021-10-22/rust-std-beta-armv7-linux-androideabi.tar.gz": "5dd746bb8db14ca9f968a651f3ae7e3c3c5a505800c0c3da8f6469809a81230a",
+    "dist/2021-10-22/rust-std-beta-armv7-linux-androideabi.tar.xz": "2cd651fad1f2820a2bb9b828faf292d3029ce633d24283d9a5363a726a024044",
+    "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "06f337db74903b607d09151f8a5178ce48e8b5905af407ae9b37445fe78aeed0",
+    "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "8851247487823bbee990937a1f83578d910985ed4055fe3bf339871a7aa28bce",
+    "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "5696a2c0fc2c3141d43f2d97d8e4959310032756cbdf0140dde28a5843b431e8",
+    "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "d8f9a3669d550f1c6f338d99ea74f4e48771620d4125bbd408cc750a70ee4686",
+    "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "326e4ac48ef1e1a60c434699b5fb09b9d0581e020bb745196011f2f61af41a13",
+    "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "cbd10db975412fe275d12b81cdfd5e97c0b464194639dcc439cd72a65790d601",
+    "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "977c9e94e25fa9a1db5f93ec800d529d80d874ceb2ed3a10bff63639fd24da59",
+    "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "0729470e2138e90d9140e30779d7397e58ebfc1ec243e55caf90ab12ef904da4",
+    "dist/2021-10-22/rust-std-beta-armv7a-none-eabi.tar.gz": "3115e3b7f0981dba799902b212f350608042a2beff3bc3b32e930e9c9c3cca17",
+    "dist/2021-10-22/rust-std-beta-armv7a-none-eabi.tar.xz": "75b3d8eba51877916129d8dec07bc86ec6e88076af79cc221e8543695e64da63",
+    "dist/2021-10-22/rust-std-beta-armv7r-none-eabi.tar.gz": "9787d23a7078c94b4ac33d34cdfb68da586d777f020a6284bb1540b54069f476",
+    "dist/2021-10-22/rust-std-beta-armv7r-none-eabi.tar.xz": "c8f9b933b2e9c955e6bbcb141082f6b5833f89f34de16e14f54e8d4aac02c473",
+    "dist/2021-10-22/rust-std-beta-armv7r-none-eabihf.tar.gz": "ce9ea3ade0886bf7ea40a1066981d172d915aff4c54ca325d72ed823c7e17787",
+    "dist/2021-10-22/rust-std-beta-armv7r-none-eabihf.tar.xz": "2d2442ed2ac017777d3fab1a3f69a578a9db1139fa1aa63dc87113071f08a6f8",
+    "dist/2021-10-22/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "98258ea791d398c6a29e1ebe28557aceb59ac228a0bb1332bdbd9f702c61a4bd",
+    "dist/2021-10-22/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "a4172c8c2b719d0391654968377fdba932343e444bc78482f19f731ca45806ca",
+    "dist/2021-10-22/rust-std-beta-i586-pc-windows-msvc.tar.gz": "2221360e32bdbbdbf073a4bc1fbbb98b86bd0a1df526cb8dd05dd521ea402c7a",
+    "dist/2021-10-22/rust-std-beta-i586-pc-windows-msvc.tar.xz": "03c53e31762e5ccc58d1296a8fcee123592dc6d3b88d0c81ed1f8305545faca1",
+    "dist/2021-10-22/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "612eb9bc2a06779ec05f6033f44b18f283d6cc8dccac0d5c81a6d09f515fc077",
+    "dist/2021-10-22/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "70ad4e52227ae069a9e99cf53e07470267abf1f2ae0398192ac854cfd31d50d9",
+    "dist/2021-10-22/rust-std-beta-i586-unknown-linux-musl.tar.gz": "8a5dd3dd62cb31c77aec2e00847812ba53e951fb284c74671cf3875b18a015eb",
+    "dist/2021-10-22/rust-std-beta-i586-unknown-linux-musl.tar.xz": "10650efcfda713c2a3053a9c505847dd021bed19b1e3af12d58742deb76cb421",
+    "dist/2021-10-22/rust-std-beta-i686-linux-android.tar.gz": "6fb4f4ac2b448bebade72ba2080bdcf579b6a40041b311301452ee41ea267ea1",
+    "dist/2021-10-22/rust-std-beta-i686-linux-android.tar.xz": "6e0e8feb477ad35bab1ef599f51f64b4720dc37194dd6354a7a4bfdbacbf2c82",
+    "dist/2021-10-22/rust-std-beta-i686-pc-windows-gnu.tar.gz": "0b0c0e86be0fb63dd56b419f0b8d05eb59841649120e16a8216bbe490a76db1c",
+    "dist/2021-10-22/rust-std-beta-i686-pc-windows-gnu.tar.xz": "c54a116404d31591d6a6a1a332e4bb8ee177ea7a0367b11eef6a8cae6c1c0325",
+    "dist/2021-10-22/rust-std-beta-i686-pc-windows-msvc.tar.gz": "14313eb7b20a3a3739a28406b1544cfe421c593a3198b081956a1a54387cd0b8",
+    "dist/2021-10-22/rust-std-beta-i686-pc-windows-msvc.tar.xz": "54fb4abc77fb6c97929641095ef86e559a4cb116cdac7dc4bf34a81aafa03681",
+    "dist/2021-10-22/rust-std-beta-i686-unknown-freebsd.tar.gz": "9a2a5b2d3d5cd98cb3f9a43fc34d3dd0dcdf9bd104798380f70373440edaefa4",
+    "dist/2021-10-22/rust-std-beta-i686-unknown-freebsd.tar.xz": "d0165b16890da11196a1e4cd6b48d545f44ddb996ba9515a919ecad85cddaceb",
+    "dist/2021-10-22/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "a42e125c252eed17664a50713d5e2f0c43f0f9ffe54e471500db75352d1e2147",
+    "dist/2021-10-22/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "705185a2b4b98f6ac16a9106af60f30618c24d6d93ffb0283a41cd31f992750e",
+    "dist/2021-10-22/rust-std-beta-i686-unknown-linux-musl.tar.gz": "1a01712d4b8b470548c22a24e7e9524c0ddacfcf15459b490531e68e62b8a400",
+    "dist/2021-10-22/rust-std-beta-i686-unknown-linux-musl.tar.xz": "a86f8080ea25267f7e127f23bb75538cc3032091061b1fc3ce95c917d2a1cc92",
+    "dist/2021-10-22/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "d6d06becfaa6a4b0cb7131fbadd6cc6ff58edfa11fc6d98e69d2cf5388e8bdef",
+    "dist/2021-10-22/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "65bafaa34e506e8bab15d2442742fc075dab2ea8687c69f6090acf0204b6fb06",
+    "dist/2021-10-22/rust-std-beta-mips-unknown-linux-musl.tar.gz": "53a48c17c4ed3740049d0c88b14d2a1189e7ef5fa08a926c8ca26ec5b2b298b8",
+    "dist/2021-10-22/rust-std-beta-mips-unknown-linux-musl.tar.xz": "14525b83b69fc54d4c808ffb69e06f015850ea9186837c670dcc23b5bc66d4bd",
+    "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "1b8f11cb2ab076f00cd601c1465ff3a2e3857cdec255c8ecc1697efa713f5626",
+    "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "31e824a6243a6e15ea96a2984c69711e312eefa5214ba349ef6d6a4c42fffffa",
+    "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "89178cf43cfbffea696390c317230d39108e529803e28ca60d37b6167e589dbd",
+    "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "8b9fc0f9a2297d15abc86db95ac8768e872ec1acd21461e599a1aacb80f4b182",
+    "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "13ec0039303d3df358ccfa4fc19924df0ce17b31e8f57b13e7367db68bb9dfe8",
+    "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "1266340a228c8cd657d0ee7ef257d80a33b193c4ecb742cdb82d469772311499",
+    "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "b100adc79e776116a267bc918ded30c4c8d27d83ed21f65f9428ed8831d101b6",
+    "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "6966af76ccf83f37657efc4aff88887de81642dddc3f2ef59dcaa91219d4f674",
+    "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "0b7a859f952741a740458609cd207d5f7291c054fc6d9a0191d3acf0f216bd17",
+    "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "2e6e61f68fc3772a6c3b3f0b3be6d99bca1a57b5f568e87397765cf6fe867dd1",
+    "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "881946b261399e50992beb3cc613ca2141736a7480103fa1fb117c1e7df2b1db",
+    "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "223a78a4c5055ca00a7d5b40491aef9498a204759cb388e734408e305999713b",
+    "dist/2021-10-22/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "76d81922eb6f61d33c10f2754ccc9b1394ae09feee5818b23b62f768f0e6a370",
+    "dist/2021-10-22/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "be57410669ba5a516dc935fd1eaa73b2d0d3d237a2eb184a8dadce919bf1975f",
+    "dist/2021-10-22/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "cebf48de57e57285c91092abc01ab1fd9bc7eb660eaad3db2ce71877bd6b9352",
+    "dist/2021-10-22/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "30a8fc47441c4f7b34f540f5132b3d7ff9756e8906ac6e2b9df5ea8fb622ad65",
+    "dist/2021-10-22/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "7deb058683792cd3fcab92b950f653a4ba0d2a2997bef508c6d1d04be319f057",
+    "dist/2021-10-22/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "c5d26bbe5b6c64ce9cae78465d22faa98ef956dc4d8bacc91a127a7f439f7b11",
+    "dist/2021-10-22/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "bf06959a991270e9e15d538e70d078a5241b6e87d62a55a655e4c2f9e8ea2964",
+    "dist/2021-10-22/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d85b330532cb6743071ffa117fbe8bc26b9c6167a0ff76c0ba32fb17c0247c70",
+    "dist/2021-10-22/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "7dda5e010ddb4afd6e6efeb9f43ef17cb30af7ed9f172b59e6c737b2f9d66ef8",
+    "dist/2021-10-22/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "35d8feb28897bead99c17d952b711888f2f6f613fef767f28e3593fb4aa2dc36",
+    "dist/2021-10-22/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "2e7067692c10447d50df8e9871f95b4ea925a88c5792f973b3c51325afaa8457",
+    "dist/2021-10-22/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "4b2d3bc61727c87f7c2ba129e9147621c3e3efd542feba3acb6596ea91d10d71",
+    "dist/2021-10-22/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "093aa10e425beef7d66e9986b045543b3dc04c296fa3b3fdd9071fd6d61b269b",
+    "dist/2021-10-22/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "8f3512c368b7c44c7d8ec9e1dbdbaed344859ebe2d0dcee22118397d41b841b3",
+    "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "adab0b58b93d37949eb35d4a6f3ba9e6b43630e4a82f1d9047116f1462cd1809",
+    "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "6a0410d1194ec0c471e384c5d02aba555efbd47b36a3544c56674fc2080c51e7",
+    "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "19c8be8430ab59b92006e0bccf186687569ca172b54f934ff4763da20cebdb58",
+    "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "6cb9647a504683fa5c67e5ab2e737bf1d6004dd4a7ffbaf593dea0f9844ced6f",
+    "dist/2021-10-22/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "cc2d94e753035ff0b49490173b042d21f1ea58711f7c6ce5cfdfd79a76e539b1",
+    "dist/2021-10-22/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "de398391e577f2fa09f369fbea4114c6cc0f1412884c6f52c97d71c74920462b",
+    "dist/2021-10-22/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "feefd67b9c9dceee7ef7947753ebd990a914d7a54562b718e6704d35a1f5c75f",
+    "dist/2021-10-22/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "1b550a911a51514f8d69b9b763cc3379cd674615090652a253eeb7b585d2d97d",
+    "dist/2021-10-22/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "4d7d78589d6d72e5ce60d6997394c4d7ff03fd2bae471ef3334f1d5bff9f18d7",
+    "dist/2021-10-22/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "ec499330b2f63047eb43bf98b1e66d301d7ea7015447c83307ab528421387502",
+    "dist/2021-10-22/rust-std-beta-sparcv9-sun-solaris.tar.gz": "7e48f11954d44dade640c86cc87d5841ebd708643cd5220ae7d07127f71ff333",
+    "dist/2021-10-22/rust-std-beta-sparcv9-sun-solaris.tar.xz": "5038770dbb2dda71d32c4270653fd3ece96062b24ad55dc8def6475e464210df",
+    "dist/2021-10-22/rust-std-beta-thumbv6m-none-eabi.tar.gz": "b8b9a59bf1a9127b26aff54dde3a1da9992a99fd3d601be7cc1daa6ce3c7b6e4",
+    "dist/2021-10-22/rust-std-beta-thumbv6m-none-eabi.tar.xz": "e0a96a8b105466a3279da3d9bf589724def7326448bc6f51ae6f8e8aee2ac880",
+    "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabi.tar.gz": "cc3a8d935ae2101cff8af86fb066c09672f9fd0297cd9d6b960c9f4877618e98",
+    "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabi.tar.xz": "9bafbfbcb01e23f58b1adc7fab26e8ebd135c5c20589887278065f75cb5b5350",
+    "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "8dd7c2cbc2c24e5220ff6a7f5caffcca6605f3d76ff66f766af00ba4bb316067",
+    "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "963a698d49c8742ec5c7520fdefa1668db573eb01bd7774f80133496122b0517",
+    "dist/2021-10-22/rust-std-beta-thumbv7m-none-eabi.tar.gz": "3a01a35a10f0efe48cef64d45e80fccab31df8287f500bf280b5d9bd5784ea3a",
+    "dist/2021-10-22/rust-std-beta-thumbv7m-none-eabi.tar.xz": "84a5b9d9cc21a13cf1e2e1c29e7af63c75690cbb2293c63fe95e075ebf59815d",
+    "dist/2021-10-22/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "946e96f404b8a9f4c8139e90172ea26f3a6c509effc6e1ff16a49dc9ff6cc1e4",
+    "dist/2021-10-22/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "787cd874aeb33e4a4fed2726a571d39f6687da20625aa9a485a95d7167b321b5",
+    "dist/2021-10-22/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "70fd17c069fe4b6a318d887794c54a142275cc65f088a7bcbda5bbbd7c9d6aa7",
+    "dist/2021-10-22/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "15ce829bd9ea0a1ee918e7887392ce1e74e00b23509b802f5f45550176d78768",
+    "dist/2021-10-22/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "2edc66ee89c319ef7c9520c5203185a5b5203ca4ea9996e0142075273ccf84b6",
+    "dist/2021-10-22/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "3c129a2557639fad501c7f1474f45535a55c33813a889f08521f4a7d527010ab",
+    "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "354e644c51ad5863bb0eea09e0c5d1aa32858e7025c039d693e2e433e1c18c04",
+    "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "6996a329a81624537d45b2401b8dba81911e5c61d2fff6bcd63c5fb15b2fbec3",
+    "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "97d6aa47e209650860e97d442f7ec5c5da385399aa5f06bca4c7f9a08767026d",
+    "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "dac5cadd67e5d162e00861ec5d2c96166fe1a80954237068aed6072afe0f728e",
+    "dist/2021-10-22/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "e0161120cb6cefb23514c839eb2be13a54139d4f408563bd9dc1d6b9d665496a",
+    "dist/2021-10-22/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "94bcd63f3712cb3b09948ed62c8db889e2bc78b97d868c89386f912d0daa1b4d",
+    "dist/2021-10-22/rust-std-beta-wasm32-unknown-unknown.tar.gz": "00a37ebbf36bd66ab6e0b957e93c7a2e5c2d8567583c65873abc1c79b37bbabf",
+    "dist/2021-10-22/rust-std-beta-wasm32-unknown-unknown.tar.xz": "75589caa1835ee12362a2ad581828c9faf0d527f48d5a07c1d7f0b810e035def",
+    "dist/2021-10-22/rust-std-beta-wasm32-wasi.tar.gz": "2276b9ef2ff2faa665f15d3572abe0d13a5bb9ec0ad08a6a0c00d9e143464993",
+    "dist/2021-10-22/rust-std-beta-wasm32-wasi.tar.xz": "fa132a08849d7c583dbf37db97f3702c263b17de595823d87fa14e56ff21ef3c",
+    "dist/2021-10-22/rust-std-beta-x86_64-apple-darwin.tar.gz": "47454a419e6a87b057047c002932cd2f0f52a77ed4c3b4e4d9b65cc4f4ddaaf4",
+    "dist/2021-10-22/rust-std-beta-x86_64-apple-darwin.tar.xz": "f9040fa310d122651461d026f43873aa18d5f2c63a9f3bdd47f9a034e4153348",
+    "dist/2021-10-22/rust-std-beta-x86_64-apple-ios.tar.gz": "e143c4c8d394810c7734824476dbbfb2a73b3b62cb8a708f796e0c0332deede9",
+    "dist/2021-10-22/rust-std-beta-x86_64-apple-ios.tar.xz": "53c660ef68e1898574f62725c2f50fc2f26539143c0be0675327a33511142f8f",
+    "dist/2021-10-22/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "e419db2f8f12467335c8571902f1ed163a5407394914f55416fe948525140ec5",
+    "dist/2021-10-22/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "efd2b6df7dd439b0ae0312831afd4517cf19adf619916eeda1f571daf1dae723",
+    "dist/2021-10-22/rust-std-beta-x86_64-fuchsia.tar.gz": "e669378ed5da5948dbe232323ef3926f37ad430feb8c398259229fd18675de20",
+    "dist/2021-10-22/rust-std-beta-x86_64-fuchsia.tar.xz": "5a26a35164ae44467d256e6fab0e8f45731e8840204635ac9b1dd1d7d8f96810",
+    "dist/2021-10-22/rust-std-beta-x86_64-linux-android.tar.gz": "0d922ff7d7658c296246c22f4440a8975c8036f7159508e2fa964d1f2ad3aebb",
+    "dist/2021-10-22/rust-std-beta-x86_64-linux-android.tar.xz": "d775ecb6054216f0f48dbd0acb7710fc097ef6d61df9c1f59139721ada7bef8a",
+    "dist/2021-10-22/rust-std-beta-x86_64-pc-solaris.tar.gz": "1e830dc490e9b00b86c9d55c974feefdd87efc06c1bb90088b41737151987dce",
+    "dist/2021-10-22/rust-std-beta-x86_64-pc-solaris.tar.xz": "cb37a89a871d61849f9aa262bee7248813a8c7a422872aa3926f20c1adf4ec63",
+    "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "d83a17c374e937b9a06a364d0be980f4dc953df01efccdb3a0bf853ffd889718",
+    "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "94fb51d1db6482adf683b9953fcc942923fa5c85cbb63f7b05ad19c24272a21e",
+    "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "4b7cc0a0a6b07054bb1da0b75d5f687fb38653a7b31f7610f5a90a402839e481",
+    "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "267f634ec4e08d0a76a75ec0f4ae037aaba44db3ac2969ed3f34d74db43bea1a",
+    "dist/2021-10-22/rust-std-beta-x86_64-sun-solaris.tar.gz": "3648f1129895e89467a569219570061a6c50937d87bbb407e6b3b6b1f488bac3",
+    "dist/2021-10-22/rust-std-beta-x86_64-sun-solaris.tar.xz": "3a7d686102d9f2469e180a80679db52b6c8dc8ca35adf3e50a25b7bd35f4c6a5",
+    "dist/2021-10-22/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "6cb296c0d9e07e00b8561c2f39a7dad9c9d74e224658fa9a7039e34d4b5f3aa7",
+    "dist/2021-10-22/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "9e951fec5ee4a4a655693d1c9e205413aeb3120a7b2c0bb6673f4392cdf9fa6d",
+    "dist/2021-10-22/rust-std-beta-x86_64-unknown-illumos.tar.gz": "35b6775e13b79b946398a65d6cd4f15d26e160dbf44718cf177679964b2f3cec",
+    "dist/2021-10-22/rust-std-beta-x86_64-unknown-illumos.tar.xz": "84d127ce90d62f1698a948ffb247cba400bd162b9864d2ca7c0240a46b23c88b",
+    "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "53a627ff89fbfd2abe9b4354e25e02d2ae8d05fcf6f6cefe99b84aec9775acd0",
+    "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "7692b0b44eea139874fb8c6cbaca46b8f156ce392454ee4891daad532a5c6baa",
+    "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "853db076a2c469e37003fc8e52af2d0a2e31cd7f74c51147f00b04532df5721e",
+    "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "6925429b5f25d0454abbd68ee333623ccec9d706fe0ec528fb619b2688528770",
+    "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "13e920a779485d04952e4c402b42fac9b7570098e5e32394996cd985889682fc",
+    "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "158062a56de043afc4acefc8eafaa536c3018cbdc7696b6d909c757050062b42",
+    "dist/2021-10-22/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "1701a13827b3ab22fe78569704d39a2f699f463b2f6f159407a39eaf4c7fd6d8",
+    "dist/2021-10-22/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "f10ff1def90cb101179f11b4b07ceeec0ae26ee15c7a85f80e4e31c61baf846c",
+    "dist/2021-10-22/rust-std-beta-x86_64-unknown-redox.tar.gz": "20c6c718322cc341f0e1f69a9dc42f3146d10f32075d32376a241a90a2e40f48",
+    "dist/2021-10-22/rust-std-beta-x86_64-unknown-redox.tar.xz": "d0429de3b0391f063836c765ad17e2fd1940f737b69961f501eb9d2573cba6e5",
+    "dist/2021-10-22/rustc-beta-aarch64-apple-darwin.tar.gz": "31d16857f6fec033e6f79121040eb025c28a1d049014c6047fbf1057450f86d6",
+    "dist/2021-10-22/rustc-beta-aarch64-apple-darwin.tar.xz": "997a9aa6db5e23f476aefd3f4799f986a51fda3e31e2b293309fb65fa92b0370",
+    "dist/2021-10-22/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "73fb943292d50a372f2df490e47235f395ff7eceac353be74fde3adcf45d363f",
+    "dist/2021-10-22/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "30a4a4cbe3fb683b8e846052a83a3185d1b8d714251bd6ad0bfc251b49a72121",
+    "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "b238cffde0b9ae2305e501970cb9cff1782331f1cccbf8dff84979d1ffdf0625",
+    "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "5d01b8e471419036703886fc7dcceb89ffc88fa62994727109865339fbe0c92c",
+    "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "8b8b48fc67a2093502baf21c372870bad42840377548e250023c9f83884322b5",
+    "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "a9e73e67a7120968474040dbde7b12668bd6e3a6b4f9d91b8c9a66474f68e40b",
+    "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "4e83419922b4f02b1c1c62ca14db65863f4226cbaa61674ac792e860c026a948",
+    "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "20d7369422ebb89f8e1064616a9842cbc98d9056910a2d0ba46f8bcf144cb794",
+    "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "05ab3071cdb3ea4e39f53e179c754d2cf64800ca1c38ff887e45f60294d6e222",
+    "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "e8509c60955ecf4938575a7a40091ba5d7aff77c9c3e24208623882d1bb45e6f",
+    "dist/2021-10-22/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "185a3e399dcc67d8fb43a0174ef8e15c36a068b82aa33db8b42c948c2ee15689",
+    "dist/2021-10-22/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "69be7881ba1b2d4348ea06fc2d31a62fe484843e660f399349c49a17852cfaa7",
+    "dist/2021-10-22/rustc-beta-i686-pc-windows-gnu.tar.gz": "74c3a25a67b10abbefadf63bc09f6069242267a9ca8a9177e2f46e2b29869b75",
+    "dist/2021-10-22/rustc-beta-i686-pc-windows-gnu.tar.xz": "9f0d3ce0a00b33bb591d6b615f9cc80a714f3ea0d787f410da7d643ac5e1144a",
+    "dist/2021-10-22/rustc-beta-i686-pc-windows-msvc.tar.gz": "feac518beb813b2d553d6ee1ce03daf890c956918f0de69d5f59d4067f2f60d3",
+    "dist/2021-10-22/rustc-beta-i686-pc-windows-msvc.tar.xz": "aad640ae5e48f489148e1edf5e815a78b19288d916615e2af8805f0023e15686",
+    "dist/2021-10-22/rustc-beta-i686-unknown-linux-gnu.tar.gz": "c5996c458e6e1a3f3dbcb70debe562bb5d0f4a6eadd97932d8935209fbbe6809",
+    "dist/2021-10-22/rustc-beta-i686-unknown-linux-gnu.tar.xz": "d5ed640d08bcf3770b80386282c442d79af38e4c7e73be9617d0ac72d553c507",
+    "dist/2021-10-22/rustc-beta-mips-unknown-linux-gnu.tar.gz": "aa0dd3e77f92c1cc21f550c59761a437d3a8ddf31b23040e8849dd116e209835",
+    "dist/2021-10-22/rustc-beta-mips-unknown-linux-gnu.tar.xz": "3c7bfcd663507730ad3d07024e1d884dee6adb49343bef0cfb8fd07b8a56c6e4",
+    "dist/2021-10-22/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "0370337cce565e6e363e6de59aaa8c2e17db49d79496086c20f00d80198635c8",
+    "dist/2021-10-22/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "30413f65a4fcafbbb6a5302cc65bc35edc549cded8ce6a32277ae9a499adfe59",
+    "dist/2021-10-22/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "0e6ee26e237a185a26068c2c69ef095ff37f24af7984bad91196ad253dae196b",
+    "dist/2021-10-22/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "f0185e074bb0c6811d244502ce93384cd7256840fbf64025e074d97e4ccb03a9",
+    "dist/2021-10-22/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "a2c1f733c16d62300adef3ed41f9c5926f704e6b3d47e98cc615665496aa4f17",
+    "dist/2021-10-22/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "3945ad08c0b296a700bfca778994fd93bd3cbe643517ba20a60aa1f9a88eb2cf",
+    "dist/2021-10-22/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "e3871e21ac938b4bf3a1ed44fed2f05fa3a27d3eb000d98876f9f220a5fe9175",
+    "dist/2021-10-22/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "bdc7cddaf0031af1b737fd0c2510ef018d68ebed914200ae8acbfd31ad38ad06",
+    "dist/2021-10-22/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "9ea42f7e50864bb514293461d3622096fd7a73e8f487578ba1425a3e8d26a970",
+    "dist/2021-10-22/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "c39cf38c563b16d303bc2cde8c67527e7d2a74e8c5375af73744d9a9e3dc5e1e",
+    "dist/2021-10-22/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "dee289bd99b3b573493160446f923fb2f2b66926a5a69c0a7704eb2aaaac3ea8",
+    "dist/2021-10-22/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "e3c89f1baa358b6a28ae567981d5efd457d2df61f2eeee19bceeac715793510b",
+    "dist/2021-10-22/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "748df03717e997a01a6d222bdb6d6c0b1e206d9be55b74c14c3374a333ad8d55",
+    "dist/2021-10-22/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "5cbef13c038d0fe822920eabf91c152a7130e50824fd203e3fffff4a44b10bcc",
+    "dist/2021-10-22/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "dd0ec4dba66712a10c3ee5e5ef1835210d8632766c17a4afa1ba0594b6fdd35c",
+    "dist/2021-10-22/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "30d736ad6f32019435613fec04b4474795c8915e878a528c46de453a25df1bd9",
+    "dist/2021-10-22/rustc-beta-x86_64-apple-darwin.tar.gz": "14c1ba057a56a0c34f129ebae29c6a9453faa03125f1fe88b564355c186d42bb",
+    "dist/2021-10-22/rustc-beta-x86_64-apple-darwin.tar.xz": "67d1c23c910e038c6238d286af0141f0a954799dc12a6b935d47239f4d2e8bd9",
+    "dist/2021-10-22/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "7685e5b408bf70aa4c8af5ce7b5e5d5a6ac7125c75e7b10a9b3dc0e2dbd4cca1",
+    "dist/2021-10-22/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "a52b846d34cfaeddb57d00d0209b1829fb129049ef61212937c0f19fff5efc91",
+    "dist/2021-10-22/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "a5c2dce3211ec671959abb8b2f7fc34b572e3bd44362c61b98e0850c0530d1bb",
+    "dist/2021-10-22/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "ba948c4a665c349732de9f8faddc2f7e0f7be5995ad88af44f8f4f5ffd4b9387",
+    "dist/2021-10-22/rustc-beta-x86_64-unknown-freebsd.tar.gz": "edf7d1c9c9288cca973a0bc3a90bf005d25df324c592b0b8d051f0de98b85f78",
+    "dist/2021-10-22/rustc-beta-x86_64-unknown-freebsd.tar.xz": "0c01b34ed39016866e945e0f01de830a68c54f7eef2ac83c3ab85318b01debb0",
+    "dist/2021-10-22/rustc-beta-x86_64-unknown-illumos.tar.gz": "6ddf6e92653ab0c00ec524e1274be3e644868cfa867933bc383e8e3e7674945f",
+    "dist/2021-10-22/rustc-beta-x86_64-unknown-illumos.tar.xz": "14353a439a306d0803d89a3ce3da5e5c91b9236ed84759fecf8b38ebe1d8a8b1",
+    "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "4d7feace1b414919ba2e682c748e24b31d811d7b54d710a7cf70e0b3c9c1a591",
+    "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "35593657a752a66f3052752c67c380e7ebace191a0be78c5def2cc3c1fb3a18a",
+    "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "04e752df5371b5d3879c8514b7dab27bcb35a7b8c7eaec0ec6e3ec5f51ff84a2",
+    "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "b0ef02ff310386b80a9b6113a6e44a437ab78b42480b4d0a86e828d97d92a3dc",
+    "dist/2021-10-22/rustc-beta-x86_64-unknown-netbsd.tar.gz": "387040cfbb92e6b2acc52067ab2184313de2588a6af65c0af003432bc9e69c75",
+    "dist/2021-10-22/rustc-beta-x86_64-unknown-netbsd.tar.xz": "a617e0ee647908038bd1b3f233b99db1a82b0f32875c9093cb66387f3b2bf430",
+    "dist/2021-10-23/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "5ef7d34a33925b7af081f2e135a0fd20ebb18f711372d432a570f8983243c93b",
+    "dist/2021-10-23/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "6003e9f8fb4b2a581e359e2e4f1bad83b9055d5a0c60fa0b752ef1aa15957f28",
+    "dist/2021-10-23/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "838f7773a9aaec82c4323d8412a441eb3db94da8384bc1a4a50969c5beea9aa8",
+    "dist/2021-10-23/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "403a2141367854a281302f9cdcc2d1b37a2415e8aca4cd5e5308af5fa254601d",
+    "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "6a3b69c8352c8262a37ba0104043a66bc579fb033166434a1b9eeaf115d8d1c2",
+    "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "f272195798b40df211b1d2e817e91bba68a1083026159cab4414ecc88ddb06f3",
+    "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "5ec04606fc7196f9a5cd130dc4c98e8df58994278ab50f7ea6baf2cdca957b07",
+    "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "a24513ffce8f76fa3334932268aed073958f904b1988d337df7bd4277d3a139b",
+    "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "8f078b404db9fabd8b0a45deb5110fab32e2ffe5f604f74ef787d9baf3f857ad",
+    "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "3569e3ed42cd9b4dd6f8b2838329c7864c6d3f7a5242cbdbcd9a756e6f2ca5ea",
+    "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "afa42b42631320a68d6a99902fd48b1e72d2daeb07a5be34b833f22ba6dcb67a",
+    "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "839a8576012332bb2ad01d5b4ab24d46af8644e38b3019b36c0ba5a9417bfd07",
+    "dist/2021-10-23/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "aa59c2ebf3bbff46b6c09aa1e7784ebf83dccd6df60e1295935ff3cc954fa755",
+    "dist/2021-10-23/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "e7f479891368cebb99f41b59508a3904321d600e20cc2507954f78386a448601",
+    "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "a971a861cc76d0a2a4c5fecfc4537c8e1c14f4d43013bceeed395722e8620cbd",
+    "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "5879a7a9af9c6ef6397f75e4b062527fee5006d655fac5b7538915b176d9faa8",
+    "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "dc66ac568c709f4b580b46d567bf2d79481566688e0ae55df1edd2a5f07fe0a9",
+    "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "a2ea4554d52b1181c589eefdf67c60bc0831f2e26430bd6e5e7bb4094db5dfc5",
+    "dist/2021-10-23/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "8d9ef4755d32e8dc480db1b130943f47b45cc2ba69b1e9fa3dfa128d63780b70",
+    "dist/2021-10-23/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "3cac0853da192779f4edc5bc3c913e4b93a02ae98b883cfe2717cc58329d7469",
+    "dist/2021-10-23/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "14c5197f4884f418a392bccce9ac3c9a09dcd0a710a337bba5959f5570c41e98",
+    "dist/2021-10-23/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "f9b14921e3a6bd006479a01579e6601787082ecc0ec8e631b8cea6a4f1c0b967",
+    "dist/2021-10-23/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "9f4efc8229a5a8561bea614a3df0da49349dc4118d72905ecd6feb6b6e1eba9f",
+    "dist/2021-10-23/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "02d829ac6d9013f7268e505aa2b0aa99db7e25ddc3d6555ca8f9a4c5ed3f01e7",
+    "dist/2021-10-23/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "8192413e5e376bf957a2caffe8ab15b3c235c714f8214a0f3a46711a79fe33c5",
+    "dist/2021-10-23/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "be155309daae3cb39dbbc874b2ddaebd1ad303b09f40e130ea8429cc7c9c366f",
+    "dist/2021-10-23/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "318c3e8235913f64c9e90b0e7c1fb50229caf59c02f0ddc702cf0728d54dc41c",
+    "dist/2021-10-23/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "50bf71e32ae2228142ad88d67e794ab00b632147fb554ebbfcda7ec79304ae2f",
+    "dist/2021-10-23/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "80f5b76c38d7300c5aa6a71a8b3325b28290b1bb936dd59287fa87d6dee044da",
+    "dist/2021-10-23/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "30a71791c6ed0cf3e0fb955fa697549dcd13d2c0f3e357d9723fa729c3a03698",
+    "dist/2021-10-23/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "7e5dc3dc89cb21638b452eb9b5c9f008803ee5845c973f2547f59db01b7a0100",
+    "dist/2021-10-23/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "e1a949b29d249361b306af38bba7118aa1931c14061b6fa7621027e9994b519f",
+    "dist/2021-10-23/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "ae4186e4faebc9ad8a13f06a97f96c48cbb35353ad649e25f2e80e519a9d272a",
+    "dist/2021-10-23/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "ca4466d872bb050cabce20ae04eb915ac3e39e4788899db7bec5b51ed7d5b579",
+    "dist/2021-10-23/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "0f39f27e2ee437df69975578c6e32b6e293bf3129f7e63bde83091330aaa496c",
+    "dist/2021-10-23/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "55700dff4b4f3f7d9dfee3317d984afe2b44681deb7b074441b41cfd59e497ed",
+    "dist/2021-10-23/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "6273db29aa2715ffe38593802c520adafcbb2300ed2595121bff628686eae675",
+    "dist/2021-10-23/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "7a4ce848a1083c16bc17bd22345427ba4c920cb887e90d612a8c3d1ddcf802ed",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "12a715fca796c192514157b43b0296d688cc46e9d81416a67a0019184c1703d4",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "9a651e94a0cdddef7c7a56e356e25d0f35d0c592b6a54f2cbeeb3364fc5d457c",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "2ea52a8413a43a10165322135064692faee0d03a453c4b28ddea480b153de5c8",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "843b06b9b21c56fe1749e8a5bda908dcc2b6d8206faabd04d050ce83f8c32b73",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "69210991cca5a07c0421254a2e18a29de28ab5019b490a576f7bb94496ca10b8",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "3f5a59ba68e004c06cb07ce83d4a567b77179e11071a8b5b8ab6fe3a70bdb872",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "7225fde4655ed5b4479ff9f4e61237a16280541f44aa751c5a06d5916e8fde3f",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "e844e80d99418bea9e7cf96cd389056d17f3be60e9412983d91c64e107a28b92",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "6c1b031bc408349c5d15bf494881dd75aa68df8e7417e6c72c061c7d3270cdf8",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "d24b970a15dfd41cb1b0027a4a5822e8c2b0217dd1984503d60a85fc6acf7414",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "5b5aec4bfde07863d2d5bb71f38d3459db0659df75f53567be6fbaacec33c7b3",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "851b9582bd2518a3e050127c46e59f7bb6b24d354c6e89a9b0fe4d3e09cfbbb9",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "758a05277e99d00e21ff9d8abf96a6da71350664a1eb85adbb1ad4cfa1934255",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "6431dabc8ef72ca252b257683fd2f5ce3c1347b18ff1d4b7ee7758c6906ba2af",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "51bdea94714c0892ca7020ddcc7c55bb20ac69eaf5152a38f83925d793b90eb1",
+    "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "660a23d1430164b01b3e1e8b50233be07fa0988d90e9880bb9044fe661537cde"
   }
 }
index d4a44b17392bea37ba5f45164de2eaf89e9812f4..5196aa9fa1759e3a0c9b0b051113fcb491d68a73 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // assembly-output: emit-asm
 // compile-flags: -O
 // compile-flags: --target aarch64-unknown-linux-gnu
index 42cef9bb67911e1e19915aac6b4c8cc1216d6310..c2ec4e911b9d17152ae919bad65f424347a1e7d7 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 12.0
 // assembly-output: emit-asm
 // compile-flags: -O
 // compile-flags: --target aarch64-unknown-linux-gnu
index aa25562d323595bd214dc73122c1404b4eeac1ba..66c39a48c6e1d5fbc1ecb2ea3207c5dedeb4af37 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // assembly-output: emit-asm
 // compile-flags: --target aarch64-unknown-linux-gnu
 // needs-llvm-components: aarch64
index bb6cc1c9873563b9a628def3f8305ab45136c15a..a6985a3bf5c6b6313c13b1e64b1f7bc8bd4e1947 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // assembly-output: emit-asm
 // compile-flags: -O
 // compile-flags: --target armv7-unknown-linux-gnueabihf
index b16fde571afac7d4c5920d9afc595f72f379a61f..c848e3284ff1f06bb1926b6ba7587e13b2bb5983 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // assembly-output: emit-asm
 // compile-flags: --target armv7-unknown-linux-gnueabihf
 // compile-flags: -C target-feature=+neon
index 3a7f2fa1efb6bddf2bd2ac9be79143e9300fa7b3..1c981040d601474da4547213aa610003c4e16e0d 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // only-x86_64
 // assembly-output: emit-asm
 // compile-flags: -C llvm-args=--x86-asm-syntax=intel
index 40352cdb4cdf2760273dcf13cf8cae26f595c26a..2156d77233d83888f99ed4ee9454596dfb4920e2 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // assembly-output: emit-asm
 // compile-flags: --target hexagon-unknown-linux-musl
 // needs-llvm-components: hexagon
index 9ec7ba83c4278b263b4e57add025815a0780d673..eb6627639f159d5d77a02c6e9756b7cdcffa5204 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // revisions: mips32 mips64
 // assembly-output: emit-asm
 //[mips32] compile-flags: --target mips-unknown-linux-gnu
index 75b6371fb70957ea7a9b72eb0c83caaafc6bd405..cc816fd78f81e2063c66a74e2740afe941b2182f 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // assembly-output: emit-asm
 // compile-flags: --target nvptx64-nvidia-cuda
 // compile-flags: --crate-type cdylib
index 55ca8ee836c9844b566e2ffd6f52184f7649c881..342998245315e8be0eeb55ce1bfb4c235b218d3b 100644 (file)
@@ -1,4 +1,4 @@
-// min-llvm-version: 10.0.1
+// min-llvm-version: 12.0.1
 // revisions: powerpc powerpc64
 // assembly-output: emit-asm
 //[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
index e62a6197b9a5e319adc698b4ea29c465afbee48c..c510689b42bff788ce2ac9626c10a10446eabf08 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // revisions: riscv64 riscv32
 // assembly-output: emit-asm
 //[riscv64] compile-flags: --target riscv64imac-unknown-none-elf
@@ -6,7 +5,6 @@
 //[riscv32] compile-flags: --target riscv32imac-unknown-none-elf
 //[riscv32] needs-llvm-components: riscv
 // compile-flags: -C target-feature=+d
-// min-system-llvm-version: 12.0
 
 #![feature(no_core, lang_items, rustc_attrs)]
 #![crate_type = "rlib"]
index 69d9cab23c8edde71d4f9453b237e233b8989855..b8a4ca08df1cc8ce2d06a39ad7513558b69ede8c 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // revisions: s390x
 // assembly-output: emit-asm
 //[s390x] compile-flags: --target s390x-unknown-linux-gnu
index a071a850c22b588cd25aa8c56fcf0af4db013161..4b2e83e69b1065ba5701286557cbcbc373176632 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // assembly-output: emit-asm
 // compile-flags: --target wasm32-unknown-unknown
 // compile-flags: --crate-type cdylib
index c926fd7b3f56539a81d8c905c7f946df22fa8b61..574fdf12cd0401194a11afd13c5fbd4512929d9c 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // revisions: x86_64 i686
 // assembly-output: emit-asm
 // compile-flags: -O
index d25f3a03777a6746beed80a72b1e525062374421..81be79cbaac18c25d8e9516bd8bb6327bdb6b92d 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // revisions: x86_64 i686
 // assembly-output: emit-asm
 //[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
index b331d45668ab378711f10001434f8101eba80252..6c41e0b78f13790fefa12e8850485845ec675d7b 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 12.0.0
 // revisions: x64 A64 ppc64le
 // assembly-output: emit-asm
 // [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static
diff --git a/src/test/codegen-units/item-collection/implicit-panic-call.rs b/src/test/codegen-units/item-collection/implicit-panic-call.rs
new file mode 100644 (file)
index 0000000..abec7ad
--- /dev/null
@@ -0,0 +1,58 @@
+// compile-flags:-Zprint-mono-items=lazy
+
+// rust-lang/rust#90405
+// Ensure implicit panic calls are collected
+
+#![feature(lang_items)]
+#![feature(no_core)]
+#![crate_type = "lib"]
+#![no_core]
+#![no_std]
+
+#[lang = "panic_location"]
+struct Location<'a> {
+    _file: &'a str,
+    _line: u32,
+    _col: u32,
+}
+
+#[lang = "panic"]
+#[inline]
+#[track_caller]
+fn panic(_: &'static str) -> ! {
+    loop {}
+}
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+trait Copy {}
+
+#[lang = "freeze"]
+trait Freeze {}
+
+impl Copy for i32 {}
+
+#[lang = "div"]
+trait Div<Rhs = Self> {
+    type Output;
+    fn div(self, rhs: Rhs) -> Self::Output;
+}
+
+impl Div for i32 {
+    type Output = i32;
+    fn div(self, rhs: i32) -> i32 {
+        self / rhs
+    }
+}
+
+#[allow(unconditional_panic)]
+pub fn foo() {
+    // This implicitly generates a panic call.
+    let _ = 1 / 0;
+}
+
+//~ MONO_ITEM fn foo
+//~ MONO_ITEM fn <i32 as Div>::div
+//~ MONO_ITEM fn panic
index aee93b93e3737177ab4fdb96a114c201e905de07..c3ffaeb9547b3c20a43168cc88d3aed04cbb29d3 100644 (file)
@@ -1,6 +1,5 @@
 //
 // no-system-llvm
-// min-llvm-version: 10.0.1
 // compile-flags: -O
 #![crate_type="lib"]
 
index 91a82c601202947f887fd75ea7aae0a76daab9ac..ce13a7ff938c8beb23ce18f7c230dd6ddfc4f8aa 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // revisions: powerpc powerpc64 powerpc64le
 //[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
 //[powerpc] needs-llvm-components: powerpc
index 110d1d55626f120cabf0f9f581fdc9b2da3564a3..2deabcaa6c21f289266b50aada863efa96ba9c3f 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 11.0.0
 // compile-flags: -O
 // ignore-debug: the debug assertions get in the way
 #![crate_type = "lib"]
index 851d68da5ee62b1575823c0e3e7d9637f0fbffaf..1c8cc61f204ddfff178d1d86b55e288154429761 100644 (file)
@@ -18,6 +18,9 @@
 // MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, _>::vtable$"
 // CHECK: !DISubrange(count: 3
 
+// NONMSVC-LABEL: !DIGlobalVariable(name: "<debug_vtable::bar::{closure#0} as core::ops::function::FnOnce<(core::option::Option<&dyn core::ops::function::Fn<(), Output=()>>)>>::{vtable}"
+// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::bar::closure$0, core::ops::function::FnOnce<tuple$<enum$<core::option::Option<ref$<dyn$<core::ops::function::Fn<tuple$<>,assoc$<Output,tuple$<> > > > > >, {{.*}}, {{.*}}, Some> > > >::vtable$"
+
 #![crate_type = "lib"]
 
 pub struct Foo;
@@ -45,3 +48,10 @@ pub fn foo(x: &Foo) -> (u32, (u64, i8), &dyn Send) {
     let z: &dyn SomeTraitWithGenerics<u64, i8> = x;
     (y.method1(), z.method1(), x as &dyn Send)
 }
+
+// Constructing the debuginfo name for the FnOnce vtable below initially caused an ICE on MSVC
+// because the trait type contains a late bound region that needed to be erased before the type
+// layout for the niche enum `Option<&dyn Fn()>` could be computed.
+pub fn bar() -> Box<dyn FnOnce(Option<&dyn Fn()>)> {
+    Box::new(|_x: Option<&dyn Fn()>| {})
+}
index 7e3773b6a3eb17aafa6d9f74644bc2bb7b769762..aa66c2ed08edb777fc24e53c76b870c99b93026d 100644 (file)
@@ -1,7 +1,6 @@
 // This test checks an optimization that is not guaranteed to work. This test case should not block
 // a future LLVM update.
 // compile-flags: -O
-// min-llvm-version: 11.0
 
 #![crate_type = "lib"]
 
index ad029f0fa7399300e87937e3b69a884152d6380a..b26945bc54940642ee5fc04aa5600bd13a8f87b4 100644 (file)
@@ -1,7 +1,6 @@
 // This test checks an optimization that is not guaranteed to work. This test case should not block
 // a future LLVM update.
 // compile-flags: -O
-// min-llvm-version: 11.0
 
 #![crate_type = "lib"]
 
index e779e2ef27439008ab39cc6011d293ea81d4566e..a1fa1387d9441d0f00d83b8e87fae37d51b7663e 100644 (file)
@@ -1,5 +1,4 @@
 // compile-flags: -O
-// min-llvm-version: 11.0
 
 #![crate_type = "lib"]
 
index f936f90960346004627318ef2ac216f9aed3bab4..3e10e227e55fef2604a0e707557ebc3c50fe1010 100644 (file)
@@ -1,6 +1,4 @@
 // compile-flags: -O -C no-prepopulate-passes
-//
-// min-system-llvm-version: 12.0
 
 #![crate_type = "lib"]
 #![feature(rustc_attrs)]
index 7ae78782ff9d1477cf2545e434da06d184ccdf3b..e5ee94e1f45e137263d0971028e79dff857a52fb 100644 (file)
@@ -1,5 +1,4 @@
 // compile-flags: -O
-// min-llvm-version: 11.0
 
 #![crate_type = "lib"]
 
index 6ba4d707f42b14088a21591427e311862d1db77b..a09c4bcfbeac539242fd388fcea324cb266afe37 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 12.0.0
 // compile-flags: -O
 #![crate_type = "lib"]
 
index e5f3ae45c07d345c967058f821f7381455adde7f..8d07a67a1b451807d84bc90a70a302bdcb2dc04f 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 11.0.0
 // compile-flags: -O
 // ignore-debug: the debug assertions get in the way
 #![crate_type = "lib"]
index d07eaa75b7a82d5dd213cd17154d62f40dcdd728..1ad05906e21abe61ad351258e12569ff81d09a16 100644 (file)
@@ -1,7 +1,6 @@
 // This test checks that bounds checks are elided when
 // index is part of a (x | y) < C style condition
 
-// min-llvm-version: 11.0.0
 // compile-flags: -O
 
 #![crate_type = "lib"]
index a03c63c1d09488f91e8f17fad4828df23bd3afc1..2d363d8f73be9161fc3a27cd2851292a1b505fbf 100644 (file)
@@ -1,6 +1,5 @@
 // Regression test for #75525, verifies that no bounds checks are generated.
 
-// min-llvm-version: 12.0.0
 // compile-flags: -O
 
 #![crate_type = "lib"]
index 49e4d4c7ec56da3ff0761a26b55a4a0044b68101..470a9e04096050d321bafd74e899ba3a8a07084d 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 12.0.0
 // compile-flags: -O
 #![crate_type = "lib"]
 
index 95042579adb6b65f20c909bfc650c22d390c4f67..4cc82414546b298c664be37db0e83a8b0fd9f0ca 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 12.0.0
 // compile-flags: -O
 #![crate_type = "lib"]
 
index 8f9a53d19d43a8bfeb7cb6dd430208295c1024b6..fa9c66b47c0a47d475233733bf2f7b69ba4fbd20 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 12.0
 // compile-flags: -C opt-level=3
 
 #![crate_type = "lib"]
index a4c76de1e3b8a452d752b814411d408aa44dab05..81d62ab33d77855628ddb9e716fa3016ad91c118 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 12.0
 // compile-flags: -C opt-level=3
 
 #![crate_type = "lib"]
index ccb22afbc7ae092a271037771331e4f6fc90693f..6d1f2d4bf8f4ad5ab60c8de9a56ffb6028e11a93 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 12.0
 // compile-flags: -C opt-level=3
 
 #![crate_type = "lib"]
index 896b7e8721cb741fb6d659216fd297851ce0f0a8..5e25e04fc24ac2136530923073d590e28e6f622b 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 12.0
 // compile-flags: -C opt-level=3
 
 #![crate_type = "lib"]
index 3017adb443252606c31bffc4b209ba76a42dd9d6..a61dad218cd85eda032383c0a2f5cc40604ee9f9 100644 (file)
@@ -1,7 +1,6 @@
 // compile-flags: -C no-prepopulate-passes
 //
 
-// min-system-llvm-version: 12.0
 // ignore-arm
 // ignore-aarch64
 // ignore-mips
index 429d760b4aa04cf4f627ecc67a11350cb8c3fcff..b68e8e9ebe9b463a1b1e1a878e575bd1d371e322 100644 (file)
@@ -1,7 +1,6 @@
 // compile-flags: -C no-prepopulate-passes
 //
 
-// min-system-llvm-version: 12.0
 // ignore-aarch64
 // ignore-emscripten
 // ignore-mips64
index 21176ac0e7a231774e55d037c19462e80e6ba690..0db17e6b13a80e513acd7437260907b3cf27d9b4 100644 (file)
@@ -1,7 +1,6 @@
 // compile-flags: -C no-prepopulate-passes
 //
 
-// min-system-llvm-version: 12.0
 // only-mips64
 // See repr-transparent.rs
 
diff --git a/src/test/codegen/sanitizer_cfi_add_canonical_jump_tables_flag.rs b/src/test/codegen/sanitizer_cfi_add_canonical_jump_tables_flag.rs
new file mode 100644 (file)
index 0000000..68f8180
--- /dev/null
@@ -0,0 +1,14 @@
+// Verifies that "CFI Canonical Jump Tables" module flag is added.
+//
+// ignore-windows
+// needs-sanitizer-cfi
+// only-aarch64
+// only-x86_64
+// compile-flags: -Clto -Zsanitizer=cfi
+
+#![crate_type="lib"]
+
+pub fn foo() {
+}
+
+// CHECK: !{{[0-9]+}} = !{i32 2, !"CFI Canonical Jump Tables", i32 1}
diff --git a/src/test/codegen/sanitizer_cfi_emit_type_checks.rs b/src/test/codegen/sanitizer_cfi_emit_type_checks.rs
new file mode 100644 (file)
index 0000000..9ed0422
--- /dev/null
@@ -0,0 +1,24 @@
+// Verifies that pointer type membership tests for indirect calls are emitted.
+//
+// ignore-windows
+// needs-sanitizer-cfi
+// only-aarch64
+// only-x86_64
+// compile-flags: -Clto -Cno-prepopulate-passes -Zsanitizer=cfi
+
+#![crate_type="lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}}
+    // CHECK:       start:
+    // CHECK-NEXT:  %0 = bitcast i32 (i32)* %f to i8*
+    // CHECK-NEXT:  %1 = call i1 @llvm.type.test(i8* %0, metadata !"{{[[:print:]]+}}")
+    // CHECK-NEXT:  br i1 %1, label %type_test.pass, label %type_test.fail
+    // CHECK:       type_test.pass:
+    // CHECK-NEXT:  %2 = call i32 %f(i32 %arg)
+    // CHECK-NEXT:  br label %bb1
+    // CHECK:       type_test.fail:
+    // CHECK-NEXT:  call void @llvm.trap()
+    // CHECK-NEXT:  unreachable
+    f(arg)
+}
diff --git a/src/test/codegen/sanitizer_cfi_emit_type_metadata.rs b/src/test/codegen/sanitizer_cfi_emit_type_metadata.rs
new file mode 100644 (file)
index 0000000..96fced4
--- /dev/null
@@ -0,0 +1,31 @@
+// Verifies that type metadata for functions are emitted.
+//
+// ignore-windows
+// needs-sanitizer-cfi
+// only-aarch64
+// only-x86_64
+// compile-flags: -Clto -Cno-prepopulate-passes -Zsanitizer=cfi
+
+#![crate_type="lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}}
+    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid1")
+    f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}bar{{.*}}!type !{{[0-9]+}}
+    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid2")
+    f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+    // CHECK-LABEL: define{{.*}}baz{{.*}}!type !{{[0-9]+}}
+    // CHECK:       %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid3")
+    f(arg1, arg2, arg3)
+}
+
+// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid2"}
+// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid3"}
+// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid4"}
index eaa9eafa1e87226c982959e649857ecc9a2a0c07..dc7db8e23728ea9f3d3ae64f275014aa437bdd3c 100644 (file)
@@ -1,5 +1,4 @@
 // compile-flags: -g -Z src-hash-algorithm=sha256
-// min-llvm-version: 11.0
 
 #![crate_type = "lib"]
 
index 72ed7492be93cb38fb2de2be2210feef86703598..a656c9e6f656a8f01db6717e3bfff5ec27d5d3bc 100644 (file)
@@ -1,6 +1,5 @@
 // ignore-debug: the debug assertions get in the way
 // compile-flags: -O
-// min-llvm-version: 11.0
 #![crate_type = "lib"]
 
 // Ensure that trivial casts of vec elements are O(1)
index baf130a87917972c569e8b17edda7d95c282a58e..eb06c4975bb7c2dc9cde840997c74af332f33758 100644 (file)
@@ -1,6 +1,5 @@
 // only-wasm32
 // compile-flags: -C target-feature=-nontrapping-fptoint
-// min-llvm-version: 12.0
 #![crate_type = "lib"]
 
 // CHECK-LABEL: @cast_f64_i64
diff --git a/src/test/incremental/auxiliary/rustc-rust-log-aux.rs b/src/test/incremental/auxiliary/rustc-rust-log-aux.rs
new file mode 100644 (file)
index 0000000..a361373
--- /dev/null
@@ -0,0 +1,8 @@
+// rustc-env:RUSTC_LOG=debug
+#[cfg(rpass1)]
+pub fn foo() {}
+
+#[cfg(rpass2)]
+pub fn foo() {
+    println!();
+}
index 5a944d28a0b913facc8955e2f829a7d50dcbce42..1b96cd54c3ed01b4baf623f9a0ab0c506de9f9c3 100644 (file)
@@ -83,7 +83,7 @@ pub fn change_iteration_variable_pattern() {
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck, promoted_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")]
 #[rustc_clean(cfg="cfail6")]
 pub fn change_iteration_variable_pattern() {
     let mut _x = 0;
@@ -108,7 +108,7 @@ pub fn change_iterable() {
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir, optimized_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir")]
 #[rustc_clean(cfg="cfail6")]
 pub fn change_iterable() {
     let mut _x = 0;
@@ -183,7 +183,7 @@ pub fn add_loop_label_to_break() {
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
 #[rustc_clean(cfg="cfail6")]
 pub fn add_loop_label_to_break() {
     let mut _x = 0;
@@ -237,7 +237,7 @@ pub fn add_loop_label_to_continue() {
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
 #[rustc_clean(cfg="cfail6")]
 pub fn add_loop_label_to_continue() {
     let mut _x = 0;
diff --git a/src/test/incremental/rustc-rust-log.rs b/src/test/incremental/rustc-rust-log.rs
new file mode 100644 (file)
index 0000000..566f0d9
--- /dev/null
@@ -0,0 +1,16 @@
+// revisions: rpass1 rpass2
+// This test is just checking that we won't ICE if logging is turned
+// on; don't bother trying to compare that (copious) output.
+//
+// dont-check-compiler-stdout
+// dont-check-compiler-stderr
+// aux-build: rustc-rust-log-aux.rs
+// rustc-env:RUSTC_LOG=debug
+
+#[cfg(rpass1)]
+fn main() {}
+
+#[cfg(rpass2)]
+fn main() {
+    println!();
+}
index 9035b46f4c69da407697aa3eba9822edf7525788..29243c9aa75d28758233d49d40294c68eec4f298 100644 (file)
@@ -3,10 +3,10 @@
   
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/inline-generator.rs:8:11: 8:11
-      let _1: std::ops::GeneratorState<<impl std::ops::Generator<bool> as std::ops::Generator<bool>>::Yield, <impl std::ops::Generator<bool> as std::ops::Generator<bool>>::Return>; // in scope 0 at $DIR/inline-generator.rs:9:9: 9:11
-      let mut _2: std::pin::Pin<&mut impl std::ops::Generator<bool>>; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:32
-      let mut _3: &mut impl std::ops::Generator<bool>; // in scope 0 at $DIR/inline-generator.rs:9:23: 9:31
-      let mut _4: impl std::ops::Generator<bool>; // in scope 0 at $DIR/inline-generator.rs:9:28: 9:31
+      let _1: std::ops::GeneratorState<i32, bool>; // in scope 0 at $DIR/inline-generator.rs:9:9: 9:11
+      let mut _2: std::pin::Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:32
+      let mut _3: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 0 at $DIR/inline-generator.rs:9:23: 9:31
+      let mut _4: [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 0 at $DIR/inline-generator.rs:9:28: 9:31
 +     let mut _7: bool;                    // in scope 0 at $DIR/inline-generator.rs:9:14: 9:46
       scope 1 {
           debug _r => _1;                  // in scope 1 at $DIR/inline-generator.rs:9:9: 9:11
diff --git a/src/test/mir-opt/inline/issue-78442.rs b/src/test/mir-opt/inline/issue-78442.rs
new file mode 100644 (file)
index 0000000..aa8ede2
--- /dev/null
@@ -0,0 +1,20 @@
+// compile-flags: -Z mir-opt-level=3 -Z inline-mir
+// ignore-wasm32-bare compiled with panic=abort by default
+#![crate_type = "lib"]
+
+// EMIT_MIR issue_78442.bar.RevealAll.diff
+// EMIT_MIR issue_78442.bar.Inline.diff
+pub fn bar<P>(
+    // Error won't happen if "bar" is not generic
+    _baz: P,
+) {
+    hide_foo()();
+}
+
+fn hide_foo() -> impl Fn() {
+    // Error won't happen if "iterate" hasn't impl Trait or has generics
+    foo
+}
+
+fn foo() { // Error won't happen if "foo" isn't used in "iterate" or has generics
+}
diff --git a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
new file mode 100644 (file)
index 0000000..4d9e022
--- /dev/null
@@ -0,0 +1,67 @@
+- // MIR for `bar` before Inline
++ // MIR for `bar` after Inline
+  
+  fn bar(_1: P) -> () {
+      debug _baz => _1;                    // in scope 0 at $DIR/issue-78442.rs:9:5: 9:9
+      let mut _0: ();                      // return place in scope 0 at $DIR/issue-78442.rs:10:3: 10:3
+      let _2: ();                          // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+      let mut _3: &fn() {foo};             // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+      let _4: fn() {foo};                  // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+      let mut _5: ();                      // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
++     scope 1 (inlined <fn() {foo} as Fn<()>>::call - shim(fn() {foo})) { // at $DIR/issue-78442.rs:11:5: 11:17
++     }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+          StorageLive(_3);                 // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+          StorageLive(_4);                 // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+-         _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
++         _4 = hide_foo() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+                                           // mir::Constant
+                                           // + span: $DIR/issue-78442.rs:11:5: 11:13
+                                           // + literal: Const { ty: fn() -> impl std::ops::Fn<()> {hide_foo}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          _3 = &_4;                        // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+          StorageLive(_5);                 // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+-         _2 = <impl Fn<()> as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+-                                          // mir::Constant
+-                                          // + span: $DIR/issue-78442.rs:11:5: 11:15
+-                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl std::ops::Fn<()>, ()) -> <impl std::ops::Fn<()> as std::ops::FnOnce<()>>::Output {<impl std::ops::Fn<()> as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
++         _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $DIR/issue-78442.rs:11:5: 11:17
+      }
+  
+      bb2: {
+-         StorageDead(_5);                 // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
+-         StorageDead(_3);                 // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
+-         StorageDead(_4);                 // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
+-         StorageDead(_2);                 // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
+-         _0 = const ();                   // scope 0 at $DIR/issue-78442.rs:10:3: 12:2
+-         drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
++         return;                          // scope 0 at $DIR/issue-78442.rs:12:2: 12:2
+      }
+  
+-     bb3: {
+-         return;                          // scope 0 at $DIR/issue-78442.rs:12:2: 12:2
++     bb3 (cleanup): {
++         drop(_1) -> bb4;                 // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
+      }
+  
+      bb4 (cleanup): {
+-         drop(_1) -> bb5;                 // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
++         resume;                          // scope 0 at $DIR/issue-78442.rs:7:1: 12:2
+      }
+  
+-     bb5 (cleanup): {
+-         resume;                          // scope 0 at $DIR/issue-78442.rs:7:1: 12:2
++     bb5: {
++         StorageDead(_5);                 // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
++         StorageDead(_3);                 // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
++         StorageDead(_4);                 // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
++         StorageDead(_2);                 // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
++         _0 = const ();                   // scope 0 at $DIR/issue-78442.rs:10:3: 12:2
++         drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
new file mode 100644 (file)
index 0000000..45b552c
--- /dev/null
@@ -0,0 +1,55 @@
+- // MIR for `bar` before RevealAll
++ // MIR for `bar` after RevealAll
+  
+  fn bar(_1: P) -> () {
+      debug _baz => _1;                    // in scope 0 at $DIR/issue-78442.rs:9:5: 9:9
+      let mut _0: ();                      // return place in scope 0 at $DIR/issue-78442.rs:10:3: 10:3
+      let _2: ();                          // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+-     let mut _3: &impl std::ops::Fn<()>;  // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+-     let _4: impl std::ops::Fn<()>;       // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
++     let mut _3: &fn() {foo};             // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
++     let _4: fn() {foo};                  // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+      let mut _5: ();                      // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+          StorageLive(_3);                 // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+          StorageLive(_4);                 // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+          _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+                                           // mir::Constant
+                                           // + span: $DIR/issue-78442.rs:11:5: 11:13
+                                           // + literal: Const { ty: fn() -> impl std::ops::Fn<()> {hide_foo}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          _3 = &_4;                        // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+          StorageLive(_5);                 // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+          nop;                             // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+          _2 = <impl Fn<()> as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+                                           // mir::Constant
+                                           // + span: $DIR/issue-78442.rs:11:5: 11:15
+                                           // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl std::ops::Fn<()>, ()) -> <impl std::ops::Fn<()> as std::ops::FnOnce<()>>::Output {<impl std::ops::Fn<()> as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb2: {
+          StorageDead(_5);                 // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
+          StorageDead(_3);                 // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
+          StorageDead(_4);                 // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
+          StorageDead(_2);                 // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
+          _0 = const ();                   // scope 0 at $DIR/issue-78442.rs:10:3: 12:2
+          drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
+      }
+  
+      bb3: {
+          return;                          // scope 0 at $DIR/issue-78442.rs:12:2: 12:2
+      }
+  
+      bb4 (cleanup): {
+          drop(_1) -> bb5;                 // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
+      }
+  
+      bb5 (cleanup): {
+          resume;                          // scope 0 at $DIR/issue-78442.rs:7:1: 12:2
+      }
+  }
+  
index 1ff1ffcc4b0b8a80dde01c8f60df5b0de136859c..8722d9e10d91d204fa457b5afc93eb1b3f1f7e42 100644 (file)
@@ -1,5 +1,4 @@
 # needs-profiler-support
-# min-llvm-version: 11.0
 
 -include ../coverage/coverage_tools.mk
 
index 78fbf811f12bf5b70aa2ad0842db9bbb5a5ad748..4adf02bee0af47eaf85a133e0871c87f6746695a 100644 (file)
@@ -1,6 +1,5 @@
 # needs-profiler-support
 # ignore-windows-gnu
-# min-llvm-version: 11.0
 
 # FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works
 # properly. Since we only have GCC on the CI ignore the test for now.
index c279cf7e8bf10bcb77e5b150b909f00563a0149f..dd3b7c76f28675b8d0d77321f9607193fe843119 100644 (file)
@@ -2,8 +2,6 @@
 // are caught by catch_unwind. Also tests that Rust panics can unwind through
 // C++ code.
 
-// For linking libstdc++ on MinGW
-#![cfg_attr(all(windows, target_env = "gnu"), feature(static_nobundle))]
 #![feature(c_unwind)]
 
 use std::panic::{catch_unwind, AssertUnwindSafe};
index a288b90d7924e96de619596b1eede797573fb423..86e6d9e756c51d9946e1828195a4de2c090699ed 100644 (file)
@@ -25,7 +25,7 @@
 use rustc_interface::interface::Compiler;
 use rustc_interface::{Config, Queries};
 use rustc_middle::ty::query::query_values::mir_borrowck;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::Session;
 use std::cell::RefCell;
@@ -87,9 +87,8 @@ fn after_analysis<'tcx>(
     }
 }
 
-fn override_queries(_session: &Session, local: &mut Providers, external: &mut Providers) {
+fn override_queries(_session: &Session, local: &mut Providers, _external: &mut ExternProviders) {
     local.mir_borrowck = mir_borrowck;
-    external.mir_borrowck = mir_borrowck;
 }
 
 // Since mir_borrowck does not have access to any other state, we need to use a
diff --git a/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/Makefile b/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/Makefile
new file mode 100644 (file)
index 0000000..4934e87
--- /dev/null
@@ -0,0 +1,18 @@
+-include ../../run-make-fulldeps/tools.mk
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc"
+DYLIB_NAME := $(shell echo | $(RUSTC) --crate-name foobar_macro --crate-type dylib --print file-names -)
+
+all:
+       $(RUSTC) src/proc.rs --crate-name foobar_macro --edition=2021 --crate-type proc-macro --emit=dep-info,link
+
+       $(RUSTC) src/lib.rs --crate-name foobar --edition=2021 --crate-type lib --emit=dep-info,link
+
+       $(RUSTDOC) examples/ex.rs --crate-name ex --crate-type bin --output $(OUTPUT_DIR) \
+               --extern foobar=$(TMPDIR)/libfoobar.rlib --extern foobar_macro=$(TMPDIR)/$(DYLIB_NAME) \
+               -Z unstable-options --scrape-examples-output-path $(TMPDIR)/ex.calls --scrape-examples-target-crate foobar
+
+       $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --output $(OUTPUT_DIR) \
+               -Z unstable-options --with-examples $(TMPDIR)/ex.calls
+
+       $(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
diff --git a/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/examples/ex.rs b/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/examples/ex.rs
new file mode 100644 (file)
index 0000000..4d8c8b3
--- /dev/null
@@ -0,0 +1,27 @@
+extern crate foobar;
+extern crate foobar_macro;
+
+use foobar::*;
+use foobar_macro::*;
+
+a_proc_macro!(); // no
+
+#[an_attr_macro]
+fn a() {
+  f(); // no
+}
+
+#[an_attr_macro(with_span)]
+fn b() {
+  f(); // yes
+}
+
+fn c() {
+  a_rules_macro!(f()); // yes
+}
+
+fn d() {
+  a_rules_macro!(()); // no
+}
+
+fn main(){}
diff --git a/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/lib.rs b/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/lib.rs
new file mode 100644 (file)
index 0000000..bac3970
--- /dev/null
@@ -0,0 +1,12 @@
+// Scraped example should only include line numbers for items b and c in ex.rs
+// @!has foobar/fn.f.html '//*[@class="line-numbers"]' '14'
+// @has foobar/fn.f.html '//*[@class="line-numbers"]' '15'
+// @has foobar/fn.f.html '//*[@class="line-numbers"]' '21'
+// @!has foobar/fn.f.html '//*[@class="line-numbers"]' '22'
+
+pub fn f() {}
+
+#[macro_export]
+macro_rules! a_rules_macro {
+  ($e:expr) => { ($e, foobar::f()); }
+}
diff --git a/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/proc.rs b/src/test/run-make-fulldeps/rustdoc-scrape-examples-macros/src/proc.rs
new file mode 100644 (file)
index 0000000..46e518f
--- /dev/null
@@ -0,0 +1,39 @@
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn a_proc_macro(_item: TokenStream) -> TokenStream {
+    "fn ex() { foobar::f(); }".parse().unwrap()
+}
+
+// inserts foobar::f() to the end of the function
+#[proc_macro_attribute]
+pub fn an_attr_macro(attr: TokenStream, item: TokenStream) -> TokenStream {
+    let new_call: TokenStream = "foobar::f();".parse().unwrap();
+
+    let mut tokens = item.into_iter();
+
+    let fn_tok = tokens.next().unwrap();
+    let ident_tok = tokens.next().unwrap();
+    let args_tok = tokens.next().unwrap();
+    let body = match tokens.next().unwrap() {
+        TokenTree::Group(g) => {
+            let new_g = Group::new(g.delimiter(), new_call);
+            let mut outer_g = Group::new(
+                g.delimiter(),
+                [TokenTree::Group(g.clone()), TokenTree::Group(new_g)].into_iter().collect(),
+            );
+
+            if attr.to_string() == "with_span" {
+                outer_g.set_span(g.span());
+            }
+
+            TokenTree::Group(outer_g)
+        }
+        _ => unreachable!(),
+    };
+
+    let tokens = vec![fn_tok, ident_tok, args_tok, body].into_iter().collect::<TokenStream>();
+
+    tokens
+}
index c89f2ae8349e538fffed9bdb78b1d9ad7f1d15d5..e8e62efe01c140de3ddc5c462469aa06859ac20d 100644 (file)
@@ -1,7 +1,5 @@
 -include ../tools.mk
 
-# min-llvm-version: 11.0
-
 all: off packed unpacked
 
 ifeq ($(UNAME),Darwin)
index f56b4168b2d66673a0f98895b7e786d910ea2c4c..ef61ff0450157a73c603b9ec1cff626547fa12ec 100644 (file)
@@ -1,7 +1,6 @@
 -include ../tools.mk
 
 # only-linux
-# min-llvm-version: 11.0
 
 all:
        $(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 foo.rs -g
index 3934c4725f4133a1ad86ae63e4bf469ca924c67a..9655d09df0f2a021ff78835395c411d308d1694f 100644 (file)
@@ -117,10 +117,10 @@ else
        # that it is compiled with the expectation that pthreads is dynamically
        # linked as a DLL and will fail to link with a statically linked libpthread.
        #
-       # So we end up with the following hack: we link use static-nobundle to only
+       # So we end up with the following hack: we link use static:-bundle to only
        # link the parts of libstdc++ that we actually use, which doesn't include
        # the dependency on the pthreads DLL.
-       EXTRARSCXXFLAGS := -l static-nobundle=stdc++
+       EXTRARSCXXFLAGS := -l static:-bundle=stdc++ -Z unstable-options
 endif
 else
 ifeq ($(UNAME),Darwin)
index 845844f427bdf1177edb4ceebaf7746126b2cc6d..f30a35e27c0bcc7f596fda1de1e8007e2798c109 100644 (file)
@@ -1,8 +1,5 @@
 // Tests that linking to C++ code with global destructors works.
 
-// For linking libstdc++ on MinGW
-#![cfg_attr(all(windows, target_env = "gnu"), feature(static_nobundle))]
-
 extern "C" {
     fn get() -> u32;
 }
diff --git a/src/test/run-make/rustdoc-scrape-examples-invalid-expr/Makefile b/src/test/run-make/rustdoc-scrape-examples-invalid-expr/Makefile
new file mode 100644 (file)
index 0000000..dce8b83
--- /dev/null
@@ -0,0 +1,5 @@
+deps := ex
+
+-include ../rustdoc-scrape-examples-multiple/scrape.mk
+
+all: scrape
diff --git a/src/test/run-make/rustdoc-scrape-examples-invalid-expr/examples/ex.rs b/src/test/run-make/rustdoc-scrape-examples-invalid-expr/examples/ex.rs
new file mode 100644 (file)
index 0000000..b342b5b
--- /dev/null
@@ -0,0 +1,2 @@
+pub struct Foo([usize; foobar::f()]);
+fn main() {}
diff --git a/src/test/run-make/rustdoc-scrape-examples-invalid-expr/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-invalid-expr/src/lib.rs
new file mode 100644 (file)
index 0000000..c30c99d
--- /dev/null
@@ -0,0 +1 @@
+pub const fn f() -> usize { 5 }
diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/Makefile b/src/test/run-make/rustdoc-scrape-examples-multiple/Makefile
new file mode 100644 (file)
index 0000000..897805e
--- /dev/null
@@ -0,0 +1,5 @@
+deps := ex ex2
+
+-include ./scrape.mk
+
+all: scrape
diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex.rs b/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex.rs
new file mode 100644 (file)
index 0000000..01b730c
--- /dev/null
@@ -0,0 +1,4 @@
+fn main() {
+    foobar::ok();
+    foobar::ok();
+}
diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex2.rs b/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex2.rs
new file mode 100644 (file)
index 0000000..f83cf2f
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    foobar::ok();
+}
diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/scrape.mk b/src/test/run-make/rustdoc-scrape-examples-multiple/scrape.mk
new file mode 100644 (file)
index 0000000..1fa1fae
--- /dev/null
@@ -0,0 +1,20 @@
+-include ../../run-make-fulldeps/tools.mk
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc"
+
+$(TMPDIR)/%.calls: $(TMPDIR)/libfoobar.rmeta
+       $(RUSTDOC) examples/$*.rs --crate-name $* --crate-type bin --output $(OUTPUT_DIR) \
+         --extern foobar=$(TMPDIR)/libfoobar.rmeta \
+               -Z unstable-options \
+               --scrape-examples-output-path $@ \
+               --scrape-examples-target-crate foobar
+
+$(TMPDIR)/lib%.rmeta: src/lib.rs
+       $(RUSTC) src/lib.rs --crate-name $* --crate-type lib --emit=metadata
+
+scrape: $(foreach d,$(deps),$(TMPDIR)/$(d).calls)
+       $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --output $(OUTPUT_DIR) \
+               -Z unstable-options \
+               $(foreach d,$(deps),--with-examples $(TMPDIR)/$(d).calls)
+
+       $(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-multiple/src/lib.rs
new file mode 100644 (file)
index 0000000..bdfeda9
--- /dev/null
@@ -0,0 +1,6 @@
+// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]//*[@class="prev"]' ''
+// @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' ''
+// @has src/ex/ex.rs.html
+// @has foobar/fn.ok.html '//a[@href="../src/ex/ex.rs.html#2"]' ''
+
+pub fn ok() {}
diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/Makefile b/src/test/run-make/rustdoc-scrape-examples-ordering/Makefile
new file mode 100644 (file)
index 0000000..339d539
--- /dev/null
@@ -0,0 +1,5 @@
+deps := ex1 ex2
+
+-include ../rustdoc-scrape-examples-multiple/scrape.mk
+
+all: scrape
diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex1.rs b/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex1.rs
new file mode 100644 (file)
index 0000000..05c1800
--- /dev/null
@@ -0,0 +1,11 @@
+fn main() {
+    foobar::ok(0);
+
+    // this is a
+
+    //  ..
+
+    // BIG
+
+    // item
+}
diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex2.rs b/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex2.rs
new file mode 100644 (file)
index 0000000..de21d90
--- /dev/null
@@ -0,0 +1,8 @@
+fn main() {
+    foobar::ok(1);
+    // small item
+}
+
+fn f() {
+    foobar::ok(2);
+}
diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs
new file mode 100644 (file)
index 0000000..5afffff
--- /dev/null
@@ -0,0 +1,7 @@
+// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]' 'ex2'
+// @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' 'ex1'
+// @has foobar/fn.ok.html '//*[@class="highlight focus"]' '1'
+// @has foobar/fn.ok.html '//*[@class="highlight"]' '2'
+// @has foobar/fn.ok.html '//*[@class="highlight focus"]' '0'
+
+pub fn ok(_x: i32) {}
diff --git a/src/test/run-make/rustdoc-scrape-examples-remap/Makefile b/src/test/run-make/rustdoc-scrape-examples-remap/Makefile
new file mode 100644 (file)
index 0000000..dce8b83
--- /dev/null
@@ -0,0 +1,5 @@
+deps := ex
+
+-include ../rustdoc-scrape-examples-multiple/scrape.mk
+
+all: scrape
diff --git a/src/test/run-make/rustdoc-scrape-examples-remap/examples/ex.rs b/src/test/run-make/rustdoc-scrape-examples-remap/examples/ex.rs
new file mode 100644 (file)
index 0000000..1438fdb
--- /dev/null
@@ -0,0 +1,4 @@
+fn main() {
+    foobar::b::foo();
+    foobar::c::foo();
+}
diff --git a/src/test/run-make/rustdoc-scrape-examples-remap/src/a.rs b/src/test/run-make/rustdoc-scrape-examples-remap/src/a.rs
new file mode 100644 (file)
index 0000000..b76b432
--- /dev/null
@@ -0,0 +1 @@
+pub fn foo() {}
diff --git a/src/test/run-make/rustdoc-scrape-examples-remap/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-remap/src/lib.rs
new file mode 100644 (file)
index 0000000..f525a42
--- /dev/null
@@ -0,0 +1,8 @@
+// @has foobar/b/fn.foo.html '//*[@class="scraped-example expanded"]' 'ex.rs'
+// @has foobar/c/fn.foo.html '//*[@class="scraped-example expanded"]' 'ex.rs'
+
+#[path = "a.rs"]
+pub mod b;
+
+#[path = "a.rs"]
+pub mod c;
diff --git a/src/test/rustdoc-gui/anchor-navigable.goml b/src/test/rustdoc-gui/anchor-navigable.goml
new file mode 100644 (file)
index 0000000..424c312
--- /dev/null
@@ -0,0 +1,11 @@
+// The `impl Foo` heading underneath `Implementations` has a §
+// anchor to its left (used for linking to that heading). The anchor only shows
+// up when hovering the `impl Foo`. This test ensures there's no gap between the
+// anchor and the `impl Foo`. If there were a gap, this would cause an annoying
+// problem: you hover `impl Foo` to see the anchor, then when you move your
+// mouse to the left, the anchor disappears before you reach it.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+// We check that ".item-info" is bigger than its content.
+move-cursor-to: ".impl"
+assert-property: (".impl > a.anchor", {"offsetWidth": "9"})
+assert-css: (".impl > a.anchor", {"left": "-8px"})
index 44fcec3393744dedd21752a821bda94875581b04..239e51a91293fafcf152bc83c26f9cb8a3867126 100644 (file)
@@ -1,4 +1,4 @@
 goto: file://|DOC_PATH|/test_docs/index.html
 assert: ("#functions")
 goto: ./struct.Foo.html
-assert: ("div.type-decl")
+assert: ("div.item-decl")
diff --git a/src/test/rustdoc-gui/check-code-blocks-margin.goml b/src/test/rustdoc-gui/check-code-blocks-margin.goml
new file mode 100644 (file)
index 0000000..2de4768
--- /dev/null
@@ -0,0 +1,6 @@
+// This test ensures that the docblock elements have the appropriate left margin.
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+// The top docblock elements shouldn't have left margin...
+assert-css: ("#main .docblock.item-decl", {"margin-left": "0px"})
+// ... but all the others should!
+assert-css: ("#main .docblock:not(.item-decl)", {"margin-left": "24px"})
diff --git a/src/test/rustdoc-gui/docblock-code-block-line-number.goml b/src/test/rustdoc-gui/docblock-code-block-line-number.goml
new file mode 100644 (file)
index 0000000..7e6607b
--- /dev/null
@@ -0,0 +1,22 @@
+// Checks that the setting "line numbers" is working as expected.
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+
+// We check that without this setting, there is no line number displayed.
+assert-false: "pre.line-number"
+
+// We now set the setting to show the line numbers on code examples.
+local-storage: {"rustdoc-line-numbers": "true" }
+// We reload to make the line numbers appear.
+reload:
+
+// We wait for them to be added into the DOM by the JS...
+wait-for: "pre.line-number"
+// If the test didn't fail, it means that it was found!
+// Let's now check some CSS properties...
+assert-css: ("pre.line-number", {
+    "margin": "0px",
+    "padding": "13px 8px",
+    "text-align": "right"
+})
+// The first code block has two lines so let's check its `<pre>` elements lists both of them.
+assert-text: ("pre.line-number", "1\n2")
index d8411511c5aeef97e3b01d7bc0e5406c8f433c67..0459fd4b9c353644158378331ed6ab8765b0f090 100644 (file)
@@ -1,6 +1,6 @@
 goto: file://|DOC_PATH|/lib2/struct.Foo.html
 // This test checks that the font weight is correctly applied.
-assert-css: ("//*[@class='docblock type-decl']//a[text()='Alias']", {"font-weight": "400"})
+assert-css: ("//*[@class='docblock item-decl']//a[text()='Alias']", {"font-weight": "400"})
 assert-css: ("//*[@class='structfield small-section-header']//a[text()='Alias']", {"font-weight": "400"})
 assert-css: ("#method\.a_method > .code-header", {"font-weight": "600"})
 assert-css: ("#associatedtype\.X > .code-header", {"font-weight": "600"})
@@ -16,7 +16,7 @@ goto: file://|DOC_PATH|/lib2/trait.Trait.html
 
 // This is a complex selector, so here's how it works:
 //
-// * //*[@class='docblock type-decl'] — selects element of any tag with classes docblock and type-decl
+// * //*[@class='docblock item-decl'] — selects element of any tag with classes docblock and item-decl
 // * /pre[@class='rust trait'] — selects immediate child with tag pre and classes rust and trait
 // * /code — selects immediate child with tag code
 // * /a[@class='constant'] — selects immediate child with tag a and class constant
@@ -25,8 +25,8 @@ goto: file://|DOC_PATH|/lib2/trait.Trait.html
 //
 // This uses '/parent::*' as a proxy for the style of the text node.
 // We can't just select the '<a>' because intermediate tags could be added.
-assert-count: ("//*[@class='docblock type-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*", 1)
-assert-css: ("//*[@class='docblock type-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*", {"font-weight": "400"})
+assert-count: ("//*[@class='docblock item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*", 1)
+assert-css: ("//*[@class='docblock item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*", {"font-weight": "400"})
 
 assert-count: (".methods .type", 1)
 assert-css: (".methods .type", {"font-weight": "600"})
diff --git a/src/test/rustdoc-gui/headings.goml b/src/test/rustdoc-gui/headings.goml
new file mode 100644 (file)
index 0000000..bdf17ec
--- /dev/null
@@ -0,0 +1,156 @@
+// This test check that headers (a) have the correct heading level, (b) are the right size,
+// and (c) have the correct underlining (or absence of underlining).
+// The sizes may change as design changes, but try to make sure a lower header is never bigger than
+// its parent headers. Also make sure lower headers don't have underlines when their parents lack
+// an underline.
+// Most of these sizes are set in CSS in `em` units, so here's a conversion chart based on our
+// default 16px font size:
+// 24px    1.5em
+// 22.4px  1.4em
+// 20.8px  1.3em
+// 18.4px  1.15em
+// 17.6px  1.1em
+// 16px    1em
+// 15.2px  0.95em  
+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"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "17.6px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#fields", {"font-size": "22.4px"})
+assert-css: ("h2#fields", {"border-bottom-width": "1px"})
+assert-css: ("h3#title-for-field", {"font-size": "20.8px"})
+assert-css: ("h3#title-for-field", {"border-bottom-width": "0px"})
+assert-css: ("h4#sub-heading-for-field", {"font-size": "16px"})
+assert-css: ("h4#sub-heading-for-field", {"border-bottom-width": "0px"})
+
+assert-css: ("h2#implementations", {"font-size": "22.4px"})
+assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
+
+assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
+assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#title-for-struct-impl-doc", {"font-size": "16px"})
+assert-css: ("h4#title-for-struct-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h5#sub-heading-for-struct-impl-doc", {"font-size": "16px"})
+assert-css: ("h5#sub-heading-for-struct-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"border-bottom-width": "0px"})
+
+assert-css: ("h5#title-for-struct-impl-item-doc", {"font-size": "16px"})
+assert-css: ("h5#title-for-struct-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-struct-impl-item-doc", {"font-size": "15.2px"})
+
+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"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "17.6px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#variants", {"font-size": "22.4px"})
+assert-css: ("h2#variants", {"border-bottom-width": "1px"})
+
+assert-css: ("h3#none-prose-title", {"font-size": "20.8px"})
+assert-css: ("h3#none-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h4#none-prose-sub-heading", {"font-size": "16px"})
+assert-css: ("h4#none-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h3#wrapped-prose-title", {"font-size": "20.8px"})
+assert-css: ("h3#wrapped-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h4#wrapped-prose-sub-heading", {"font-size": "16px"})
+assert-css: ("h4#wrapped-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#wrapped0-prose-title", {"font-size": "16px"})
+assert-css: ("h4#wrapped0-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h5#wrapped0-prose-sub-heading", {"font-size": "16px"})
+assert-css: ("h5#wrapped0-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#structy-prose-title", {"font-size": "16px"})
+assert-css: ("h4#structy-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h5#structy-prose-sub-heading", {"font-size": "16px"})
+assert-css: ("h5#structy-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h2#implementations", {"font-size": "22.4px"})
+assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
+
+assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
+assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#title-for-enum-impl-doc", {"font-size": "16px"})
+assert-css: ("h4#title-for-enum-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h5#sub-heading-for-enum-impl-doc", {"font-size": "16px"})
+assert-css: ("h5#sub-heading-for-enum-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"border-bottom-width": "0px"})
+
+assert-css: ("h5#title-for-enum-impl-item-doc", {"font-size": "16px"})
+assert-css: ("h5#title-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
+
+assert-text: (".sidebar .others h3", "Modules")
+assert-css: (".sidebar .others h3", {"border-bottom-width": "1px"}, ALL)
+
+goto: file://|DOC_PATH|/test_docs/union.HeavilyDocumentedUnion.html
+
+assert-css: ("h1.fqn", {"font-size": "24px"})
+assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
+
+assert-css: ("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"})
+
+assert-css: ("h2#fields", {"font-size": "22.4px"})
+assert-css: ("h2#fields", {"border-bottom-width": "1px"})
+
+assert-css: ("h3#title-for-union-variant", {"font-size": "20.8px"})
+assert-css: ("h3#title-for-union-variant", {"border-bottom-width": "0px"})
+assert-css: ("h4#sub-heading-for-union-variant", {"font-size": "16px"})
+assert-css: ("h4#sub-heading-for-union-variant", {"border-bottom-width": "0px"})
+
+assert-css: ("h2#implementations", {"font-size": "22.4px"})
+assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
+
+assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
+assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("h4#title-for-union-impl-doc", {"font-size": "16px"})
+assert-css: ("h4#title-for-union-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h5#sub-heading-for-union-impl-doc", {"font-size": "16px"})
+assert-css: ("h5#sub-heading-for-union-impl-doc", {"border-bottom-width": "0px"})
+
+assert-css: ("h5#title-for-union-impl-item-doc", {"font-size": "16px"})
+assert-css: ("h5#title-for-union-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"border-bottom-width": "0px"})
+
+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"})
diff --git a/src/test/rustdoc-gui/javascript-disabled.goml b/src/test/rustdoc-gui/javascript-disabled.goml
new file mode 100644 (file)
index 0000000..1693f7b
--- /dev/null
@@ -0,0 +1,6 @@
+// When JavaScript is disabled, we hide the search bar, because it
+// can't be used without JS.
+javascript: false
+
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+assert-css: (".sub", {"display": "none"})
index ab595d28019210bfec57a956853fb640dd11ab75..0316172ee1464663e393d4290d63f01f7491b59b 100644 (file)
@@ -1,23 +1,23 @@
 // This test checks that the correct font is used on module items (in index.html pages).
 goto: file://|DOC_PATH|/test_docs/index.html
-assert-css: (".item-table .module-item a", {"font-family": '"Fira Sans", Arial, sans-serif'}, ALL)
-assert-css: (".item-table .docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'}, ALL)
+assert-css: (".item-table .module-item a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ALL)
+assert-css: (".item-table .docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ALL)
 
 // modules
-assert-css: ("#modules + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#modules + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#modules + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#modules + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
 // structs
-assert-css: ("#structs + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#structs + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#structs + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#structs + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
 // enums
-assert-css: ("#enums + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#enums + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#enums + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#enums + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
 // traits
-assert-css: ("#traits + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#traits + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#traits + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#traits + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
 // functions
-assert-css: ("#functions + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#functions + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#functions + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#functions + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
 // keywords
-assert-css: ("#keywords + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#keywords + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#keywords + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#keywords + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
diff --git a/src/test/rustdoc-gui/overflow-tooltip-information.goml b/src/test/rustdoc-gui/overflow-tooltip-information.goml
new file mode 100644 (file)
index 0000000..7ef85a4
--- /dev/null
@@ -0,0 +1,8 @@
+// The goal of this test is to ensure that the tooltip `.information` class doesn't
+// have overflow and max-width CSS rules set because they create a bug in firefox on
+// mac. For more information: https://github.com/rust-lang/rust/issues/89185
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+assert-css: (".docblock > .information", {
+    "overflow-x": "visible",
+    "max-width": "none"
+}, ALL)
diff --git a/src/test/rustdoc-gui/sidebar-macro-reexport.goml b/src/test/rustdoc-gui/sidebar-macro-reexport.goml
new file mode 100644 (file)
index 0000000..a3a62fe
--- /dev/null
@@ -0,0 +1,5 @@
+// This test ensures that the reexport of a macro doesn't make the original macro
+// displayed twice in the sidebar.
+goto: file://|DOC_PATH|/test_docs/macro.repro.html
+wait-for: ".sidebar-elems .macro .macro"
+assert-count: ("//*[@class='sidebar-elems']//*[@class='block macro']//a[text()='repro']", 1)
index c8ebb8c56f5351657f3c0de218ccf7da6f1acd93..f9c707f81e79c8022c510a1f183d74f2f92cd5f6 100644 (file)
@@ -4,15 +4,17 @@ assert-text: (".sidebar > .location", "Crate test_docs")
 assert-count: (".sidebar .location", 1)
 assert-text: (".sidebar-elems > #all-types", "See all test_docs's items")
 // 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")
+assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs")
 // And we're also supposed to have the list of items in the current module.
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(3)", "Enums")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(4)", "Traits")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(5)", "Functions")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(6)", "Type Definitions")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(7)", "Keywords")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Modules")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(2)", "Macros")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(3)", "Structs")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(4)", "Enums")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(5)", "Traits")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(6)", "Functions")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(7)", "Type Definitions")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(8)", "Unions")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(9)", "Keywords")
 assert-text: ("#structs + .item-table .item-left > a", "Foo")
 click: "#structs + .item-table .item-left > a"
 
@@ -22,13 +24,13 @@ assert-count: (".sidebar .location", 2)
 assert-false: ".sidebar-elems > .crate"
 // We now go back to the crate page to click on the "lib2" crate link.
 goto: file://|DOC_PATH|/test_docs/index.html
-click: ".sidebar-elems .crate > ul > li:first-child > a"
+click: ".sidebar-elems .crate > ul > li:first-child > a"
 
 // PAGE: lib2/index.html
 goto: file://|DOC_PATH|/lib2/index.html
 assert-text: (".sidebar > .location", "Crate lib2")
 // We check that we have the crates list and that the "current" on is now "lib2".
-assert-text: (".sidebar-elems .crate > ul > li > a.current", "lib2")
+assert-text: (".sidebar-elems .crate > ul > li > a.current", "lib2")
 // We now go to the "foobar" function page.
 assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
 assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
@@ -55,6 +57,6 @@ assert-false: ".sidebar-elems > .crate"
 goto: ./sub_module/sub_sub_module/index.html
 assert-text: (".sidebar > .location", "Module sub_sub_module")
 // We check that we don't have the crate list.
-assert-false: ".sidebar-elems .crate"
-assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Functions")
+assert-false: ".sidebar-elems .crate"
+assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Functions")
 assert-text: ("#functions + .item-table .item-left > a", "foo")
index d5835b78d2fcf17a5d9457c0c9de39a691cd80af..f2e76b546c4affb1afc342703af74856b0f8111e 100644 (file)
@@ -84,3 +84,20 @@ pub mod summary_table {
     /// | content | content |
     pub struct Foo;
 }
+
+pub mod too_long {
+pub type ReallyLongTypeNameLongLongLong = Option<unsafe extern "C" fn(a: *const u8, b: *const u8) -> *const u8>;
+
+pub const ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong: u32 = 0;
+
+pub struct SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName {
+    pub a: u32,
+}
+
+impl SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName {
+    /// ```
+    /// let x = SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName { a: 0 };
+    /// ```
+        pub fn foo(&self) {}
+    }
+}
index 2a147e64d8bf2706f4f137774b07bd79993661aa..14d8b18613087caf1d8c311cc7e4648f17ca109a 100644 (file)
@@ -12,6 +12,7 @@
 ///
 /// ```
 /// println!("nothing fancy");
+/// println!("but with two lines!");
 /// ```
 ///
 /// A failing to compile one:
@@ -123,3 +124,136 @@ pub mod huge_amount_of_consts {
 
 /// Very long code text `hereIgoWithLongTextBecauseWhyNotAndWhyWouldntI`.
 pub mod long_code_block {}
+
+#[macro_export]
+macro_rules! repro {
+    () => {};
+}
+
+pub use crate::repro as repro2;
+
+/// # Top-doc Prose title
+///
+/// Text below title.
+///
+/// ## Top-doc Prose sub-heading
+///
+/// Text below sub-heading.
+///
+/// ### Top-doc Prose sub-sub-heading
+///
+/// Text below sub-sub-heading
+pub struct HeavilyDocumentedStruct {
+    /// # Title for field
+    /// ## Sub-heading for field
+    pub nothing: (),
+}
+
+/// # Title for struct impl doc
+///
+/// Text below heading.
+///
+/// ## Sub-heading for struct impl doc
+///
+/// Text below sub-heading.
+///
+/// ### Sub-sub-heading for struct impl doc
+///
+/// Text below sub-sub-heading.
+///
+impl HeavilyDocumentedStruct {
+    /// # Title for struct impl-item doc
+    /// Text below title.
+    /// ## Sub-heading for struct impl-item doc
+    /// Text below sub-heading.
+    /// ### Sub-sub-heading for struct impl-item doc
+    /// Text below sub-sub-heading.
+    pub fn do_nothing() {}
+}
+
+/// # Top-doc Prose title
+///
+/// Text below title.
+///
+/// ## Top-doc Prose sub-heading
+///
+/// Text below sub-heading.
+///
+/// ### Top-doc Prose sub-sub-heading
+///
+/// Text below sub-sub-heading
+pub enum HeavilyDocumentedEnum {
+    /// # None prose title
+    /// ## None prose sub-heading
+    None,
+    /// # Wrapped prose title
+    /// ## Wrapped prose sub-heading
+    Wrapped(
+        /// # Wrapped.0 prose title
+        /// ## Wrapped.0 prose sub-heading
+        String,
+        String,
+    ),
+    Structy {
+        /// # Structy prose title
+        /// ## Structy prose sub-heading
+        alpha: String,
+        beta: String,
+    },
+}
+
+/// # Title for enum impl doc
+///
+/// Text below heading.
+///
+/// ## Sub-heading for enum impl doc
+///
+/// Text below sub-heading.
+///
+/// ### Sub-sub-heading for enum impl doc
+///
+/// Text below sub-sub-heading.
+///
+impl HeavilyDocumentedEnum {
+    /// # Title for enum impl-item doc
+    /// Text below title.
+    /// ## Sub-heading for enum impl-item doc
+    /// Text below sub-heading.
+    /// ### Sub-sub-heading for enum impl-item doc
+    /// Text below sub-sub-heading.
+    pub fn do_nothing() {}
+}
+
+/// # Top-doc prose title
+///
+/// Text below heading.
+///
+/// ## Top-doc prose sub-heading
+///
+/// Text below heading.
+pub union HeavilyDocumentedUnion {
+    /// # Title for union variant
+    /// ## Sub-heading for union variant
+    pub nothing: (),
+    pub something: f32,
+}
+
+/// # Title for union impl doc
+/// ## Sub-heading for union impl doc
+impl HeavilyDocumentedUnion {
+    /// # Title for union impl-item doc
+    /// ## Sub-heading for union impl-item doc
+    pub fn do_nothing() {}
+}
+
+/// # Top-doc prose title
+///
+/// Text below heading.
+///
+/// ## Top-doc prose sub-heading
+///
+/// Text below heading.
+#[macro_export]
+macro_rules! heavily_documented_macro {
+    () => {};
+}
index 0a316e220a42ce82fcab9b91af5f03d1357c892e..63ab867fb17720c3e8cf8119076732d2f597a33e 100644 (file)
@@ -1,8 +1,25 @@
-// This test ensures that the type declaration content overflow is handled inside the <pre> directly.
+// This test ensures that the items declaration content overflow is handled inside the <pre> directly.
 goto: file://|DOC_PATH|/lib2/long_trait/trait.ALongNameBecauseItHelpsTestingTheCurrentProblem.html
 // We set a fixed size so there is no chance of "random" resize.
 size: (1100, 800)
 // Logically, the <body> scroll width should be the width of the window.
 assert-property: ("body", {"scrollWidth": "1100"})
 // However, since there is overflow in the type declaration, its scroll width is bigger.
-assert-property: (".type-decl pre", {"scrollWidth": "1324"})
+assert-property: (".item-decl pre", {"scrollWidth": "1324"})
+
+// We now make the same check on type declaration...
+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", {"scrollWidth": "840"})
+// And now checking that it has scrollable content.
+assert-property: (".item-decl pre", {"scrollWidth": "1103"})
+
+// ... and constant.
+// On a sidenote, it also checks that the (very) long title isn't changing the docblock width.
+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", {"scrollWidth": "840"})
+// And now checking that it has scrollable content.
+assert-property: (".item-decl pre", {"scrollWidth": "950"})
index 49a80ae2360f542723017c49ab17dee74c724b0d..63a9ad5381244c635e80674ea8eafc11e04bd839 100644 (file)
@@ -1,10 +1,12 @@
 // exact-check
 
 const QUERY = [
-  '"R<P>"',
-  '"P"',
-  'P',
-  '"ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>"',
+    '"R<P>"',
+    '"P"',
+    'P',
+    '"ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>"',
+    'TraitCat',
+    'TraitDog',
 ];
 
 const EXPECTED = [
@@ -30,9 +32,11 @@ const EXPECTED = [
     {
         'returned': [
             { 'path': 'generics', 'name': 'alef' },
+            { 'path': 'generics', 'name': 'bet' },
         ],
         'in_args': [
             { 'path': 'generics', 'name': 'alpha' },
+            { 'path': 'generics', 'name': 'beta' },
         ],
     },
     {
@@ -41,4 +45,14 @@ const EXPECTED = [
         ],
         'returned': [],
     },
+    {
+        'in_args': [
+            { 'path': 'generics', 'name': 'gamma' },
+        ],
+    },
+    {
+        'in_args': [
+            { 'path': 'generics', 'name': 'gamma' },
+        ],
+    },
 ];
index a0dc086e9f9cfe17b55dabf6769ed1c1aa2620f4..5e11a6d6018856f75daaa7e73cc43fe7cd03764e 100644 (file)
@@ -19,3 +19,8 @@ pub fn extracreditlabhomework(
 pub fn redherringmatchforextracredit(
     _param: ExtraCreditStructMulti<ExtraCreditInnerMulti, ()>
 ) { loop {} }
+
+pub trait TraitCat {}
+pub trait TraitDog {}
+
+pub fn gamma<T: TraitCat + TraitDog>(t: T) {}
diff --git a/src/test/rustdoc-json/reexport/macro.rs b/src/test/rustdoc-json/reexport/macro.rs
new file mode 100644 (file)
index 0000000..b86614f
--- /dev/null
@@ -0,0 +1,17 @@
+// edition:2018
+
+#![no_core]
+#![feature(no_core)]
+
+// @count macro.json "$.index[*][?(@.name=='macro')].inner.items[*]" 2
+
+// @set repro_id = macro.json "$.index[*][?(@.name=='repro')].id"
+// @has - "$.index[*][?(@.name=='macro')].inner.items[*]" $repro_id
+#[macro_export]
+macro_rules! repro {
+    () => {};
+}
+
+// @set repro2_id = macro.json "$.index[*][?(@.inner.name=='repro2')].id"
+// @has - "$.index[*][?(@.name=='macro')].inner.items[*]" $repro2_id
+pub use crate::repro as repro2;
index 3ad56aebc21c580b28a4638d53dde913c289fa43..e58bba640585388f4329ce4dba355cc067bead13 100644 (file)
@@ -11,7 +11,6 @@ impl Struct {
     pub const AssocConst: Self::AssocTy = 42;
     //~^ ERROR ambiguous associated type
     //~| HELP use fully-qualified syntax
-    // FIXME: for some reason, the error is shown twice with rustdoc but only once with rustc
     //~| ERROR ambiguous associated type
     //~| HELP use fully-qualified syntax
 }
index 6812a454157b9a98b3ac5bc5ef1d68fb5628665d..315fca195873a233bc8bbb92d2efb932eb6cbeb7 100644 (file)
@@ -11,3 +11,12 @@ pub mod foo {
     //~^ ERROR missing code example in this documentation
     pub fn bar() {}
 }
+
+// This impl is here to ensure the lint isn't emitted for foreign traits implementations.
+impl std::ops::Neg for Foo {
+    type Output = Self;
+
+    fn neg(self) -> Self::Output {
+        Self
+    }
+}
index aac537e9783cd7ae9519e368985dfe7f0516a97d..1c138044165f233fc53eac31c4c3594015f155b0 100644 (file)
@@ -6,7 +6,7 @@ LL | |
 LL | | /// Some docs.
 LL | |
 ...  |
-LL | |     pub fn bar() {}
+LL | |     }
 LL | | }
    | |_^
    |
index 595ece2ea724707527b41ec419903c8182c90b5e..55006b2087eb024f3037bbc638dfbd8f23d8131c 100644 (file)
@@ -29,7 +29,7 @@ LL | pub 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!
    = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
-   = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information
+   = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
 
 error: this attribute can only be applied at the crate level
   --> $DIR/invalid-doc-attr.rs:15:12
@@ -72,7 +72,7 @@ LL |     pub fn baz() {}
    |
    = 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
-   = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information
+   = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/rustdoc-ui/recursive-deref-ice.rs b/src/test/rustdoc-ui/recursive-deref-ice.rs
new file mode 100644 (file)
index 0000000..c44fd27
--- /dev/null
@@ -0,0 +1,19 @@
+// check-pass
+
+// ICE found in https://github.com/rust-lang/rust/issues/83123
+
+pub struct Attribute;
+
+pub struct Map<'hir> {}
+impl<'hir> Map<'hir> {
+    pub fn attrs(&self) -> &'hir [Attribute] { &[] }
+}
+
+pub struct List<T>(T);
+
+impl<T> std::ops::Deref for List<T> {
+    type Target = [T];
+    fn deref(&self) -> &[T] {
+        &[]
+    }
+}
diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs
new file mode 100644 (file)
index 0000000..a1f005c
--- /dev/null
@@ -0,0 +1 @@
+// compile-flags: -Z unstable-options --scrape-examples-target-crate foobar
diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr
new file mode 100644 (file)
index 0000000..eb8e9f7
--- /dev/null
@@ -0,0 +1,2 @@
+error: must use --scrape-examples-output-path and --scrape-examples-target-crate together
+
diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs
new file mode 100644 (file)
index 0000000..4aacec7
--- /dev/null
@@ -0,0 +1 @@
+// compile-flags: -Z unstable-options --scrape-examples-output-path ex.calls
diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr
new file mode 100644 (file)
index 0000000..eb8e9f7
--- /dev/null
@@ -0,0 +1,2 @@
+error: must use --scrape-examples-output-path and --scrape-examples-target-crate together
+
index 6a588fbd56e75945b2c5ae02936d8e5a99084f7f..1c7f4b7241893b8f705862a7064586db1a55c875 100644 (file)
@@ -8,6 +8,6 @@ pub extern "C" fn f() {}
 #[export_name = "bar"]
 pub extern "C" fn g() {}
 
-// @has foo/struct.Repr.html '//*[@class="docblock type-decl"]' '#[repr(C, align(8))]'
+// @has foo/struct.Repr.html '//*[@class="docblock item-decl"]' '#[repr(C, align(8))]'
 #[repr(C, align(8))]
 pub struct Repr;
diff --git a/src/test/rustdoc/deref-recursive-pathbuf.rs b/src/test/rustdoc/deref-recursive-pathbuf.rs
new file mode 100644 (file)
index 0000000..9ab338c
--- /dev/null
@@ -0,0 +1,25 @@
+// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
+// levels and across multiple crates.
+// For `Deref` on non-foreign types, look at `deref-recursive.rs`.
+
+// @has 'foo/struct.Foo.html'
+// @has '-' '//*[@id="deref-methods-PathBuf"]' 'Methods from Deref<Target = PathBuf>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.as_path"]' 'pub fn as_path(&self)'
+// @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
+// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.as_path"]' 'as_path'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>'
+// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.exists"]' 'exists'
+
+#![crate_name = "foo"]
+
+use std::ops::Deref;
+use std::path::PathBuf;
+
+pub struct Foo(PathBuf);
+
+impl Deref for Foo {
+    type Target = PathBuf;
+    fn deref(&self) -> &PathBuf { &self.0 }
+}
diff --git a/src/test/rustdoc/deref-recursive.rs b/src/test/rustdoc/deref-recursive.rs
new file mode 100644 (file)
index 0000000..c07e048
--- /dev/null
@@ -0,0 +1,41 @@
+// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
+// levels if needed.
+// For `Deref` on foreign types, look at `deref-recursive-pathbuf.rs`.
+
+// @has 'foo/struct.Foo.html'
+// @has '-' '//*[@id="deref-methods-Bar"]' 'Methods from Deref<Target = Bar>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.bar"]' 'pub fn bar(&self)'
+// @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
+// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.bar"]' 'bar'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>'
+// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.baz"]' 'baz'
+
+#![crate_name = "foo"]
+
+use std::ops::Deref;
+
+pub struct Foo(Bar);
+pub struct Bar(Baz);
+pub struct Baz;
+
+impl Deref for Foo {
+    type Target = Bar;
+    fn deref(&self) -> &Bar { &self.0 }
+}
+
+impl Deref for Bar {
+    type Target = Baz;
+    fn deref(&self) -> &Baz { &self.0 }
+}
+
+impl Bar {
+    /// This appears under `Foo` methods
+    pub fn bar(&self) {}
+}
+
+impl Baz {
+    /// This should also appear in `Foo` methods when recursing
+    pub fn baz(&self) {}
+}
index d42ff384b29b83863eb9b9aa81600bb74930d634..ad7a96c5dad1fc7c6ce37cc1746c13b7387b85d7 100644 (file)
@@ -1,12 +1,12 @@
 #![crate_name = "foo"]
 
 // @has 'foo/struct.Bar.html'
-// @has '-' '//*[@id="deref-methods"]' 'Methods from Deref<Target = FooJ>'
+// @has '-' '//*[@id="deref-methods-FooJ"]' 'Methods from Deref<Target = FooJ>'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_a"]' 'pub fn foo_a(&self)'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)'
-// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods"]' 'Methods from Deref<Target=FooJ>'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
 // @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_a"]' 'foo_a'
 // @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_b"]' 'foo_b'
 // @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_c"]' 'foo_c'
diff --git a/src/test/rustdoc/doc-auto-cfg.rs b/src/test/rustdoc/doc-auto-cfg.rs
new file mode 100644 (file)
index 0000000..fcdd835
--- /dev/null
@@ -0,0 +1,8 @@
+#![feature(doc_auto_cfg)]
+
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-test'
+#[cfg(not(test))]
+pub fn foo() {}
index b9d0d32313723ddb1128b563e33237881ef7ab11..424fa6d6a911fac841884f3d302fcb7a0805ed6c 100644 (file)
@@ -1,5 +1,5 @@
 #![crate_name = "oud"]
-#![feature(doc_cfg, doc_cfg_hide)]
+#![feature(doc_auto_cfg, doc_cfg, doc_cfg_hide)]
 
 #![doc(cfg_hide(feature = "solecism"))]
 
index 36c2025785d0f87a8e76915fe7fcd3ce897b4fe8..5d17a4ede6adcb16da2a182c0abe50e36b64132f 100644 (file)
@@ -1,5 +1,5 @@
 #![crate_name = "funambulism"]
-#![feature(doc_cfg)]
+#![feature(doc_auto_cfg, doc_cfg)]
 
 // @has 'funambulism/struct.Disorbed.html'
 // @count   - '//*[@class="stab portability"]' 1
diff --git a/src/test/rustdoc/feature-gate-doc_auto_cfg.rs b/src/test/rustdoc/feature-gate-doc_auto_cfg.rs
new file mode 100644 (file)
index 0000000..da76381
--- /dev/null
@@ -0,0 +1,8 @@
+#![feature(doc_cfg)]
+
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @count - '//*[@class="item-info"]/*[@class="stab portability"]' 0
+#[cfg(not(test))]
+pub fn foo() {}
diff --git a/src/test/rustdoc/issue-89852.rs b/src/test/rustdoc/issue-89852.rs
new file mode 100644 (file)
index 0000000..45544db
--- /dev/null
@@ -0,0 +1,14 @@
+// edition:2018
+
+#![no_core]
+#![feature(no_core)]
+
+// @matches 'issue_89852/sidebar-items.js' '"repro"'
+// @!matches 'issue_89852/sidebar-items.js' '"repro".*"repro"'
+
+#[macro_export]
+macro_rules! repro {
+    () => {};
+}
+
+pub use crate::repro as repro2;
index fcb636ade8f7ad2729ae0f9786b005ba401ef6ed..65a7debc2538dd8e1804d0a302956a0e60fe5c2c 100644 (file)
@@ -15,7 +15,7 @@ impl Deref for A {
     fn deref(&self) -> &B { todo!() }
 }
 
-// @!has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_c'
+// @has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_c'
 impl Deref for B {
     type Target = C;
     fn deref(&self) -> &C { todo!() }
index 3d17bce472154e7de09411c3ab85e27b633edcf4..a7504fbccfb508f9384b13b551698a2fc59fd2cc 100644 (file)
@@ -1,9 +1,16 @@
 use std::ops::Deref;
 
+// Cyclic deref with the parent (which is not the top parent).
 pub struct A;
 pub struct B;
+pub struct C;
+
+impl C {
+    pub fn c(&self) {}
+}
 
 // @has recursive_deref/struct.A.html '//h3[@class="code-header in-band"]' 'impl Deref for A'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.c"]' 'pub fn c(&self)'
 impl Deref for A {
     type Target = B;
 
@@ -13,8 +20,99 @@ fn deref(&self) -> &Self::Target {
 }
 
 // @has recursive_deref/struct.B.html '//h3[@class="code-header in-band"]' 'impl Deref for B'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.c"]' 'pub fn c(&self)'
 impl Deref for B {
-    type Target = A;
+    type Target = C;
+
+    fn deref(&self) -> &Self::Target {
+        panic!()
+    }
+}
+
+// @has recursive_deref/struct.C.html '//h3[@class="code-header in-band"]' 'impl Deref for C'
+impl Deref for C {
+    type Target = B;
+
+    fn deref(&self) -> &Self::Target {
+        panic!()
+    }
+}
+
+// Cyclic deref with the grand-parent (which is not the top parent).
+pub struct D;
+pub struct E;
+pub struct F;
+pub struct G;
+
+impl G {
+    // There is no "self" parameter so it shouldn't be listed!
+    pub fn g() {}
+}
+
+// @has recursive_deref/struct.D.html '//h3[@class="code-header in-band"]' 'impl Deref for D'
+// We also check that `G::g` method isn't rendered because there is no `self` argument.
+// @!has '-' '//*[@id="deref-methods-G"]'
+impl Deref for D {
+    type Target = E;
+
+    fn deref(&self) -> &Self::Target {
+        panic!()
+    }
+}
+
+// @has recursive_deref/struct.E.html '//h3[@class="code-header in-band"]' 'impl Deref for E'
+// We also check that `G::g` method isn't rendered because there is no `self` argument.
+// @!has '-' '//*[@id="deref-methods-G"]'
+impl Deref for E {
+    type Target = F;
+
+    fn deref(&self) -> &Self::Target {
+        panic!()
+    }
+}
+
+// @has recursive_deref/struct.F.html '//h3[@class="code-header in-band"]' 'impl Deref for F'
+// We also check that `G::g` method isn't rendered because there is no `self` argument.
+// @!has '-' '//*[@id="deref-methods-G"]'
+impl Deref for F {
+    type Target = G;
+
+    fn deref(&self) -> &Self::Target {
+        panic!()
+    }
+}
+
+// @has recursive_deref/struct.G.html '//h3[@class="code-header in-band"]' 'impl Deref for G'
+impl Deref for G {
+    type Target = E;
+
+    fn deref(&self) -> &Self::Target {
+        panic!()
+    }
+}
+
+// Cyclic deref with top parent.
+pub struct H;
+pub struct I;
+
+impl I {
+    // There is no "self" parameter so it shouldn't be listed!
+    pub fn i() {}
+}
+
+// @has recursive_deref/struct.H.html '//h3[@class="code-header in-band"]' 'impl Deref for H'
+// @!has '-' '//*[@id="deref-methods-I"]'
+impl Deref for H {
+    type Target = I;
+
+    fn deref(&self) -> &Self::Target {
+        panic!()
+    }
+}
+
+// @has recursive_deref/struct.I.html '//h3[@class="code-header in-band"]' 'impl Deref for I'
+impl Deref for I {
+    type Target = H;
 
     fn deref(&self) -> &Self::Target {
         panic!()
index ff7424033aa49c46135a8875c98ec9d8df75badf..509457f6c9649610b4200fb4cf69886ac0a7bed8 100644 (file)
@@ -5,25 +5,25 @@
 
 extern crate reexports;
 
-// @has 'foo/macro.addr_of.html' '//*[@class="docblock type-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' '//*[@class="docblock type-decl"]' 'pub(crate) macro addr_of_crate($place : expr) {'
+// @has 'foo/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/macro.addr_of_self.html' '//*[@class="docblock type-decl"]' 'pub(crate) macro addr_of_self($place : expr) {'
+// @has 'foo/macro.addr_of_self.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_self($place : expr) {'
 pub(self) use reexports::addr_of_self;
 
-// @has 'foo/struct.Foo.html' '//*[@class="docblock type-decl"]' 'pub struct Foo;'
+// @has 'foo/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;'
 pub use reexports::Foo;
-// @has 'foo/struct.FooCrate.html' '//*[@class="docblock type-decl"]' 'pub(crate) struct FooCrate;'
+// @has 'foo/struct.FooCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) struct FooCrate;'
 pub(crate) use reexports::FooCrate;
-// @has 'foo/struct.FooSelf.html' '//*[@class="docblock type-decl"]' 'pub(crate) struct FooSelf;'
+// @has 'foo/struct.FooSelf.html' '//*[@class="docblock item-decl"]' 'pub(crate) struct FooSelf;'
 pub(self) use reexports::FooSelf;
 
-// @has 'foo/enum.Bar.html' '//*[@class="docblock type-decl"]' 'pub enum Bar {'
+// @has 'foo/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {'
 pub use reexports::Bar;
-// @has 'foo/enum.BarCrate.html' '//*[@class="docblock type-decl"]' 'pub(crate) enum BarCrate {'
+// @has 'foo/enum.BarCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) enum BarCrate {'
 pub(crate) use reexports::BarCrate;
-// @has 'foo/enum.BarSelf.html' '//*[@class="docblock type-decl"]' 'pub(crate) enum BarSelf {'
+// @has 'foo/enum.BarSelf.html' '//*[@class="docblock item-decl"]' 'pub(crate) enum BarSelf {'
 pub(self) use reexports::BarSelf;
 
 // @has 'foo/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
 // @has 'foo/type.TypeSelf.html' '//*[@class="rust typedef"]' 'pub(crate) type TypeSelf ='
 pub(self) use reexports::TypeSelf;
 
-// @has 'foo/union.Union.html' '//*[@class="docblock type-decl"]' 'pub union Union {'
+// @has 'foo/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {'
 pub use reexports::Union;
-// @has 'foo/union.UnionCrate.html' '//*[@class="docblock type-decl"]' 'pub(crate) union UnionCrate {'
+// @has 'foo/union.UnionCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) union UnionCrate {'
 pub(crate) use reexports::UnionCrate;
-// @has 'foo/union.UnionSelf.html' '//*[@class="docblock type-decl"]' 'pub(crate) union UnionSelf {'
+// @has 'foo/union.UnionSelf.html' '//*[@class="docblock item-decl"]' 'pub(crate) union UnionSelf {'
 pub(self) use reexports::UnionSelf;
 
 pub mod foo {
index ab4c5bc74390784b2b32d9071a20e0d3293506fa..c308d0c2f05cf49db8f5fc2be4026ffa9a29b74b 100644 (file)
@@ -4,21 +4,21 @@
 
 extern crate reexports;
 
-// @has 'foo/macro.addr_of.html' '//*[@class="docblock type-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;
 // @!has 'foo/macro.addr_of_self.html'
 pub(self) use reexports::addr_of_self;
 
-// @has 'foo/struct.Foo.html' '//*[@class="docblock type-decl"]' 'pub struct Foo;'
+// @has 'foo/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;'
 pub use reexports::Foo;
 // @!has 'foo/struct.FooCrate.html'
 pub(crate) use reexports::FooCrate;
 // @!has 'foo/struct.FooSelf.html'
 pub(self) use reexports::FooSelf;
 
-// @has 'foo/enum.Bar.html' '//*[@class="docblock type-decl"]' 'pub enum Bar {'
+// @has 'foo/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {'
 pub use reexports::Bar;
 // @!has 'foo/enum.BarCrate.html'
 pub(crate) use reexports::BarCrate;
@@ -39,7 +39,7 @@
 // @!has 'foo/type.TypeSelf.html'
 pub(self) use reexports::TypeSelf;
 
-// @has 'foo/union.Union.html' '//*[@class="docblock type-decl"]' 'pub union Union {'
+// @has 'foo/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {'
 pub use reexports::Union;
 // @!has 'foo/union.UnionCrate.html'
 pub(crate) use reexports::UnionCrate;
index ae871e79d7f6b0b62e24abed3d2c667962c03683..937646987dd4f2c5532bd4e562ef67d3fbac1347 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 type-decl"]' 'fields omitted'
+// @has - '//div[@class="docblock item-decl"]' 'fields omitted'
 pub struct PrivStruct {
     a: usize,
     b: usize,
index 6cd4a1a0afa085e89f210d1c46138fda15f1194a..c9fccf5a77cde6d31986f42812bc12a05a8165bb 100644 (file)
 // @has foo/index.html '//a[@class="traitalias"]' 'Alias2'
 // @has foo/index.html '//a[@class="traitalias"]' 'Foo'
 
-// @has foo/traitalias.CopyAlias.html '//section[@id="main"]/pre' 'trait CopyAlias = Copy;'
+// @has foo/traitalias.CopyAlias.html
+// @has - '//section[@id="main"]/div[@class="docblock item-decl"]/pre' 'trait CopyAlias = Copy;'
 pub trait CopyAlias = Copy;
-// @has foo/traitalias.Alias2.html '//section[@id="main"]/pre' 'trait Alias2 = Copy + Debug;'
+// @has foo/traitalias.Alias2.html
+// @has - '//section[@id="main"]/div[@class="docblock item-decl"]/pre' 'trait Alias2 = Copy + Debug;'
 pub trait Alias2 = Copy + Debug;
-// @has foo/traitalias.Foo.html '//section[@id="main"]/pre' 'trait Foo<T> = Into<T> + Debug;'
+// @has foo/traitalias.Foo.html
+// @has - '//section[@id="main"]/div[@class="docblock item-decl"]/pre' 'trait Foo<T> = Into<T> + Debug;'
 pub trait Foo<T> = Into<T> + Debug;
 // @has foo/fn.bar.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
 pub fn bar<T>() where T: Alias2 {}
index 225d49e05a3fa49fef67994992f726d6c772bbcf..a948947dbdb610df2e36d4d6193f6fc70f03d107 100644 (file)
@@ -40,25 +40,22 @@ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
 LL | extern "x86-interrupt" fn x86() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: use of calling convention not supported on this target
+error[E0570]: `"thiscall"` is not a supported ABI for the current target
   --> $DIR/unsupported.rs:43:1
    |
-LL | extern "stdcall" fn stdcall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
+LL | extern "thiscall" fn thiscall() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:50:1
+  --> $DIR/unsupported.rs:47:1
    |
-LL | extern "thiscall" fn thiscall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "stdcall" fn stdcall() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
 
-error: aborting due to 7 previous errors; 2 warnings emitted
+error: aborting due to 8 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0570`.
index b050ee0aa3148501b5bc94661152b5d2a07633b3..297354c28289569d064fd1e0f42fd81e4b522aab 100644 (file)
@@ -34,25 +34,22 @@ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
 LL | extern "x86-interrupt" fn x86() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: use of calling convention not supported on this target
+error[E0570]: `"thiscall"` is not a supported ABI for the current target
   --> $DIR/unsupported.rs:43:1
    |
-LL | extern "stdcall" fn stdcall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
+LL | extern "thiscall" fn thiscall() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:50:1
+  --> $DIR/unsupported.rs:47:1
    |
-LL | extern "thiscall" fn thiscall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "stdcall" fn stdcall() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
 
-error: aborting due to 6 previous errors; 2 warnings emitted
+error: aborting due to 7 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0570`.
index 9319eac8d30d84bd84be935d7bd7fe0ba49fe17d..6427a5695c0297c032f5d2601da51e91654b60cc 100644 (file)
@@ -40,14 +40,11 @@ extern "avr-interrupt" fn avr() {}
 extern "x86-interrupt" fn x86() {}
 //[aarch64]~^ ERROR is not a supported ABI
 //[arm]~^^ ERROR is not a supported ABI
-extern "stdcall" fn stdcall() {}
-//[x64]~^ WARN use of calling convention not supported
-//[x64]~^^ WARN this was previously accepted
-//[aarch64]~^^^ WARN use of calling convention not supported
-//[aarch64]~^^^^ WARN this was previously accepted
-//[arm]~^^^^^ WARN use of calling convention not supported
-//[arm]~^^^^^^ WARN this was previously accepted
 extern "thiscall" fn thiscall() {}
+//[x64]~^ ERROR is not a supported ABI
+//[aarch64]~^^ ERROR is not a supported ABI
+//[arm]~^^^ ERROR is not a supported ABI
+extern "stdcall" fn stdcall() {}
 //[x64]~^ WARN use of calling convention not supported
 //[x64]~^^ WARN this was previously accepted
 //[aarch64]~^^^ WARN use of calling convention not supported
index f2f52683324dba69576e9759aa00e298d88a7c3c..49b88cd3fac939c559b2bfda5d4ad4fba8024aa3 100644 (file)
@@ -34,25 +34,22 @@ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: use of calling convention not supported on this target
+error[E0570]: `"thiscall"` is not a supported ABI for the current target
   --> $DIR/unsupported.rs:43:1
    |
-LL | extern "stdcall" fn stdcall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
+LL | extern "thiscall" fn thiscall() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:50:1
+  --> $DIR/unsupported.rs:47:1
    |
-LL | extern "thiscall" fn thiscall() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "stdcall" fn stdcall() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
 
-error: aborting due to 6 previous errors; 2 warnings emitted
+error: aborting due to 7 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0570`.
index 906dcb0ebab982777589fd38979e14b44255a2da..05165b2d46c0dd3eb85fccd5dd7711d57592b269 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // only-aarch64
 // run-pass
 // revisions: mirunsafeck thirunsafeck
index 58feb52653740e6445bbec213fa65429f4651382..143ed1824039c91b4fb91ad789a6a600659e5d0a 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // only-aarch64
 // build-fail
 // compile-flags: -Ccodegen-units=1
index 96dab1bce0b758d1097ed7595945207ffca5936d..f03fbf28d3184f55ae9d618025fd7287422d28c9 100644 (file)
@@ -1,5 +1,5 @@
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:11:15
+  --> $DIR/srcloc.rs:10:15
    |
 LL |         asm!("invalid_instruction");
    |               ^
@@ -11,7 +11,7 @@ LL |     invalid_instruction
    |     ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:15:13
+  --> $DIR/srcloc.rs:14:13
    |
 LL |             invalid_instruction
    |             ^
@@ -23,7 +23,7 @@ LL |             invalid_instruction
    |             ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:20:13
+  --> $DIR/srcloc.rs:19:13
    |
 LL |             invalid_instruction
    |             ^
@@ -35,7 +35,7 @@ LL |             invalid_instruction
    |             ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:26:13
+  --> $DIR/srcloc.rs:25:13
    |
 LL |             invalid_instruction
    |             ^
@@ -47,7 +47,7 @@ LL |             invalid_instruction
    |             ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:33:13
+  --> $DIR/srcloc.rs:32:13
    |
 LL |             invalid_instruction
    |             ^
@@ -59,7 +59,7 @@ LL |             invalid_instruction
    |             ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:38:14
+  --> $DIR/srcloc.rs:37:14
    |
 LL |         asm!(concat!("invalid", "_", "instruction"));
    |              ^
@@ -71,7 +71,7 @@ LL |     invalid_instruction
    |     ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:42:14
+  --> $DIR/srcloc.rs:41:14
    |
 LL |             "invalid_instruction",
    |              ^
@@ -83,7 +83,7 @@ LL |     invalid_instruction
    |     ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:48:14
+  --> $DIR/srcloc.rs:47:14
    |
 LL |             "invalid_instruction",
    |              ^
@@ -95,7 +95,7 @@ LL | invalid_instruction
    | ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:55:14
+  --> $DIR/srcloc.rs:54:14
    |
 LL |             "invalid_instruction",
    |              ^
@@ -107,7 +107,7 @@ LL | invalid_instruction
    | ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:62:13
+  --> $DIR/srcloc.rs:61:13
    |
 LL |             concat!("invalid", "_", "instruction"),
    |             ^
@@ -119,7 +119,7 @@ LL | invalid_instruction
    | ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:69:13
+  --> $DIR/srcloc.rs:68:13
    |
 LL |             concat!("invalid", "_", "instruction"),
    |             ^
@@ -131,7 +131,7 @@ LL | invalid_instruction
    | ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:76:14
+  --> $DIR/srcloc.rs:75:14
    |
 LL |             "invalid_instruction1",
    |              ^
@@ -143,7 +143,7 @@ LL |     invalid_instruction1
    |     ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:77:14
+  --> $DIR/srcloc.rs:76:14
    |
 LL |             "invalid_instruction2",
    |              ^
@@ -155,7 +155,7 @@ LL | invalid_instruction2
    | ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:83:13
+  --> $DIR/srcloc.rs:82:13
    |
 LL |             concat!(
    |             ^
@@ -167,7 +167,7 @@ LL |     invalid_instruction1
    |     ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:83:13
+  --> $DIR/srcloc.rs:82:13
    |
 LL |             concat!(
    |             ^
@@ -179,7 +179,7 @@ LL | invalid_instruction2
    | ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:92:13
+  --> $DIR/srcloc.rs:91:13
    |
 LL |             concat!(
    |             ^
@@ -191,7 +191,7 @@ LL |     invalid_instruction1
    |     ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:92:13
+  --> $DIR/srcloc.rs:91:13
    |
 LL |             concat!(
    |             ^
@@ -203,7 +203,7 @@ LL | invalid_instruction2
    | ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:96:13
+  --> $DIR/srcloc.rs:95:13
    |
 LL |             concat!(
    |             ^
@@ -215,7 +215,7 @@ LL | invalid_instruction3
    | ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:96:13
+  --> $DIR/srcloc.rs:95:13
    |
 LL |             concat!(
    |             ^
@@ -227,7 +227,7 @@ LL | invalid_instruction4
    | ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:107:13
+  --> $DIR/srcloc.rs:106:13
    |
 LL |             concat!(
    |             ^
@@ -239,7 +239,7 @@ LL |     invalid_instruction1
    |     ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:107:13
+  --> $DIR/srcloc.rs:106:13
    |
 LL |             concat!(
    |             ^
@@ -251,7 +251,7 @@ LL | invalid_instruction2
    | ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:111:13
+  --> $DIR/srcloc.rs:110:13
    |
 LL |             concat!(
    |             ^
@@ -263,7 +263,7 @@ LL | invalid_instruction3
    | ^
 
 error: unrecognized instruction mnemonic
-  --> $DIR/srcloc.rs:111:13
+  --> $DIR/srcloc.rs:110:13
    |
 LL |             concat!(
    |             ^
index 6fd1192eec6e030faa4a1d4d8f24f0594f58bd68..526555334cb882cd1cf2c5d97ef225bab56974fc 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // only-aarch64
 // only-linux
 // run-pass
index d4de9abb8caf08a51531274721f73e896d289ffc..dbf17755720829516155af2e69b864d2952e92ec 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // only-x86_64
 // run-pass
 // revisions: mirunsafeck thirunsafeck
diff --git a/src/test/ui/asm/x86_64/issue-89875.rs b/src/test/ui/asm/x86_64/issue-89875.rs
new file mode 100644 (file)
index 0000000..9b2b21b
--- /dev/null
@@ -0,0 +1,14 @@
+// build-pass
+// only-x86_64
+
+#![feature(asm, target_feature_11)]
+
+#[target_feature(enable = "avx")]
+fn main() {
+    unsafe {
+        asm!(
+            "/* {} */",
+            out(ymm_reg) _,
+        );
+    }
+}
index ed8cefc58b727e8f4b793f2761844ebc4d59abc9..c4ccfb8016a7798e7bf87178a61ecf9d9f71fc47 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // only-x86_64
 // build-fail
 // compile-flags: -Ccodegen-units=1
index b62c8948289ddf1bf55575457bdc2e178c99d50c..77894657292fbb8e40d24488b952192d9c94017e 100644 (file)
@@ -1,5 +1,5 @@
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:11:15
+  --> $DIR/srcloc.rs:10:15
    |
 LL |         asm!("invalid_instruction");
    |               ^
@@ -11,7 +11,7 @@ LL |     invalid_instruction
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:15:13
+  --> $DIR/srcloc.rs:14:13
    |
 LL |             invalid_instruction
    |             ^
@@ -23,7 +23,7 @@ LL |             invalid_instruction
    |             ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:20:13
+  --> $DIR/srcloc.rs:19:13
    |
 LL |             invalid_instruction
    |             ^
@@ -35,7 +35,7 @@ LL |             invalid_instruction
    |             ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:26:13
+  --> $DIR/srcloc.rs:25:13
    |
 LL |             invalid_instruction
    |             ^
@@ -47,7 +47,7 @@ LL |             invalid_instruction
    |             ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:33:13
+  --> $DIR/srcloc.rs:32:13
    |
 LL |             invalid_instruction
    |             ^
@@ -59,7 +59,7 @@ LL |             invalid_instruction
    |             ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:38:14
+  --> $DIR/srcloc.rs:37:14
    |
 LL |         asm!(concat!("invalid", "_", "instruction"));
    |              ^
@@ -71,7 +71,7 @@ LL |     invalid_instruction
    |     ^^^^^^^^^^^^^^^^^^^
 
 warning: scale factor without index register is ignored
-  --> $DIR/srcloc.rs:41:15
+  --> $DIR/srcloc.rs:40:15
    |
 LL |         asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
    |               ^
@@ -83,7 +83,7 @@ LL |     movaps %xmm3, (%esi, 2)
    |                          ^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:45:14
+  --> $DIR/srcloc.rs:44:14
    |
 LL |             "invalid_instruction",
    |              ^
@@ -95,7 +95,7 @@ LL |     invalid_instruction
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:51:14
+  --> $DIR/srcloc.rs:50:14
    |
 LL |             "invalid_instruction",
    |              ^
@@ -107,7 +107,7 @@ LL | invalid_instruction
    | ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:58:14
+  --> $DIR/srcloc.rs:57:14
    |
 LL |             "invalid_instruction",
    |              ^
@@ -119,7 +119,7 @@ LL | invalid_instruction
    | ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:65:13
+  --> $DIR/srcloc.rs:64:13
    |
 LL |             concat!("invalid", "_", "instruction"),
    |             ^
@@ -131,7 +131,7 @@ LL | invalid_instruction
    | ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:72:13
+  --> $DIR/srcloc.rs:71:13
    |
 LL |             concat!("invalid", "_", "instruction"),
    |             ^
@@ -143,7 +143,7 @@ LL | invalid_instruction
    | ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction1'
-  --> $DIR/srcloc.rs:79:14
+  --> $DIR/srcloc.rs:78:14
    |
 LL |             "invalid_instruction1",
    |              ^
@@ -155,7 +155,7 @@ LL |     invalid_instruction1
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction2'
-  --> $DIR/srcloc.rs:80:14
+  --> $DIR/srcloc.rs:79:14
    |
 LL |             "invalid_instruction2",
    |              ^
@@ -167,7 +167,7 @@ LL | invalid_instruction2
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction1'
-  --> $DIR/srcloc.rs:86:13
+  --> $DIR/srcloc.rs:85:13
    |
 LL |             concat!(
    |             ^
@@ -179,7 +179,7 @@ LL |     invalid_instruction1
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction2'
-  --> $DIR/srcloc.rs:86:13
+  --> $DIR/srcloc.rs:85:13
    |
 LL |             concat!(
    |             ^
@@ -191,7 +191,7 @@ LL | invalid_instruction2
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction1'
-  --> $DIR/srcloc.rs:95:13
+  --> $DIR/srcloc.rs:94:13
    |
 LL |             concat!(
    |             ^
@@ -203,7 +203,7 @@ LL |     invalid_instruction1
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction2'
-  --> $DIR/srcloc.rs:95:13
+  --> $DIR/srcloc.rs:94:13
    |
 LL |             concat!(
    |             ^
@@ -215,7 +215,7 @@ LL | invalid_instruction2
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction3'
-  --> $DIR/srcloc.rs:99:13
+  --> $DIR/srcloc.rs:98:13
    |
 LL |             concat!(
    |             ^
@@ -227,7 +227,7 @@ LL | invalid_instruction3
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction4'
-  --> $DIR/srcloc.rs:99:13
+  --> $DIR/srcloc.rs:98:13
    |
 LL |             concat!(
    |             ^
@@ -239,7 +239,7 @@ LL | invalid_instruction4
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction1'
-  --> $DIR/srcloc.rs:110:13
+  --> $DIR/srcloc.rs:109:13
    |
 LL |             concat!(
    |             ^
@@ -251,7 +251,7 @@ LL |     invalid_instruction1
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction2'
-  --> $DIR/srcloc.rs:110:13
+  --> $DIR/srcloc.rs:109:13
    |
 LL |             concat!(
    |             ^
@@ -263,7 +263,7 @@ LL | invalid_instruction2
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction3'
-  --> $DIR/srcloc.rs:114:13
+  --> $DIR/srcloc.rs:113:13
    |
 LL |             concat!(
    |             ^
@@ -275,7 +275,7 @@ LL | invalid_instruction3
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction4'
-  --> $DIR/srcloc.rs:114:13
+  --> $DIR/srcloc.rs:113:13
    |
 LL |             concat!(
    |             ^
index 634ef010e6feaa96405a8ac6c5807711314b51cf..188d03e298e0182b734bb4dce9d5091aaef89589 100644 (file)
@@ -1,4 +1,4 @@
-// min-llvm-version: 10.0.1
+// min-llvm-version: 12.0.1
 // only-x86_64
 // only-linux
 // run-pass
index 912dedfdcebbc3b220401347f2191c494eb02f5a..c993e1d27202d5a53ac33f843623d48b8bd24852 100644 (file)
@@ -28,11 +28,13 @@ pub fn f1_int_uint() {
 pub fn f1_uint_uint() {
     f1(2u32, 4u32);
     //~^ ERROR `u32: Foo` is not satisfied
+    //~| ERROR `u32: Foo` is not satisfied
 }
 
 pub fn f1_uint_int() {
     f1(2u32, 4i32);
     //~^ ERROR `u32: Foo` is not satisfied
+    //~| ERROR `u32: Foo` is not satisfied
 }
 
 pub fn f2_int() {
index 15a5245d54d9577c52a6350962400918138c6670..b3bb58f78142af7f159280f0f9e3bdb29e37dc92 100644 (file)
@@ -10,12 +10,10 @@ LL |     f1(2i32, 4u32);
    |               ~~~
 
 error[E0277]: the trait bound `u32: Foo` is not satisfied
-  --> $DIR/associated-types-path-2.rs:29:14
+  --> $DIR/associated-types-path-2.rs:29:5
    |
 LL |     f1(2u32, 4u32);
-   |     --       ^^^^ the trait `Foo` is not implemented for `u32`
-   |     |
-   |     required by a bound introduced by this call
+   |     ^^ the trait `Foo` is not implemented for `u32`
    |
 note: required by a bound in `f1`
   --> $DIR/associated-types-path-2.rs:13:14
@@ -24,10 +22,16 @@ LL | pub fn f1<T: Foo>(a: T, x: T::A) {}
    |              ^^^ required by this bound in `f1`
 
 error[E0277]: the trait bound `u32: Foo` is not satisfied
-  --> $DIR/associated-types-path-2.rs:34:14
+  --> $DIR/associated-types-path-2.rs:29:14
+   |
+LL |     f1(2u32, 4u32);
+   |              ^^^^ the trait `Foo` is not implemented for `u32`
+
+error[E0277]: the trait bound `u32: Foo` is not satisfied
+  --> $DIR/associated-types-path-2.rs:35:8
    |
 LL |     f1(2u32, 4i32);
-   |     --       ^^^^ the trait `Foo` is not implemented for `u32`
+   |     -- ^^^^ the trait `Foo` is not implemented for `u32`
    |     |
    |     required by a bound introduced by this call
    |
@@ -37,8 +41,14 @@ note: required by a bound in `f1`
 LL | pub fn f1<T: Foo>(a: T, x: T::A) {}
    |              ^^^ required by this bound in `f1`
 
+error[E0277]: the trait bound `u32: Foo` is not satisfied
+  --> $DIR/associated-types-path-2.rs:35:14
+   |
+LL |     f1(2u32, 4i32);
+   |              ^^^^ the trait `Foo` is not implemented for `u32`
+
 error[E0308]: mismatched types
-  --> $DIR/associated-types-path-2.rs:39:18
+  --> $DIR/associated-types-path-2.rs:41:18
    |
 LL |     let _: i32 = f2(2i32);
    |            ---   ^^^^^^^^ expected `i32`, found `u32`
@@ -50,7 +60,7 @@ help: you can convert a `u32` to an `i32` and panic if the converted value doesn
 LL |     let _: i32 = f2(2i32).try_into().unwrap();
    |                          ++++++++++++++++++++
 
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0277, E0308.
 For more information about an error, try `rustc --explain E0277`.
index d509ff3598b50f4a2e9f0f7b7b75bf50206bec43..baaab7fee679dcdfed20ed7419e2adb25dd4e27c 100644 (file)
@@ -1,8 +1,8 @@
 error: future cannot be sent between threads safely
-  --> $DIR/async-fn-nonsend.rs:49:5
+  --> $DIR/async-fn-nonsend.rs:49:17
    |
 LL |     assert_send(local_dropped_before_await());
-   |     ^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
    |
    = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`
 note: future is not `Send` as this value is used across an await
@@ -22,10 +22,10 @@ LL | fn assert_send(_: impl Send) {}
    |                        ^^^^ required by this bound in `assert_send`
 
 error: future cannot be sent between threads safely
-  --> $DIR/async-fn-nonsend.rs:51:5
+  --> $DIR/async-fn-nonsend.rs:51:17
    |
 LL |     assert_send(non_send_temporary_in_match());
-   |     ^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
    |
    = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`
 note: future is not `Send` as this value is used across an await
@@ -45,10 +45,10 @@ LL | fn assert_send(_: impl Send) {}
    |                        ^^^^ required by this bound in `assert_send`
 
 error: future cannot be sent between threads safely
-  --> $DIR/async-fn-nonsend.rs:53:5
+  --> $DIR/async-fn-nonsend.rs:53:17
    |
 LL |     assert_send(non_sync_with_method_call());
-   |     ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
    |
    = help: the trait `Send` is not implemented for `dyn std::fmt::Write`
 note: future is not `Send` as this value is used across an await
index 69c7ff47456c0846dc73fca9eb1da5f02d3208db..12e4bfc3d48b66b05fb91b238270a5e4dd429b81 100644 (file)
@@ -1,8 +1,8 @@
 error: future cannot be shared between threads safely
-  --> $DIR/issue-64130-1-sync.rs:21:5
+  --> $DIR/issue-64130-1-sync.rs:21:13
    |
 LL |     is_sync(bar());
-   |     ^^^^^^^ future returned by `bar` is not `Sync`
+   |             ^^^^^ future returned by `bar` is not `Sync`
    |
    = help: within `impl Future`, the trait `Sync` is not implemented for `Foo`
 note: future is not `Sync` as this value is used across an await
index 933e9296848e942b34ebac6659d3ea21a15bc6f7..9c94b8da8929ab48b764fbd8ec11aa6a31158e94 100644 (file)
@@ -1,8 +1,8 @@
 error: future cannot be sent between threads safely
-  --> $DIR/issue-64130-2-send.rs:21:5
+  --> $DIR/issue-64130-2-send.rs:21:13
    |
 LL |     is_send(bar());
-   |     ^^^^^^^ future returned by `bar` is not `Send`
+   |             ^^^^^ future returned by `bar` is not `Send`
    |
    = help: within `impl Future`, the trait `Send` is not implemented for `Foo`
 note: future is not `Send` as this value is used across an await
index ec0fdd4a5551dd70ad9a37a015c1e22a67a5a029..3dd1239e23dbeefff5a5b81af8346c02ed6b690e 100644 (file)
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future`
-  --> $DIR/issue-64130-3-other.rs:24:5
+  --> $DIR/issue-64130-3-other.rs:24:12
    |
 LL | async fn bar() {
    |                - within this `impl Future`
 ...
 LL |     is_qux(bar());
-   |     ^^^^^^ within `impl Future`, the trait `Qux` is not implemented for `Foo`
+   |            ^^^^^ within `impl Future`, the trait `Qux` is not implemented for `Foo`
    |
 note: future does not implement `Qux` as this value is used across an await
   --> $DIR/issue-64130-3-other.rs:18:5
index 656ade67c71a7a3eb9d165cce773fcd154a98811..b652d239153302fc7fddd99b23cdc4d2be9b559b 100644 (file)
@@ -1,4 +1,6 @@
 // edition:2018
+#![feature(must_not_suspend)]
+#![allow(must_not_suspend)]
 
 // This tests the basic example case for the async-await-specific error.
 
index 472fffa61b791e5f07ef0cd97939383ac41a5188..a373ba6aa71361ea74b4bb90880874cd70cdfe4e 100644 (file)
@@ -1,12 +1,12 @@
 error: future cannot be sent between threads safely
-  --> $DIR/issue-64130-non-send-future-diags.rs:21:5
+  --> $DIR/issue-64130-non-send-future-diags.rs:23:13
    |
 LL |     is_send(foo());
-   |     ^^^^^^^ future returned by `foo` is not `Send`
+   |             ^^^^^ future returned by `foo` is not `Send`
    |
    = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, u32>`
 note: future is not `Send` as this value is used across an await
-  --> $DIR/issue-64130-non-send-future-diags.rs:15:5
+  --> $DIR/issue-64130-non-send-future-diags.rs:17:5
    |
 LL |     let g = x.lock().unwrap();
    |         - has type `MutexGuard<'_, u32>` which is not `Send`
@@ -15,7 +15,7 @@ LL |     baz().await;
 LL | }
    | - `g` is later dropped here
 note: required by a bound in `is_send`
-  --> $DIR/issue-64130-non-send-future-diags.rs:7:15
+  --> $DIR/issue-64130-non-send-future-diags.rs:9:15
    |
 LL | fn is_send<T: Send>(t: T) { }
    |               ^^^^ required by this bound in `is_send`
index ebb392a45308e85bb34c7c84ab5adc4ba8345e87..7695e0325ff31feb45ee5dc1dc990d44d08ec2af 100644 (file)
@@ -1,4 +1,6 @@
 // edition:2018
+#![feature(must_not_suspend)]
+#![allow(must_not_suspend)]
 
 use std::future::Future;
 use std::sync::Mutex;
index 8903c09c17f0dbb186105e309e33bf87f5f39856..3cc800f96c20d0ed983779fc88362c13f5bf7aa2 100644 (file)
@@ -1,12 +1,12 @@
 error: future cannot be sent between threads safely
-  --> $DIR/issue-71137.rs:20:3
+  --> $DIR/issue-71137.rs:22:14
    |
 LL |   fake_spawn(wrong_mutex());
-   |   ^^^^^^^^^^ future returned by `wrong_mutex` is not `Send`
+   |              ^^^^^^^^^^^^^ future returned by `wrong_mutex` is not `Send`
    |
    = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, i32>`
 note: future is not `Send` as this value is used across an await
-  --> $DIR/issue-71137.rs:12:5
+  --> $DIR/issue-71137.rs:14:5
    |
 LL |     let mut guard = m.lock().unwrap();
    |         --------- has type `MutexGuard<'_, i32>` which is not `Send`
@@ -16,7 +16,7 @@ LL |     *guard += 1;
 LL |   }
    |   - `mut guard` is later dropped here
 note: required by a bound in `fake_spawn`
-  --> $DIR/issue-71137.rs:6:27
+  --> $DIR/issue-71137.rs:8:27
    |
 LL | fn fake_spawn<F: Future + Send + 'static>(f: F) { }
    |                           ^^^^ required by this bound in `fake_spawn`
index f34ce8081ca02e3f967910067a9d0a840f3c360f..8b53408d758e110ef55992fc4f94c42390e4f5cd 100644 (file)
@@ -7,5 +7,5 @@ fn g(_: impl Send) {}
 
 fn main() {
     g(issue_67893::run())
-    //~^ ERROR: `MutexGuard<'_, ()>` cannot be sent between threads safely
+    //~^ ERROR generator cannot be sent between threads safely
 }
index c4b55e6ec20222e9d83bcc1fb216f71641cac5b1..ee32a1a9e4fbb4a17b22ada678d38262a0058e53 100644 (file)
@@ -1,20 +1,10 @@
-error[E0277]: `MutexGuard<'_, ()>` cannot be sent between threads safely
-  --> $DIR/issue-67893.rs:9:5
+error: generator cannot be sent between threads safely
+  --> $DIR/issue-67893.rs:9:7
    |
 LL |     g(issue_67893::run())
-   |     ^ `MutexGuard<'_, ()>` cannot be sent between threads safely
-   |
-  ::: $DIR/auxiliary/issue_67893.rs:7:20
-   |
-LL | pub async fn run() {
-   |                    - within this `impl Future`
+   |       ^^^^^^^^^^^^^^^^^^ generator is not `Send`
    |
    = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
-   = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc<Mutex<()>>, &'r Mutex<()>, Result<MutexGuard<'s, ()>, PoisonError<MutexGuard<'t0, ()>>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}`
-   = note: required because it appears within the type `[static generator@run::{closure#0}]`
-   = note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{closure#0}]>`
-   = note: required because it appears within the type `impl Future`
-   = note: required because it appears within the type `impl Future`
 note: required by a bound in `g`
   --> $DIR/issue-67893.rs:6:14
    |
@@ -23,4 +13,3 @@ LL | fn g(_: impl Send) {}
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
index b6841da1f0ba9b0690a7b0c34f8a34faf66efe14..9b0018d8904ac10ad464492cabbf98c81471de8e 100644 (file)
@@ -1,13 +1,31 @@
 error: lifetime may not live long enough
-  --> $DIR/ret-impl-trait-one.rs:10:65
+  --> $DIR/ret-impl-trait-one.rs:10:85
+   |
+LL |   async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
+   |  ________________________________--__--_______________________________________________^
+   | |                                |   |
+   | |                                |   lifetime `'b` defined here
+   | |                                lifetime `'a` defined here
+LL | |
+LL | |     (a, b)
+LL | | }
+   | |_^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/ret-impl-trait-one.rs:16:65
    |
 LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
-   |                                --  --                           ^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
-   |                                |   |
-   |                                |   lifetime `'b` defined here
-   |                                lifetime `'a` defined here
+   |                                    --                           ^^^^^^^^^^^^^^
+   |                                    |
+   |                                    hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
+   |
+help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
    |
-   = help: consider adding the following bound: `'b: 'a`
+LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
+   |                                                                                ++++
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0700`.
index 7e084217c26075ee48fb846695e751c767980ddb..4f32489014d53715c66e648b890026ce5a4d5aad 100644 (file)
@@ -6,9 +6,15 @@
 trait Trait<'a> { }
 impl<T> Trait<'_> for T { }
 
+// Fails to recognize that both 'a and 'b are mentioned and should thus be accepted
+async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
+    //~^ ERROR lifetime mismatch
+    (a, b)
+}
+
 // Only `'a` permitted in return type, not `'b`.
 async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
-    //~^ ERROR lifetime mismatch
+    //~^ ERROR captures lifetime that does not appear in bounds
     (a, b)
 }
 
index 8e28605721cb5f313b2b538de5f8369cd5803cca..bcd96367e2fae41dd78fb7e0f4146fc8949bbbcd 100644 (file)
@@ -1,13 +1,27 @@
 error[E0623]: lifetime mismatch
   --> $DIR/ret-impl-trait-one.rs:10:65
    |
+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...
+
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/ret-impl-trait-one.rs:16:65
+   |
 LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
-   |                                           ------                ^^^^^^^^^^^^^^
-   |                                           |                     |
-   |                                           |                     ...but data from `b` is held across an await point here
-   |                                           |                     this `async fn` implicitly returns an `impl Future<Output = impl Trait<'a>>`
-   |                                           this parameter and the returned future are declared with different lifetimes...
+   |                                    --                           ^^^^^^^^^^^^^^
+   |                                    |
+   |                                    hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
+   |
+help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
+   |
+LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
+   |                                                                                ++++
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0623`.
+Some errors have detailed explanations: E0623, E0700.
+For more information about an error, try `rustc --explain E0623`.
index 8c581ff2229fc00889d0b9684cd75de5b2750938..b63ea106d90262ae8a0a09e7d970d40bf9db994f 100644 (file)
@@ -1,8 +1,10 @@
 error[E0277]: `PhantomPinned` cannot be unpinned
-  --> $DIR/pin-needed-to-poll-2.rs:43:9
+  --> $DIR/pin-needed-to-poll-2.rs:43:18
    |
 LL |         Pin::new(&mut self.sleep).poll(cx)
-   |         ^^^^^^^^ within `Sleep`, the trait `Unpin` is not implemented for `PhantomPinned`
+   |         -------- ^^^^^^^^^^^^^^^ within `Sleep`, the trait `Unpin` is not implemented for `PhantomPinned`
+   |         |
+   |         required by a bound introduced by this call
    |
    = note: consider using `Box::pin`
 note: required because it appears within the type `Sleep`
index 595ece2ea724707527b41ec419903c8182c90b5e..55006b2087eb024f3037bbc638dfbd8f23d8131c 100644 (file)
@@ -29,7 +29,7 @@ LL | pub 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!
    = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
-   = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information
+   = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
 
 error: this attribute can only be applied at the crate level
   --> $DIR/invalid-doc-attr.rs:15:12
@@ -72,7 +72,7 @@ LL |     pub fn baz() {}
    |
    = 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
-   = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information
+   = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
 
 error: aborting due to 6 previous errors
 
index 615193c0d02db929e18188c2603fdca40a6d501a..f36201396423adb1b7bc3fd3c995c4bd2ee3d353 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `f` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `f` is ambiguous
   --> $DIR/ambiguity-item.rs:14:13
    |
 LL |     let v = f;
    |             ^ ambiguous name
    |
+   = note: ambiguous because of multiple glob imports of a name in the same module
 note: `f` could refer to the function imported here
   --> $DIR/ambiguity-item.rs:6:5
    |
@@ -17,12 +18,13 @@ LL | use n::*; // OK, no conflict with `use m::*;`
    |     ^^^^
    = help: consider adding an explicit import of `f` to disambiguate
 
-error[E0659]: `f` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `f` is ambiguous
   --> $DIR/ambiguity-item.rs:16:9
    |
 LL |         f => {}
    |         ^ ambiguous name
    |
+   = note: ambiguous because of multiple glob imports of a name in the same module
 note: `f` could refer to the function imported here
   --> $DIR/ambiguity-item.rs:6:5
    |
diff --git a/src/test/ui/closures/2229_closure_analysis/issue-90465.fixed b/src/test/ui/closures/2229_closure_analysis/issue-90465.fixed
new file mode 100644 (file)
index 0000000..4e0b18e
--- /dev/null
@@ -0,0 +1,35 @@
+// run-rustfix
+
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE lint level is defined here
+
+fn main() {
+    struct Foo(u32);
+    impl Drop for Foo {
+        fn drop(&mut self) {
+            println!("dropped {}", self.0);
+        }
+    }
+
+    let f0 = Foo(0);
+    let f1 = Foo(1);
+
+    let c0 = move || {
+        let _ = &f0;
+        //~^ ERROR changes to closure capture in Rust 2021 will affect drop order
+        //~| NOTE for more information
+        let _ = f0;
+        //~^ NOTE in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect
+    };
+
+    let c1 = move || {
+        let _ = &f1;
+    };
+
+    println!("dropping 0");
+    drop(c0);
+    println!("dropping 1");
+    drop(c1);
+    println!("dropped all");
+}
+//~^ NOTE in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure
diff --git a/src/test/ui/closures/2229_closure_analysis/issue-90465.rs b/src/test/ui/closures/2229_closure_analysis/issue-90465.rs
new file mode 100644 (file)
index 0000000..466e6db
--- /dev/null
@@ -0,0 +1,34 @@
+// run-rustfix
+
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE lint level is defined here
+
+fn main() {
+    struct Foo(u32);
+    impl Drop for Foo {
+        fn drop(&mut self) {
+            println!("dropped {}", self.0);
+        }
+    }
+
+    let f0 = Foo(0);
+    let f1 = Foo(1);
+
+    let c0 = move || {
+        //~^ ERROR changes to closure capture in Rust 2021 will affect drop order
+        //~| NOTE for more information
+        let _ = f0;
+        //~^ NOTE in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect
+    };
+
+    let c1 = move || {
+        let _ = &f1;
+    };
+
+    println!("dropping 0");
+    drop(c0);
+    println!("dropping 1");
+    drop(c1);
+    println!("dropped all");
+}
+//~^ NOTE in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure
diff --git a/src/test/ui/closures/2229_closure_analysis/issue-90465.stderr b/src/test/ui/closures/2229_closure_analysis/issue-90465.stderr
new file mode 100644 (file)
index 0000000..3e921dc
--- /dev/null
@@ -0,0 +1,26 @@
+error: changes to closure capture in Rust 2021 will affect drop order
+  --> $DIR/issue-90465.rs:17:14
+   |
+LL |     let c0 = move || {
+   |              ^^^^^^^
+...
+LL |         let _ = f0;
+   |                 -- in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect
+...
+LL | }
+   | - in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure
+   |
+note: the lint level is defined here
+  --> $DIR/issue-90465.rs:3:9
+   |
+LL | #![deny(rust_2021_incompatible_closure_captures)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `f0` to be fully captured
+   |
+LL ~     let c0 = move || {
+LL +         let _ = &f0;
+   |
+
+error: aborting due to previous error
+
index b0fc5120f08f219783461c3e3e44316ed4323b28..26703fbf81193603e2a471b5a5d055b20bcc93db 100644 (file)
@@ -20,8 +20,8 @@ fn test_send_trait() {
     let mut f = 10;
     let fptr = SendPointer(&mut f as *mut i32);
     thread::spawn(move || { let _ = &fptr; unsafe {
-        //~^ ERROR: `Send` trait implementation for closure
-        //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send`
+        //~^ ERROR: changes to closure capture
+        //~| NOTE: in Rust 2018, this closure implements `Send`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `fptr` to be fully captured
         *fptr.0 = 20;
@@ -40,8 +40,9 @@ fn test_sync_trait() {
     let f = CustomInt(&mut f as *mut i32);
     let fptr = SyncPointer(f);
     thread::spawn(move || { let _ = &fptr; unsafe {
-        //~^ ERROR: `Sync`, `Send` trait implementation for closure
-        //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send`
+        //~^ ERROR: changes to closure capture
+        //~| NOTE: in Rust 2018, this closure implements `Sync`
+        //~| NOTE: in Rust 2018, this closure implements `Send`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `fptr` to be fully captured
         *fptr.0.0 = 20;
@@ -65,8 +66,8 @@ fn test_clone_trait() {
     let f = U(S(Foo(0)), T(0));
     let c = || {
         let _ = &f;
-        //~^ ERROR: `Clone` trait implementation for closure and drop order
-        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
+        //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+        //~| NOTE: in Rust 2018, this closure implements `Clone`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `f` to be fully captured
         let f_1 = f.1;
index 2bcf9a795edbd8f9fa093efe8b216d76725d777f..932db51d437130699e7256ef92cf104542b34940 100644 (file)
@@ -20,8 +20,8 @@ fn test_send_trait() {
     let mut f = 10;
     let fptr = SendPointer(&mut f as *mut i32);
     thread::spawn(move || unsafe {
-        //~^ ERROR: `Send` trait implementation for closure
-        //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send`
+        //~^ ERROR: changes to closure capture
+        //~| NOTE: in Rust 2018, this closure implements `Send`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `fptr` to be fully captured
         *fptr.0 = 20;
@@ -40,8 +40,9 @@ fn test_sync_trait() {
     let f = CustomInt(&mut f as *mut i32);
     let fptr = SyncPointer(f);
     thread::spawn(move || unsafe {
-        //~^ ERROR: `Sync`, `Send` trait implementation for closure
-        //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send`
+        //~^ ERROR: changes to closure capture
+        //~| NOTE: in Rust 2018, this closure implements `Sync`
+        //~| NOTE: in Rust 2018, this closure implements `Send`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `fptr` to be fully captured
         *fptr.0.0 = 20;
@@ -64,8 +65,8 @@ fn clone(&self) -> Self {
 fn test_clone_trait() {
     let f = U(S(Foo(0)), T(0));
     let c = || {
-        //~^ ERROR: `Clone` trait implementation for closure and drop order
-        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
+        //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+        //~| NOTE: in Rust 2018, this closure implements `Clone`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `f` to be fully captured
         let f_1 = f.1;
index 8d2d3553d4040f2fdbb6027cbe71d5fb5c3fd700..ee4907bb755cc115005945b6af0d7fa14e964da4 100644 (file)
@@ -1,8 +1,8 @@
-error: changes to closure capture in Rust 2021 will affect `Send` trait implementation for closure
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
   --> $DIR/auto_traits.rs:22:19
    |
 LL |     thread::spawn(move || unsafe {
-   |                   ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send`
+   |                   ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0` does not implement `Send`
 ...
 LL |         *fptr.0 = 20;
    |         ------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0`
@@ -23,11 +23,14 @@ LL |
 LL |         *fptr.0 = 20;
  ...
 
-error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
   --> $DIR/auto_traits.rs:42:19
    |
 LL |     thread::spawn(move || unsafe {
-   |                   ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send`
+   |                   ^^^^^^^^^^^^^^
+   |                   |
+   |                   in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr` is not fully captured and `fptr.0.0` does not implement `Sync`
+   |                   in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0.0` does not implement `Send`
 ...
 LL |         *fptr.0.0 = 20;
    |         --------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0.0`
@@ -40,14 +43,14 @@ LL |
 LL |
 LL |
 LL |
-LL |         *fptr.0.0 = 20;
+LL |
  ...
 
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
-  --> $DIR/auto_traits.rs:66:13
+error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+  --> $DIR/auto_traits.rs:67:13
    |
 LL |     let c = || {
-   |             ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
+   |             ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f` is not fully captured and `f.1` does not implement `Clone`
 ...
 LL |         let f_1 = f.1;
    |                   --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.1`
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs b/src/test/ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs
new file mode 100644 (file)
index 0000000..ed8cb04
--- /dev/null
@@ -0,0 +1,37 @@
+// Test that rustc doesn't ICE as in #90024.
+// check-pass
+// edition=2018
+
+#![warn(rust_2021_incompatible_closure_captures)]
+
+// Checks there's no double-subst into the generic args, otherwise we get OOB
+// MCVE by @lqd
+pub struct Graph<N, E, Ix> {
+    _edges: E,
+    _nodes: N,
+    _ix: Vec<Ix>,
+}
+fn graph<N, E>() -> Graph<N, E, i32> {
+    todo!()
+}
+fn first_ice() {
+    let g = graph::<i32, i32>();
+    let _ = || g;
+}
+
+// Checks that there is a subst into the fields, otherwise we get normalization error
+// MCVE by @cuviper
+use std::iter::Empty;
+struct Foo<I: Iterator> {
+    data: Vec<I::Item>,
+}
+pub fn second_ice() {
+    let v = Foo::<Empty<()>> { data: vec![] };
+
+    (|| v.data[0])();
+}
+
+pub fn main() {
+    first_ice();
+    second_ice();
+}
index a5652154682c5b672da67568c79a30dbc1f1e384..7df0dd76b44564b768e8989ece9e037c962d9136 100644 (file)
@@ -19,8 +19,9 @@ where
     let f = panic::AssertUnwindSafe(f);
     let result = panic::catch_unwind(move || {
         let _ = &f;
-        //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation for closure
-        //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe`
+        //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+        //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`
+        //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `f` to be fully captured
         f.0()
index d9acde073fc3d38fffd84202b80668764057f394..d02fac7c66952606048a19827fcd9c37050b3c23 100644 (file)
@@ -18,8 +18,9 @@ fn assert_panics<F>(f: F)
 {
     let f = panic::AssertUnwindSafe(f);
     let result = panic::catch_unwind(move || {
-        //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation for closure
-        //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe`
+        //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+        //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`
+        //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `f` to be fully captured
         f.0()
index 10816b7bc3adf9346df3414fd7ed2105e6b6a621..74f85b6ebaac50e5f3de999ef10a17f90740d93d 100644 (file)
@@ -1,8 +1,11 @@
-error: changes to closure capture in Rust 2021 will affect `UnwindSafe`, `RefUnwindSafe` trait implementation for closure
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
   --> $DIR/mir_calls_to_shims.rs:20:38
    |
 LL |     let result = panic::catch_unwind(move || {
-   |                                      ^^^^^^^ in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe`
+   |                                      ^^^^^^^
+   |                                      |
+   |                                      in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` because `f` is not fully captured and `f.0` does not implement `UnwindSafe`
+   |                                      in Rust 2018, this closure implements `RefUnwindSafe` as `f` implements `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `RefUnwindSafe` because `f` is not fully captured and `f.0` does not implement `RefUnwindSafe`
 ...
 LL |         f.0()
    |         --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.0`
index 11218eff1337f7f63e779df6b9ec5a7a40fdc429..2b86b0ddade2367196e542f83ac91b65cfc2b2b7 100644 (file)
@@ -18,7 +18,6 @@ impl Foo {
     }
 }
 
-
 struct S(Foo);
 
 #[derive(Clone)]
@@ -37,8 +36,8 @@ fn test_multi_issues() {
     let f2 = U(S(Foo::from("bar")), T(0));
     let c = || {
         let _ = (&f1, &f2);
-        //~^ ERROR: `Clone` trait implementation for closure and drop order
-        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+        //~^ ERROR: changes to closure capture in Rust 2021
+        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured
         let _f_1 = f1.0;
@@ -57,8 +56,8 @@ fn test_capturing_all_disjoint_fields_individually() {
     let f1 = U(S(Foo::from("foo")), T(0));
     let c = || {
         let _ = &f1;
-        //~^ ERROR: `Clone` trait implementation for closure
-        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+        //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `f1` to be fully captured
         let _f_1 = f1.0;
@@ -83,9 +82,9 @@ fn test_capturing_several_disjoint_fields_individually_1() {
     let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
     let c = || {
         let _ = &f1;
-        //~^ ERROR: `Clone` trait implementation for closure
-        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
-        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone`
+        //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `f1` to be fully captured
         let _f_0 = f1.0;
@@ -103,8 +102,8 @@ fn test_capturing_several_disjoint_fields_individually_2() {
     let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
     let c = || {
         let _ = &f1;
-        //~^ ERROR: `Clone` trait implementation for closure and drop order
-        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+        //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `f1` to be fully captured
         let _f_0 = f1.0;
@@ -136,9 +135,10 @@ fn test_multi_traits_issues() {
     let mut f2 = 10;
     let fptr2 = SendPointer(&mut f2 as *mut i32);
     thread::spawn(move || { let _ = (&fptr1, &fptr2); unsafe {
-        //~^ ERROR: `Sync`, `Send` trait implementation for closure
-        //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send`
-        //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send`
+        //~^ ERROR: changes to closure capture in Rust 2021
+        //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`
+        //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`
+        //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured
         *fptr1.0.0 = 20;
index 02f2faa2e8741615266e5f91687be7713335d207..3cac4abfad7c2a5def2e614517d6d30684481719 100644 (file)
@@ -18,7 +18,6 @@ fn from(s: &str) -> Self {
     }
 }
 
-
 struct S(Foo);
 
 #[derive(Clone)]
@@ -36,8 +35,8 @@ fn test_multi_issues() {
     let f1 = U(S(Foo::from("foo")), T(0));
     let f2 = U(S(Foo::from("bar")), T(0));
     let c = || {
-        //~^ ERROR: `Clone` trait implementation for closure and drop order
-        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+        //~^ ERROR: changes to closure capture in Rust 2021
+        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured
         let _f_1 = f1.0;
@@ -55,8 +54,8 @@ fn test_multi_issues() {
 fn test_capturing_all_disjoint_fields_individually() {
     let f1 = U(S(Foo::from("foo")), T(0));
     let c = || {
-        //~^ ERROR: `Clone` trait implementation for closure
-        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+        //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `f1` to be fully captured
         let _f_1 = f1.0;
@@ -80,9 +79,9 @@ fn clone(&self) -> Self {
 fn test_capturing_several_disjoint_fields_individually_1() {
     let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
     let c = || {
-        //~^ ERROR: `Clone` trait implementation for closure
-        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
-        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone`
+        //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `f1` to be fully captured
         let _f_0 = f1.0;
@@ -99,8 +98,8 @@ fn test_capturing_several_disjoint_fields_individually_1() {
 fn test_capturing_several_disjoint_fields_individually_2() {
     let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
     let c = || {
-        //~^ ERROR: `Clone` trait implementation for closure and drop order
-        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+        //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+        //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `f1` to be fully captured
         let _f_0 = f1.0;
@@ -132,9 +131,10 @@ fn test_multi_traits_issues() {
     let mut f2 = 10;
     let fptr2 = SendPointer(&mut f2 as *mut i32);
     thread::spawn(move || unsafe {
-        //~^ ERROR: `Sync`, `Send` trait implementation for closure
-        //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send`
-        //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send`
+        //~^ ERROR: changes to closure capture in Rust 2021
+        //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`
+        //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`
+        //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`
         //~| NOTE: for more information, see
         //~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured
         *fptr1.0.0 = 20;
index d425db5aa998c69394a674441809eef0581660b3..0008f1b2c07ed5811544fd27f9767c75c6bcfec0 100644 (file)
@@ -1,8 +1,8 @@
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
-  --> $DIR/multi_diagnostics.rs:38:13
+error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+  --> $DIR/multi_diagnostics.rs:37:13
    |
 LL |     let c = || {
-   |             ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+   |             ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
 ...
 LL |         let _f_1 = f1.0;
    |                    ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
@@ -25,11 +25,11 @@ LL ~     let c = || {
 LL +         let _ = (&f1, &f2);
    |
 
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure
-  --> $DIR/multi_diagnostics.rs:57:13
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+  --> $DIR/multi_diagnostics.rs:56:13
    |
 LL |     let c = || {
-   |             ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+   |             ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
 ...
 LL |         let _f_1 = f1.0;
    |                    ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
@@ -41,14 +41,14 @@ LL ~     let c = || {
 LL +         let _ = &f1;
    |
 
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure
-  --> $DIR/multi_diagnostics.rs:82:13
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+  --> $DIR/multi_diagnostics.rs:81:13
    |
 LL |     let c = || {
    |             ^^
    |             |
-   |             in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
-   |             in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone`
+   |             in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
+   |             in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.2` does not implement `Clone`
 ...
 LL |         let _f_0 = f1.0;
    |                    ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
@@ -63,11 +63,11 @@ LL ~     let c = || {
 LL +         let _ = &f1;
    |
 
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
-  --> $DIR/multi_diagnostics.rs:101:13
+error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+  --> $DIR/multi_diagnostics.rs:100:13
    |
 LL |     let c = || {
-   |             ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+   |             ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
 ...
 LL |         let _f_0 = f1.0;
    |                    ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
@@ -88,14 +88,15 @@ LL ~     let c = || {
 LL +         let _ = &f1;
    |
 
-error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure
-  --> $DIR/multi_diagnostics.rs:134:19
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+  --> $DIR/multi_diagnostics.rs:133:19
    |
 LL |     thread::spawn(move || unsafe {
    |                   ^^^^^^^^^^^^^^
    |                   |
-   |                   in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send`
-   |                   in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send`
+   |                   in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Sync`
+   |                   in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Send`
+   |                   in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr2` is not fully captured and `fptr2.0` does not implement `Send`
 ...
 LL |         *fptr1.0.0 = 20;
    |         ---------- in Rust 2018, this closure captures all of `fptr1`, but in Rust 2021, it will only capture `fptr1.0.0`
index d9479002b6cde31df63b1e10c5c04bb77b4504e2..36d6450c9a2f0ceb45e23cf0fa4599f3019e9bf2 100644 (file)
@@ -9,7 +9,7 @@ LL |         let c1 : () = c;
    |                  expected due to this
    |
    = note: expected unit type `()`
-                found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable)]`
+                found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#25t, extern "rust-call" fn(()), _#26t]]`
 help: use parentheses to call this closure
    |
 LL |         let c1 : () = c();
index 880e38df2d70a87586c18a20cdd111dadcbd8711..91926f233d394d83762aa3472334b10838e306c0 100644 (file)
@@ -9,7 +9,7 @@ LL |         let c1 : () = c;
    |                  expected due to this
    |
    = note: expected unit type `()`
-                found closure `[f<T>::{closure#0} closure_substs=(unavailable)]`
+                found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#25t, extern "rust-call" fn(()), _#26t]]`
 help: use parentheses to call this closure
    |
 LL |         let c1 : () = c();
index d19b07acbf175c3aa8ed7e88fbe87ed4e847e0b0..083717b333408e46d342f4e6a07b20d72058db87 100644 (file)
@@ -7,7 +7,7 @@ LL |     let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
    |              expected due to this
    |
    = note: expected fn pointer `fn(u8) -> u8`
-                 found closure `[main::{closure#0} closure_substs=(unavailable)]`
+                 found closure `[main::{closure#0} closure_substs=(unavailable) substs=[i8, extern "rust-call" fn((u8,)) -> u8, _#6t]]`
 note: closures can only be coerced to `fn` types if they do not capture any variables
   --> $DIR/closure-print-verbose.rs:10:39
    |
index 9697146d5c3d83623b7d2390bf07de83f65bb447..d5c67af2b41464fab168132c2e405752193e8963 100644 (file)
@@ -1,7 +1,6 @@
 // build-fail
 // compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
 // needs-llvm-components: arm
-// min-llvm-version: 11.0
 #![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)]
 #![no_core]
 #[lang="sized"]
index 74321fdfdde907b5694b04a5ea928f0a004dc587..9a1b0a38d5eacc21656b6023ac27bde63369119f 100644 (file)
@@ -1,7 +1,6 @@
 // build-fail
 // compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
 // needs-llvm-components: arm
-// min-llvm-version: 11.0
 #![feature(cmse_nonsecure_entry, no_core, lang_items)]
 #![no_core]
 #[lang="sized"]
diff --git a/src/test/ui/coherence/auxiliary/error_lib.rs b/src/test/ui/coherence/auxiliary/error_lib.rs
new file mode 100644 (file)
index 0000000..43806cb
--- /dev/null
@@ -0,0 +1,5 @@
+#![crate_type = "lib"]
+#![feature(negative_impls)]
+
+pub trait Error {}
+impl !Error for &str {}
diff --git a/src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs b/src/test/ui/coherence/coherence-overlap-negate-alias-strict.rs
new file mode 100644 (file)
index 0000000..16ace45
--- /dev/null
@@ -0,0 +1,19 @@
+#![feature(negative_impls)]
+#![feature(rustc_attrs)]
+#![feature(trait_alias)]
+
+trait A {}
+trait B {}
+trait AB = A + B;
+
+impl !A for u32 {}
+
+trait C {}
+#[rustc_strict_coherence]
+impl<T: AB> C for T {}
+#[rustc_strict_coherence]
+impl C for u32 {}
+//~^ ERROR: conflicting implementations of trait `C` for type `u32` [E0119]
+// FIXME this should work, we should implement an `assemble_neg_candidates` fn
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-overlap-negate-alias-strict.stderr b/src/test/ui/coherence/coherence-overlap-negate-alias-strict.stderr
new file mode 100644 (file)
index 0000000..5e43622
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `C` for type `u32`
+  --> $DIR/coherence-overlap-negate-alias-strict.rs:15:1
+   |
+LL | impl<T: AB> C for T {}
+   | ------------------- first implementation here
+LL | #[rustc_strict_coherence]
+LL | impl C for u32 {}
+   | ^^^^^^^^^^^^^^ conflicting implementation for `u32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/coherence/coherence-overlap-negate-not-use-feature-gate.rs b/src/test/ui/coherence/coherence-overlap-negate-not-use-feature-gate.rs
new file mode 100644 (file)
index 0000000..a067736
--- /dev/null
@@ -0,0 +1,8 @@
+use std::ops::DerefMut;
+
+trait Foo {}
+impl<T: DerefMut> Foo for T {}
+impl<U> Foo for &U {}
+//~^ ERROR: conflicting implementations of trait `Foo` for type `&_` [E0119]
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-overlap-negate-not-use-feature-gate.stderr b/src/test/ui/coherence/coherence-overlap-negate-not-use-feature-gate.stderr
new file mode 100644 (file)
index 0000000..4b55001
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0119]: conflicting implementations of trait `Foo` for type `&_`
+  --> $DIR/coherence-overlap-negate-not-use-feature-gate.rs:5:1
+   |
+LL | impl<T: DerefMut> Foo for T {}
+   | --------------------------- first implementation here
+LL | impl<U> Foo for &U {}
+   | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/coherence/coherence-overlap-negate-strict.rs b/src/test/ui/coherence/coherence-overlap-negate-strict.rs
new file mode 100644 (file)
index 0000000..b3ae9a7
--- /dev/null
@@ -0,0 +1,18 @@
+// check-pass
+
+#![feature(negative_impls)]
+#![feature(rustc_attrs)]
+#![feature(trait_alias)]
+
+trait A {}
+trait B {}
+
+impl !A for u32 {}
+
+trait C {}
+#[rustc_strict_coherence]
+impl<T: A + B> C for T {}
+#[rustc_strict_coherence]
+impl C for u32 {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-overlap-negate-use-feature-gate.rs b/src/test/ui/coherence/coherence-overlap-negate-use-feature-gate.rs
new file mode 100644 (file)
index 0000000..e024eae
--- /dev/null
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(negative_impls)]
+
+use std::ops::DerefMut;
+
+trait Foo {}
+impl<T: DerefMut> Foo for T {}
+impl<U> Foo for &U {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-overlap-negative-trait.rs b/src/test/ui/coherence/coherence-overlap-negative-trait.rs
new file mode 100644 (file)
index 0000000..ab65163
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+// aux-build:error_lib.rs
+//
+// Check that if we promise to not impl what would overlap it doesn't actually overlap
+
+#![feature(negative_impls)]
+
+extern crate error_lib as lib;
+use lib::Error;
+
+trait From<T> {}
+
+impl From<&str> for Box<dyn Error> {}
+impl<E> From<E> for Box<dyn Error> where E: Error {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-overlap-trait-alias.rs b/src/test/ui/coherence/coherence-overlap-trait-alias.rs
new file mode 100644 (file)
index 0000000..45b2f08
--- /dev/null
@@ -0,0 +1,20 @@
+#![feature(rustc_attrs)]
+#![feature(trait_alias)]
+
+trait A {}
+trait B {}
+trait AB = A + B;
+
+impl A for u32 {}
+impl B for u32 {}
+
+trait C {}
+#[rustc_strict_coherence]
+impl<T: AB> C for T {}
+#[rustc_strict_coherence]
+impl C for u32 {}
+//~^ ERROR
+// FIXME it's giving an ungreat error but unsure if we care given that it's using an internal rustc
+// attribute and an artificial code path for testing purposes
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-overlap-trait-alias.stderr b/src/test/ui/coherence/coherence-overlap-trait-alias.stderr
new file mode 100644 (file)
index 0000000..affc58b
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0283]: type annotations needed
+  --> $DIR/coherence-overlap-trait-alias.rs:15:6
+   |
+LL | impl C for u32 {}
+   |      ^ cannot infer type for type `u32`
+   |
+note: multiple `impl`s satisfying `u32: C` found
+  --> $DIR/coherence-overlap-trait-alias.rs:13:1
+   |
+LL | impl<T: AB> C for T {}
+   | ^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_strict_coherence]
+LL | impl C for u32 {}
+   | ^^^^^^^^^^^^^^
+note: required by a bound in `C`
+  --> $DIR/coherence-overlap-trait-alias.rs:11:1
+   |
+LL | trait C {}
+   | ^^^^^^^ required by this bound in `C`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-7.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-7.rs
new file mode 100644 (file)
index 0000000..149142f
--- /dev/null
@@ -0,0 +1,5 @@
+// Regression test for issue #89358.
+
+// compile-flags: --cfg a"
+// error-pattern: unterminated double quote string
+// error-pattern: this error occurred on the command line
diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-7.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-7.stderr
new file mode 100644 (file)
index 0000000..919709c
--- /dev/null
@@ -0,0 +1,4 @@
+error[E0765]: unterminated double quote string
+  |
+  = note: this error occurred on the command line: `--cfg=a"`
+
index 2b41dbb58873e348d77e784cb28bceca8dc56670..5517bf8ac5fb221b7ac816962d84631454ce2612 100644 (file)
@@ -2,7 +2,7 @@
 #![feature(staged_api)]
 #![feature(const_generics_defaults)]
 #![allow(incomplete_features)]
-// FIXME(const_generics): It seems like we aren't testing the right thing here,
+// FIXME(const_generics_defaults): It seems like we aren't testing the right thing here,
 // I would assume that we want the attributes to apply to the const parameter defaults
 // themselves.
 #![stable(feature = "const_default_test", since="none")]
diff --git a/src/test/ui/const-generics/defaults/doesnt_infer.rs b/src/test/ui/const-generics/defaults/doesnt_infer.rs
new file mode 100644 (file)
index 0000000..c7f14e4
--- /dev/null
@@ -0,0 +1,15 @@
+#![feature(const_generics_defaults)]
+
+// test that defaulted const params are not used to help type inference
+
+struct Foo<const N: u32 = 2>;
+
+impl<const N: u32> Foo<N> {
+    fn foo() -> Self { loop {} }
+}
+
+fn main() {
+    let foo = Foo::<1>::foo();
+    let foo = Foo::foo();
+    //~^ error: type annotations needed for `Foo<{_: u32}>`
+}
diff --git a/src/test/ui/const-generics/defaults/doesnt_infer.stderr b/src/test/ui/const-generics/defaults/doesnt_infer.stderr
new file mode 100644 (file)
index 0000000..b57975e
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed for `Foo<{_: u32}>`
+  --> $DIR/doesnt_infer.rs:13:15
+   |
+LL |     let foo = Foo::foo();
+   |         ---   ^^^^^^^^ cannot infer the value of const parameter `N`
+   |         |
+   |         consider giving `foo` the explicit type `Foo<{_: u32}>`, where the type parameter `N` is specified
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait.rs b/src/test/ui/const-generics/defaults/rp_impl_trait.rs
new file mode 100644 (file)
index 0000000..1447ebe
--- /dev/null
@@ -0,0 +1,31 @@
+// run-pass
+#![feature(const_generics_defaults)]
+
+struct Uwu<const N: u32 = 1, const M: u32 = N>;
+
+trait Trait {}
+impl<const N: u32> Trait for Uwu<N> {}
+
+fn rawr<const N: u32>() -> impl Trait {
+    Uwu::<N>
+}
+
+trait Traitor<const N: u8 = 1, const M: u8 = N> { }
+
+impl<const N: u8> Traitor<N> for u32 {}
+impl Traitor<1, 1> for u64 {}
+
+fn uwu<const N: u8>() -> impl Traitor<N> {
+    1_u32
+}
+
+fn owo() -> impl Traitor {
+    1_u64
+}
+
+fn main() {
+    rawr::<3>();
+    rawr::<7>();
+    uwu::<{ u8::MAX }>();
+    owo();
+}
diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs
new file mode 100644 (file)
index 0000000..c989fc8
--- /dev/null
@@ -0,0 +1,33 @@
+#![feature(const_generics_defaults)]
+
+struct Uwu<const N: u32 = 1, const M: u32 = N>;
+
+trait Trait {}
+impl<const N: u32> Trait for Uwu<N> {}
+
+fn rawr() -> impl Trait {
+    //~^ error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
+    Uwu::<10, 12>
+}
+
+trait Traitor<const N: u8 = 1, const M: u8 = N> { }
+
+impl<const N: u8> Traitor<N, 2> for u32 {}
+impl Traitor<1, 2> for u64 {}
+
+
+fn uwu<const N: u8>() -> impl Traitor<N> {
+    //~^ error: the trait bound `u32: Traitor<N, N>` is not satisfied
+    1_u32
+}
+
+fn owo() -> impl Traitor {
+    //~^ error: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
+    1_u64
+}
+
+fn main() {
+    rawr();
+    uwu();
+    owo();
+}
diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
new file mode 100644 (file)
index 0000000..cf28932
--- /dev/null
@@ -0,0 +1,30 @@
+error[E0277]: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
+  --> $DIR/rp_impl_trait_fail.rs:8:14
+   |
+LL | fn rawr() -> impl Trait {
+   |              ^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>`
+   |
+   = help: the following implementations were found:
+             <Uwu<N> as Trait>
+
+error[E0277]: the trait bound `u32: Traitor<N, N>` is not satisfied
+  --> $DIR/rp_impl_trait_fail.rs:19:26
+   |
+LL | fn uwu<const N: u8>() -> impl Traitor<N> {
+   |                          ^^^^^^^^^^^^^^^ the trait `Traitor<N, N>` is not implemented for `u32`
+   |
+   = help: the following implementations were found:
+             <u32 as Traitor<N, 2_u8>>
+
+error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
+  --> $DIR/rp_impl_trait_fail.rs:24:13
+   |
+LL | fn owo() -> impl Traitor {
+   |             ^^^^^^^^^^^^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
+   |
+   = help: the following implementations were found:
+             <u64 as Traitor<1_u8, 2_u8>>
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/defaults/trait_objects.rs b/src/test/ui/const-generics/defaults/trait_objects.rs
new file mode 100644 (file)
index 0000000..e36f23f
--- /dev/null
@@ -0,0 +1,45 @@
+// run-pass
+#![feature(const_generics_defaults)]
+
+trait Trait<const N: u8 = 12> {
+    fn uwu(&self) -> u8 {
+        N
+    }
+}
+
+impl Trait for u32 {}
+
+impl Trait<12> for u64 {
+    fn uwu(&self) -> u8 {
+        *self as u8
+    }
+}
+
+fn foo(arg: &dyn Trait) -> u8 {
+    arg.uwu()
+}
+
+trait Traitor<const N: u8 = 1, const M: u8 = N> {
+    fn owo(&self) -> u8 {
+        M
+    }
+}
+
+impl Traitor<2> for bool { }
+impl Traitor for u8 {
+    fn owo(&self) -> u8 {
+        *self
+    }
+}
+
+fn bar<const N: u8>(arg: &dyn Traitor<N>) -> u8 {
+    arg.owo()
+}
+
+fn main() {
+    assert_eq!(foo(&10_u32), 12);
+    assert_eq!(foo(&3_u64), 3);
+
+    assert_eq!(bar(&true), 2);
+    assert_eq!(bar(&1_u8), 1);
+}
diff --git a/src/test/ui/const-generics/defaults/trait_objects_fail.rs b/src/test/ui/const-generics/defaults/trait_objects_fail.rs
new file mode 100644 (file)
index 0000000..09e4265
--- /dev/null
@@ -0,0 +1,32 @@
+#![feature(const_generics_defaults)]
+
+trait Trait<const N: u8 = 12> {
+    fn uwu(&self) -> u8 {
+        N
+    }
+}
+
+impl Trait<2> for u32 {}
+
+fn foo(arg: &dyn Trait) -> u8 {
+    arg.uwu()
+}
+
+trait Traitor<const N: u8 = 1, const M: u8 = N> {
+    fn owo(&self) -> u8 {
+        M
+    }
+}
+
+impl Traitor<2, 3> for bool { }
+
+fn bar<const N: u8>(arg: &dyn Traitor<N>) -> u8 {
+    arg.owo()
+}
+
+fn main() {
+    foo(&10_u32);
+    //~^ error: the trait bound `u32: Trait` is not satisfied
+    bar(&true);
+    //~^ error: the trait bound `bool: Traitor<{_: u8}, {_: u8}>` is not satisfied
+}
diff --git a/src/test/ui/const-generics/defaults/trait_objects_fail.stderr b/src/test/ui/const-generics/defaults/trait_objects_fail.stderr
new file mode 100644 (file)
index 0000000..b097c8c
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0277]: the trait bound `u32: Trait` is not satisfied
+  --> $DIR/trait_objects_fail.rs:28:9
+   |
+LL |     foo(&10_u32);
+   |     --- ^^^^^^^ the trait `Trait` is not implemented for `u32`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the following implementations were found:
+             <u32 as Trait<2_u8>>
+   = note: required for the cast to the object type `dyn Trait`
+
+error[E0277]: the trait bound `bool: Traitor<{_: u8}, {_: u8}>` is not satisfied
+  --> $DIR/trait_objects_fail.rs:30:9
+   |
+LL |     bar(&true);
+   |     --- ^^^^^ the trait `Traitor<{_: u8}, {_: u8}>` is not implemented for `bool`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the following implementations were found:
+             <bool as Traitor<2_u8, 3_u8>>
+   = note: required for the cast to the object type `dyn Traitor<{_: u8}, {_: u8}>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/defaults/wfness.rs b/src/test/ui/const-generics/defaults/wfness.rs
new file mode 100644 (file)
index 0000000..c171f29
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(const_generics_defaults)]
+
+struct Ooopsies<const N: u8 = { u8::MAX + 1 }>;
+//~^ error: evaluation of constant value failed
+
+trait Trait<const N: u8> {}
+impl Trait<3> for () {}
+struct WhereClause<const N: u8 = 2> where (): Trait<N>;
+//~^ error: the trait bound `(): Trait<2_u8>` is not satisfied
+
+trait Traitor<T, const N: u8> {}
+struct WhereClauseTooGeneric<T = u32, const N: u8 = 2>(T) where (): Traitor<T, N>;
+
+// no error on struct def
+struct DependentDefaultWfness<const N: u8 = 1, T = WhereClause<N>>(T);
+fn foo() -> DependentDefaultWfness {
+    //~^ error: the trait bound `(): Trait<1_u8>` is not satisfied
+    loop {}
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/defaults/wfness.stderr b/src/test/ui/const-generics/defaults/wfness.stderr
new file mode 100644 (file)
index 0000000..9826af8
--- /dev/null
@@ -0,0 +1,38 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/wfness.rs:3:33
+   |
+LL | struct Ooopsies<const N: u8 = { u8::MAX + 1 }>;
+   |                                 ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
+
+error[E0277]: the trait bound `(): Trait<2_u8>` is not satisfied
+  --> $DIR/wfness.rs:8:47
+   |
+LL | struct WhereClause<const N: u8 = 2> where (): Trait<N>;
+   |                                               ^^^^^^^^ the trait `Trait<2_u8>` is not implemented for `()`
+   |
+   = help: the following implementations were found:
+             <() as Trait<3_u8>>
+note: required by `WhereClause`
+  --> $DIR/wfness.rs:8:1
+   |
+LL | struct WhereClause<const N: u8 = 2> where (): Trait<N>;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `(): Trait<1_u8>` is not satisfied
+  --> $DIR/wfness.rs:16:13
+   |
+LL | fn foo() -> DependentDefaultWfness {
+   |             ^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<1_u8>` is not implemented for `()`
+   |
+   = help: the following implementations were found:
+             <() as Trait<3_u8>>
+note: required by a bound in `WhereClause`
+  --> $DIR/wfness.rs:8:47
+   |
+LL | struct WhereClause<const N: u8 = 2> where (): Trait<N>;
+   |                                               ^^^^^^^^ required by this bound in `WhereClause`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0080, E0277.
+For more information about an error, try `rustc --explain E0080`.
index 33564a48448a79eb2e0e61e19c2c5a60ea1d1c4d..94e7367b1fb765d9ecfa53aae01883d380046612 100644 (file)
@@ -5,4 +5,7 @@ struct A<T = u32, const N: usize> {
     arg: T,
 }
 
+struct Foo<const N: u8 = 3, T>(T);
+//~^ error: generic parameters with a default must be trailing
+
 fn main() {}
index 47a2c6f3f4193dd45a557b091edbb99cc41607a9..143ce5c4fea7ed7512c58b18bcfcc6fbc6823ef1 100644 (file)
@@ -4,5 +4,11 @@ error: generic parameters with a default must be trailing
 LL | struct A<T = u32, const N: usize> {
    |          ^
 
-error: aborting due to previous error
+error: generic parameters with a default must be trailing
+  --> $DIR/wrong-order.rs:8:18
+   |
+LL | struct Foo<const N: u8 = 3, T>(T);
+   |                  ^
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/expose-default-substs-param-env.rs b/src/test/ui/const-generics/expose-default-substs-param-env.rs
new file mode 100644 (file)
index 0000000..e40c931
--- /dev/null
@@ -0,0 +1,9 @@
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(unused_braces, incomplete_features)]
+
+pub trait Foo<const N: usize> {}
+pub trait Bar: Foo<{ 1 }> { }
+
+fn main() {}
index e51db35925e4acb3d543482c8ba6269d0e8da6b4..4202cbae7eb29a46750827dd0247db2add4554c1 100644 (file)
@@ -1,8 +1,10 @@
 error[E0277]: the trait bound `(): _Contains<&C>` is not satisfied
-  --> $DIR/issue-85848.rs:24:5
+  --> $DIR/issue-85848.rs:24:29
    |
 LL |     writes_to_specific_path(&cap);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ the trait `_Contains<&C>` is not implemented for `()`
+   |     ----------------------- ^^^^ the trait `_Contains<&C>` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
    |
 note: required because of the requirements on the impl of `Contains<(), true>` for `&C`
   --> $DIR/issue-85848.rs:21:12
@@ -21,10 +23,12 @@ LL | fn writes_to_specific_path<C: Delegates<()>>(cap: &C) {}
    |                               ^^^^^^^^^^^^^ required by this bound in `writes_to_specific_path`
 
 error: unconstrained generic constant
-  --> $DIR/issue-85848.rs:24:5
+  --> $DIR/issue-85848.rs:24:29
    |
 LL |     writes_to_specific_path(&cap);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |     ----------------------- ^^^^
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: try adding a `where` bound using this expression: `where [(); { contains::<T, U>() }]:`
 note: required because of the requirements on the impl of `Contains<(), true>` for `&C`
index 0f0e339655bcaaa9790502bfe00b52def331a4bf..0cf69879a5c20fed0b30ab2f9524eb56a4424acf 100644 (file)
@@ -8,15 +8,5 @@ LL |     inner: [(); { [|_: &T| {}; 0].len() }],
    |
    = help: consider moving this anonymous constant into a `const` function
 
-error[E0392]: parameter `T` is never used
-  --> $DIR/issue-67375.rs:5:12
-   |
-LL | struct Bug<T> {
-   |            ^ unused parameter
-   |
-   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0392`.
index b5b842a15ae0c142c98042079777ab46653b702e..8b4b276bae0ba65ed5af74066ed724338da5ba86 100644 (file)
@@ -3,7 +3,7 @@
 #![cfg_attr(full, feature(generic_const_exprs))]
 
 struct Bug<T> {
-    //~^ ERROR parameter `T` is never used
+    //[min]~^ ERROR parameter `T` is never used
     inner: [(); { [|_: &T| {}; 0].len() }],
     //[min]~^ ERROR generic parameters may not be used in const operations
     //[full]~^^ ERROR overly complex generic constant
index 1edc7828caad2553ce00308dd7f5a1283c70cc24..8e18fcdffab7063dea9fd34e6262d89d8e2b356d 100644 (file)
@@ -12,16 +12,6 @@ LL |         let x: S = MaybeUninit::uninit();
    = note: expected type parameter `S`
                        found union `MaybeUninit<_>`
 
-error[E0392]: parameter `S` is never used
-  --> $DIR/issue-67945-1.rs:7:12
-   |
-LL | struct Bug<S> {
-   |            ^ unused parameter
-   |
-   = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0308, E0392.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0308`.
index 7b7e8428639c7d486b7e6073a84546e3aecba872..99f88bc8e1055a75d4cffab97501ca664b21a098 100644 (file)
@@ -5,7 +5,7 @@
 use std::mem::MaybeUninit;
 
 struct Bug<S> {
-    //~^ ERROR parameter `S` is never used
+    //[min]~^ ERROR parameter `S` is never used
     A: [(); {
         let x: S = MaybeUninit::uninit();
         //[min]~^ ERROR generic parameters may not be used in const operations
diff --git a/src/test/ui/const-generics/issues/issue-88997.rs b/src/test/ui/const-generics/issues/issue-88997.rs
new file mode 100644 (file)
index 0000000..7666a51
--- /dev/null
@@ -0,0 +1,14 @@
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+struct ConstAssert<const COND: bool>;
+trait True {}
+impl True for ConstAssert<true> {}
+
+struct Range<T: PartialOrd, const MIN: T, const MAX: T>(T)
+//~^ ERROR the type of const parameters must not depend on other generic parameters
+//~| ERROR the type of const parameters must not depend on other generic parameters
+where
+    ConstAssert<{ MIN <= MAX }>: True;
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-88997.stderr b/src/test/ui/const-generics/issues/issue-88997.stderr
new file mode 100644 (file)
index 0000000..505ba0d
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/issue-88997.rs:8:40
+   |
+LL | struct Range<T: PartialOrd, const MIN: T, const MAX: T>(T)
+   |                                        ^ the type must not depend on the parameter `T`
+
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/issue-88997.rs:8:54
+   |
+LL | struct Range<T: PartialOrd, const MIN: T, const MAX: T>(T)
+   |                                                      ^ the type must not depend on the parameter `T`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0770`.
diff --git a/src/test/ui/const-generics/issues/issue-89304.rs b/src/test/ui/const-generics/issues/issue-89304.rs
new file mode 100644 (file)
index 0000000..d544d63
--- /dev/null
@@ -0,0 +1,20 @@
+// check-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+struct GenericStruct<const T: usize> { val: i64 }
+
+impl<const T: usize> From<GenericStruct<T>> for GenericStruct<{T + 1}> {
+    fn from(other: GenericStruct<T>) -> Self {
+        Self { val: other.val }
+    }
+}
+
+impl<const T: usize> From<GenericStruct<{T + 1}>> for GenericStruct<T> {
+    fn from(other: GenericStruct<{T + 1}>) -> Self {
+        Self { val: other.val }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-89334.rs b/src/test/ui/const-generics/issues/issue-89334.rs
new file mode 100644 (file)
index 0000000..b15b742
--- /dev/null
@@ -0,0 +1,16 @@
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(unused_braces, incomplete_features)]
+
+pub trait AnotherTrait{
+    const ARRAY_SIZE: usize;
+}
+pub trait Shard<T: AnotherTrait>:
+    AsMut<[[u8; T::ARRAY_SIZE]]>
+where
+    [(); T::ARRAY_SIZE]: Sized
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-90364.rs b/src/test/ui/const-generics/issues/issue-90364.rs
new file mode 100644 (file)
index 0000000..b11b07b
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub struct Foo<T, const H: T>(T)
+//~^ ERROR the type of const parameters must not depend on other generic parameters
+where
+    [(); 1]:;
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-90364.stderr b/src/test/ui/const-generics/issues/issue-90364.stderr
new file mode 100644 (file)
index 0000000..e85bd13
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/issue-90364.rs:4:28
+   |
+LL | pub struct Foo<T, const H: T>(T)
+   |                            ^ the type must not depend on the parameter `T`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0770`.
diff --git a/src/test/ui/consts/closure-structural-match-issue-90013.rs b/src/test/ui/consts/closure-structural-match-issue-90013.rs
new file mode 100644 (file)
index 0000000..7853ee4
--- /dev/null
@@ -0,0 +1,8 @@
+// Regression test for issue 90013.
+// check-pass
+#![allow(incomplete_features)]
+#![feature(inline_const)]
+
+fn main() {
+    const { || {} };
+}
diff --git a/src/test/ui/consts/const-eval/issue-84957-const-str-as-bytes.rs b/src/test/ui/consts/const-eval/issue-84957-const-str-as-bytes.rs
new file mode 100644 (file)
index 0000000..7e235c4
--- /dev/null
@@ -0,0 +1,28 @@
+// build-pass
+
+trait Foo {}
+
+struct Bar {
+    bytes: &'static [u8],
+    func: fn(&Box<dyn Foo>),
+}
+fn example(_: &Box<dyn Foo>) {}
+
+const BARS: &[Bar] = &[
+    Bar {
+        bytes: "0".as_bytes(),
+        func: example,
+    },
+    Bar {
+        bytes: "0".as_bytes(),
+        func: example,
+    },
+];
+
+fn main() {
+    let x = todo!();
+
+    for bar in BARS {
+        (bar.func)(&x);
+    }
+}
diff --git a/src/test/ui/consts/precise-drop-with-promoted.rs b/src/test/ui/consts/precise-drop-with-promoted.rs
new file mode 100644 (file)
index 0000000..6f2317a
--- /dev/null
@@ -0,0 +1,9 @@
+// Regression test for issue #89938.
+// check-pass
+// compile-flags: --crate-type=lib
+#![feature(const_precise_live_drops)]
+
+pub const fn f() {
+    let _: Option<String> = None;
+    let _: &'static Option<String> = &None;
+}
index 99926532247ab1c1e5d7431feea83a4983c814be..6830b23cfa345eeb6ea83e49e8a156f107aaee53 100644 (file)
@@ -39,6 +39,8 @@ pub const fn promote_union() {
     let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed
 };
 
+const TEST_DROP: String = String::new();
+
 fn main() {
     // We must not promote things with interior mutability. Not even if we "project it away".
     let _val: &'static _ = &(Cell::new(1), 2).0; //~ ERROR temporary value dropped while borrowed
@@ -50,4 +52,17 @@ fn main() {
     let _val: &'static _ = &(1%0); //~ ERROR temporary value dropped while borrowed
     let _val: &'static _ = &(1%(1-1)); //~ ERROR temporary value dropped while borrowed
     let _val: &'static _ = &([1,2,3][4]+1); //~ ERROR temporary value dropped while borrowed
+
+    // No promotion of temporaries that need to be dropped.
+    let _val: &'static _ = &TEST_DROP;
+    //~^ ERROR temporary value dropped while borrowed
+    let _val: &'static _ = &&TEST_DROP;
+    //~^ ERROR temporary value dropped while borrowed
+    //~| ERROR temporary value dropped while borrowed
+    let _val: &'static _ = &(&TEST_DROP,);
+    //~^ ERROR temporary value dropped while borrowed
+    //~| ERROR temporary value dropped while borrowed
+    let _val: &'static _ = &[&TEST_DROP; 1];
+    //~^ ERROR temporary value dropped while borrowed
+    //~| ERROR temporary value dropped while borrowed
 }
index 932109bd86dcfa6a957d09ef9a943ae358b5b970..0d0b0f9c689b5b6593d007015efb60d00f71fba3 100644 (file)
@@ -59,7 +59,7 @@ LL | };
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:44:29
+  --> $DIR/promote-not.rs:46:29
    |
 LL |     let _val: &'static _ = &(Cell::new(1), 2).0;
    |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
@@ -70,7 +70,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:45:29
+  --> $DIR/promote-not.rs:47:29
    |
 LL |     let _val: &'static _ = &(Cell::new(1), 2).1;
    |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
@@ -81,7 +81,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:48:29
+  --> $DIR/promote-not.rs:50:29
    |
 LL |     let _val: &'static _ = &(1/0);
    |               ----------    ^^^^^ creates a temporary which is freed while still in use
@@ -92,7 +92,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:49:29
+  --> $DIR/promote-not.rs:51:29
    |
 LL |     let _val: &'static _ = &(1/(1-1));
    |               ----------    ^^^^^^^^^ creates a temporary which is freed while still in use
@@ -103,7 +103,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:50:29
+  --> $DIR/promote-not.rs:52:29
    |
 LL |     let _val: &'static _ = &(1%0);
    |               ----------    ^^^^^ creates a temporary which is freed while still in use
@@ -114,26 +114,102 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:51:29
+  --> $DIR/promote-not.rs:53:29
    |
 LL |     let _val: &'static _ = &(1%(1-1));
    |               ----------    ^^^^^^^^^ creates a temporary which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
-LL |     let _val: &'static _ = &([1,2,3][4]+1);
+...
 LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:52:29
+  --> $DIR/promote-not.rs:54:29
    |
 LL |     let _val: &'static _ = &([1,2,3][4]+1);
    |               ----------    ^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
+...
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promote-not.rs:57:29
+   |
+LL |     let _val: &'static _ = &TEST_DROP;
+   |               ----------    ^^^^^^^^^ creates a temporary which is freed while still in use
+   |               |
+   |               type annotation requires that borrow lasts for `'static`
+...
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promote-not.rs:59:29
+   |
+LL |     let _val: &'static _ = &&TEST_DROP;
+   |               ----------    ^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               |
+   |               type annotation requires that borrow lasts for `'static`
+...
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promote-not.rs:59:30
+   |
+LL |     let _val: &'static _ = &&TEST_DROP;
+   |               ----------     ^^^^^^^^^ creates a temporary which is freed while still in use
+   |               |
+   |               type annotation requires that borrow lasts for `'static`
+...
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promote-not.rs:62:29
+   |
+LL |     let _val: &'static _ = &(&TEST_DROP,);
+   |               ----------    ^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               |
+   |               type annotation requires that borrow lasts for `'static`
+...
 LL | }
    | - temporary value is freed at the end of this statement
 
-error: aborting due to 13 previous errors
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promote-not.rs:62:31
+   |
+LL |     let _val: &'static _ = &(&TEST_DROP,);
+   |               ----------      ^^^^^^^^^ creates a temporary which is freed while still in use
+   |               |
+   |               type annotation requires that borrow lasts for `'static`
+...
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promote-not.rs:65:29
+   |
+LL |     let _val: &'static _ = &[&TEST_DROP; 1];
+   |               ----------    ^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+   |               |
+   |               type annotation requires that borrow lasts for `'static`
+...
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promote-not.rs:65:31
+   |
+LL |     let _val: &'static _ = &[&TEST_DROP; 1];
+   |               ----------      ^^^^^^^^^    - temporary value is freed at the end of this statement
+   |               |               |
+   |               |               creates a temporary which is freed while still in use
+   |               type annotation requires that borrow lasts for `'static`
+
+error: aborting due to 20 previous errors
 
 For more information about this error, try `rustc --explain E0716`.
diff --git a/src/test/ui/consts/promoted-const-drop.rs b/src/test/ui/consts/promoted-const-drop.rs
new file mode 100644 (file)
index 0000000..c896c01
--- /dev/null
@@ -0,0 +1,15 @@
+#![feature(const_trait_impl)]
+#![feature(const_mut_refs)]
+
+struct A();
+
+impl const Drop for A {
+    fn drop(&mut self) {}
+}
+
+const C: A = A();
+
+fn main() {
+    let _: &'static A = &A(); //~ ERROR temporary value dropped while borrowed
+    let _: &'static [A] = &[C]; //~ ERROR temporary value dropped while borrowed
+}
diff --git a/src/test/ui/consts/promoted-const-drop.stderr b/src/test/ui/consts/promoted-const-drop.stderr
new file mode 100644 (file)
index 0000000..184ba0e
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promoted-const-drop.rs:13:26
+   |
+LL |     let _: &'static A = &A();
+   |            ----------    ^^^ creates a temporary which is freed while still in use
+   |            |
+   |            type annotation requires that borrow lasts for `'static`
+LL |     let _: &'static [A] = &[C];
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promoted-const-drop.rs:14:28
+   |
+LL |     let _: &'static [A] = &[C];
+   |            ------------    ^^^ creates a temporary which is freed while still in use
+   |            |
+   |            type annotation requires that borrow lasts for `'static`
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/src/test/ui/consts/promoted-storage.rs b/src/test/ui/consts/promoted-storage.rs
new file mode 100644 (file)
index 0000000..52ef685
--- /dev/null
@@ -0,0 +1,20 @@
+// Check that storage statements reset local qualification.
+// check-pass
+use std::cell::Cell;
+
+const C: Option<Cell<u32>> = {
+    let mut c = None;
+    let mut i = 0;
+    while i == 0 {
+        let mut x = None;
+        c = x;
+        x = Some(Cell::new(0));
+        let _ = x;
+        i += 1;
+    }
+    c
+};
+
+fn main() {
+    let _: &'static _ = &C;
+}
diff --git a/src/test/ui/consts/qualif-indirect-mutation-fail.rs b/src/test/ui/consts/qualif-indirect-mutation-fail.rs
new file mode 100644 (file)
index 0000000..f74a25a
--- /dev/null
@@ -0,0 +1,64 @@
+// compile-flags: --crate-type=lib
+#![feature(const_mut_refs)]
+#![feature(const_precise_live_drops)]
+#![feature(const_swap)]
+#![feature(raw_ref_op)]
+
+// Mutable borrow of a field with drop impl.
+pub const fn f() {
+    let mut a: (u32, Option<String>) = (0, None); //~ ERROR destructors cannot be evaluated
+    let _ = &mut a.1;
+}
+
+// Mutable borrow of a type with drop impl.
+pub const A1: () = {
+    let mut x = None; //~ ERROR destructors cannot be evaluated
+    let mut y = Some(String::new());
+    let a = &mut x;
+    let b = &mut y;
+    std::mem::swap(a, b);
+    std::mem::forget(y);
+};
+
+// Mutable borrow of a type with drop impl.
+pub const A2: () = {
+    let mut x = None;
+    let mut y = Some(String::new());
+    let a = &mut x;
+    let b = &mut y;
+    std::mem::swap(a, b);
+    std::mem::forget(y);
+    let _z = x; //~ ERROR destructors cannot be evaluated
+};
+
+// Shared borrow of a type that might be !Freeze and Drop.
+pub const fn g1<T>() {
+    let x: Option<T> = None; //~ ERROR destructors cannot be evaluated
+    let _ = x.is_some();
+}
+
+// Shared borrow of a type that might be !Freeze and Drop.
+pub const fn g2<T>() {
+    let x: Option<T> = None;
+    let _ = x.is_some();
+    let _y = x; //~ ERROR destructors cannot be evaluated
+}
+
+// Mutable raw reference to a Drop type.
+pub const fn address_of_mut() {
+    let mut x: Option<String> = None; //~ ERROR destructors cannot be evaluated
+    &raw mut x;
+
+    let mut y: Option<String> = None; //~ ERROR destructors cannot be evaluated
+    std::ptr::addr_of_mut!(y);
+}
+
+// Const raw reference to a Drop type. Conservatively assumed to allow mutation
+// until resolution of https://github.com/rust-lang/rust/issues/56604.
+pub const fn address_of_const() {
+    let x: Option<String> = None; //~ ERROR destructors cannot be evaluated
+    &raw const x;
+
+    let y: Option<String> = None; //~ ERROR destructors cannot be evaluated
+    std::ptr::addr_of!(y);
+}
diff --git a/src/test/ui/consts/qualif-indirect-mutation-fail.stderr b/src/test/ui/consts/qualif-indirect-mutation-fail.stderr
new file mode 100644 (file)
index 0000000..713df12
--- /dev/null
@@ -0,0 +1,57 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/qualif-indirect-mutation-fail.rs:9:9
+   |
+LL |     let mut a: (u32, Option<String>) = (0, None);
+   |         ^^^^^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/qualif-indirect-mutation-fail.rs:15:9
+   |
+LL |     let mut x = None;
+   |         ^^^^^ constants cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/qualif-indirect-mutation-fail.rs:31:9
+   |
+LL |     let _z = x;
+   |         ^^ constants cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/qualif-indirect-mutation-fail.rs:36:9
+   |
+LL |     let x: Option<T> = None;
+   |         ^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/qualif-indirect-mutation-fail.rs:44:9
+   |
+LL |     let _y = x;
+   |         ^^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/qualif-indirect-mutation-fail.rs:52:9
+   |
+LL |     let mut y: Option<String> = None;
+   |         ^^^^^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/qualif-indirect-mutation-fail.rs:49:9
+   |
+LL |     let mut x: Option<String> = None;
+   |         ^^^^^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/qualif-indirect-mutation-fail.rs:62:9
+   |
+LL |     let y: Option<String> = None;
+   |         ^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/qualif-indirect-mutation-fail.rs:59:9
+   |
+LL |     let x: Option<String> = None;
+   |         ^ constant functions cannot evaluate destructors
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/qualif-indirect-mutation-pass.rs b/src/test/ui/consts/qualif-indirect-mutation-pass.rs
new file mode 100644 (file)
index 0000000..06af6a0
--- /dev/null
@@ -0,0 +1,24 @@
+// compile-flags: --crate-type=lib
+// check-pass
+#![feature(const_mut_refs)]
+#![feature(const_precise_live_drops)]
+
+// Mutable reference allows only mutation of !Drop place.
+pub const fn f() {
+    let mut x: (Option<String>, u32) = (None, 0);
+    let mut a = 10;
+    *(&mut a) = 11;
+    x.1 = a;
+}
+
+// Mutable reference allows only mutation of !Drop place.
+pub const fn g() {
+    let mut a: (u32, Option<String>) = (0, None);
+    let _ = &mut a.0;
+}
+
+// Shared reference does not allow for mutation.
+pub const fn h() {
+    let x: Option<String> = None;
+    let _ = &x;
+}
diff --git a/src/test/ui/consts/qualif-union.rs b/src/test/ui/consts/qualif-union.rs
new file mode 100644 (file)
index 0000000..2054b5b
--- /dev/null
@@ -0,0 +1,32 @@
+// Checks that unions use type based qualification. Regression test for issue #90268.
+#![feature(untagged_unions)]
+use std::cell::Cell;
+
+union U { i: u32, c: Cell<u32> }
+
+const C1: Cell<u32> = {
+    unsafe { U { c: Cell::new(0) }.c }
+};
+
+const C2: Cell<u32> = {
+    unsafe { U { i : 0 }.c }
+};
+
+const C3: Cell<u32> = {
+    let mut u = U { i: 0 };
+    u.i = 1;
+    unsafe { u.c }
+};
+
+const C4: U = U { i: 0 };
+
+const C5: [U; 1] = [U {i : 0}; 1];
+
+fn main() {
+    // Interior mutability should prevent promotion.
+    let _: &'static _ = &C1; //~ ERROR temporary value dropped while borrowed
+    let _: &'static _ = &C2; //~ ERROR temporary value dropped while borrowed
+    let _: &'static _ = &C3; //~ ERROR temporary value dropped while borrowed
+    let _: &'static _ = &C4; //~ ERROR temporary value dropped while borrowed
+    let _: &'static _ = &C5; //~ ERROR temporary value dropped while borrowed
+}
diff --git a/src/test/ui/consts/qualif-union.stderr b/src/test/ui/consts/qualif-union.stderr
new file mode 100644 (file)
index 0000000..fda8ad4
--- /dev/null
@@ -0,0 +1,57 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/qualif-union.rs:27:26
+   |
+LL |     let _: &'static _ = &C1;
+   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            |
+   |            type annotation requires that borrow lasts for `'static`
+...
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/qualif-union.rs:28:26
+   |
+LL |     let _: &'static _ = &C2;
+   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            |
+   |            type annotation requires that borrow lasts for `'static`
+...
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/qualif-union.rs:29:26
+   |
+LL |     let _: &'static _ = &C3;
+   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            |
+   |            type annotation requires that borrow lasts for `'static`
+...
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/qualif-union.rs:30:26
+   |
+LL |     let _: &'static _ = &C4;
+   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            |
+   |            type annotation requires that borrow lasts for `'static`
+LL |     let _: &'static _ = &C5;
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/qualif-union.rs:31:26
+   |
+LL |     let _: &'static _ = &C5;
+   |            ----------    ^^ creates a temporary which is freed while still in use
+   |            |
+   |            type annotation requires that borrow lasts for `'static`
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
index f15be95db1024fa032db4bfcf05fb2db2f16fd50..b56eedeb80d16a1080861467b6c8a91a011264b5 100644 (file)
@@ -6,12 +6,12 @@ LL | #[deprecated = b"test"]
    |
 help: the following are the possible correct uses
    |
-LL | #[deprecated]
-   | ~~~~~~~~~~~~~
-LL | #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
-   | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL | #[deprecated = "reason"]
    | ~~~~~~~~~~~~~~~~~~~~~~~~
+LL | #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+   | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | #[deprecated]
+   | ~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
index 89186817e099c167bdbefd8181d650ea66adc87d..47c7f1c2c33408ec70a5ec983f934a8b81cef8a0 100644 (file)
@@ -11,7 +11,7 @@ note: required by a bound in `std::hash::Hash::hash`
   --> $SRC_DIR/core/src/hash/mod.rs:LL:COL
    |
 LL |     fn hash<H: Hasher>(&self, state: &mut H);
-   |                ^^^^^^ required by this bound in `std::hash::Hash::hash`
+   |             ^ required by this bound in `std::hash::Hash::hash`
    = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
index 6abb7e78b1330739de9c3b7f1eeae8c0b4b752fe..92f084b58e35be50a69503ed7ff9617a4dadad88 100644 (file)
@@ -11,7 +11,7 @@ note: required by a bound in `std::hash::Hash::hash`
   --> $SRC_DIR/core/src/hash/mod.rs:LL:COL
    |
 LL |     fn hash<H: Hasher>(&self, state: &mut H);
-   |                ^^^^^^ required by this bound in `std::hash::Hash::hash`
+   |             ^ required by this bound in `std::hash::Hash::hash`
    = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
index 405285f8838104aea1329776f06e7216e86e49e2..c57cebe04ebcbacb0e07e616ebefc10cbae2c9ba 100644 (file)
@@ -11,7 +11,7 @@ note: required by a bound in `std::hash::Hash::hash`
   --> $SRC_DIR/core/src/hash/mod.rs:LL:COL
    |
 LL |     fn hash<H: Hasher>(&self, state: &mut H);
-   |                ^^^^^^ required by this bound in `std::hash::Hash::hash`
+   |             ^ required by this bound in `std::hash::Hash::hash`
    = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
index aa12314c051762dd147457ee3981b2a6034af0d8..200937f0c9fc380dbaee757da9f1a166c6ed0dc5 100644 (file)
@@ -11,7 +11,7 @@ note: required by a bound in `std::hash::Hash::hash`
   --> $SRC_DIR/core/src/hash/mod.rs:LL:COL
    |
 LL |     fn hash<H: Hasher>(&self, state: &mut H);
-   |                ^^^^^^ required by this bound in `std::hash::Hash::hash`
+   |             ^ required by this bound in `std::hash::Hash::hash`
    = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
index b339ce5ce8c923b96bba91f9581261d0dbddb53a..bc8a93757a5994288cdd9aa9856433338fb78abf 100644 (file)
@@ -8,10 +8,10 @@ LL |     this_function_expects_a_double_option(n);
               found type `usize`
 help: try using a variant of the expected enum
    |
-LL |     this_function_expects_a_double_option(DoubleOption::FirstSome(n));
-   |                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL |     this_function_expects_a_double_option(DoubleOption::AlternativeSome(n));
    |                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     this_function_expects_a_double_option(DoubleOption::FirstSome(n));
+   |                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0308]: mismatched types
   --> $DIR/issue-42764.rs:27:33
index 1023950639a662c8daf2cae6b6d3ac8ff63890e4..26bfc4355fa114d4398ee2dc639aa1c9d8ae506f 100644 (file)
@@ -20,7 +20,7 @@ LL |     let e4 = E::Empty4();
    |              |
    |              call expression requires function
    |
-help: `E::Empty4` is a unit variant, you need to write it without the parenthesis
+help: `E::Empty4` is a unit variant, you need to write it without the parentheses
    |
 LL |     let e4 = E::Empty4;
    |              ~~~~~~~~~
@@ -41,7 +41,7 @@ LL |     let xe4 = XE::XEmpty4();
    |               |
    |               call expression requires function
    |
-help: `XE::XEmpty4` is a unit variant, you need to write it without the parenthesis
+help: `XE::XEmpty4` is a unit variant, you need to write it without the parentheses
    |
 LL |     let xe4 = XE::XEmpty4;
    |               ~~~~~~~~~~~
index 2839688f34240e05fa14f5d1f428b2ffd82c3b3c..e8c70b06513c28b59bd14e072ce4a2db784b7264 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(imported_main)]
-//~^ ERROR `main` is ambiguous (glob import vs glob import in the same module)
+//~^ ERROR `main` is ambiguous
 mod m1 { pub(crate) fn main() {} }
 mod m2 { pub(crate) fn main() {} }
 
index 36cb98d94e69a23c898c77aa50e4fb2c78b4c726..8fadd0e19b395a83b3b0bbb98b3598843478dc80 100644 (file)
@@ -1,5 +1,6 @@
-error[E0659]: `main` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `main` is ambiguous
    |
+   = note: ambiguous because of multiple glob imports of a name in the same module
 note: `main` could refer to the function imported here
   --> $DIR/imported_main_conflict.rs:6:5
    |
diff --git a/src/test/ui/enum-discriminant/issue-90038.rs b/src/test/ui/enum-discriminant/issue-90038.rs
new file mode 100644 (file)
index 0000000..5e98ecc
--- /dev/null
@@ -0,0 +1,21 @@
+// run-pass
+
+#[repr(u32)]
+pub enum Foo {
+    // Greater than or equal to 2
+    A = 2,
+}
+
+pub enum Bar {
+    A(Foo),
+    // More than two const variants
+    B,
+    C,
+}
+
+fn main() {
+    match Bar::A(Foo::A) {
+        Bar::A(_) => (),
+        _ => unreachable!(),
+    }
+}
index b6078e302360612b8f7c218c8942345c99b57957..95437bf11adecf9229393d7e458e5346214b640f 100644 (file)
@@ -21,7 +21,14 @@ LL |     let bar = foo_impl.into() * 1u32;
    |               this method call resolves to `T`
    |               help: use the fully qualified path for the potential candidate: `<Impl as Into<u32>>::into(foo_impl)`
    |
-   = note: cannot satisfy `Impl: Into<_>`
+note: multiple `impl`s satisfying `Impl: Into<_>` found
+  --> $DIR/E0283.rs:17:1
+   |
+LL | impl Into<u32> for Impl {
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+   = note: and another `impl` found in the `core` crate:
+           - impl<T, U> Into<U> for T
+             where U: From<T>;
 
 error: aborting due to 2 previous errors
 
index 19a1a8e20ccfa8c925b79042f4b46b80403db36a..db1b3f098374e5bf51a92faf3ca88d60a990a13e 100644 (file)
@@ -9,7 +9,7 @@ LL |     X::Entry();
    |     |
    |     call expression requires function
    |
-help: `X::Entry` is a unit variant, you need to write it without the parenthesis
+help: `X::Entry` is a unit variant, you need to write it without the parentheses
    |
 LL |     X::Entry;
    |     ~~~~~~~~
index b4888d4af6a218a9498e626b813b19e6a76b2cdf..382ce3ed01f34d4a0c16ded758903db59c287daa 100644 (file)
@@ -1,9 +1,17 @@
-struct Foo<'a: '_>(&'a u8); //~ ERROR cannot be used here
-fn foo<'a: '_>(_: &'a u8) {} //~ ERROR cannot be used here
+fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
+    //~^ ERROR: `'_` cannot be used here [E0637]
+    //~| ERROR: missing lifetime specifier
+    if str1.len() > str2.len() {
+        str1
+    } else {
+        str2
+    }
+}
 
-struct Bar<'a>(&'a u8);
-impl<'a: '_> Bar<'a> { //~ ERROR cannot be used here
-  fn bar() {}
+fn and_without_explicit_lifetime<T>()
+where
+    T: Into<&u32>, //~ ERROR: `&` without an explicit lifetime name cannot be used here [E0637]
+{
 }
 
 fn main() {}
index d19ebfd15a52cd341a22a7107c3544ece3a295ea..87aaba65a73adc431a8f24e3787ddda67edb05b2 100644 (file)
@@ -1,21 +1,28 @@
 error[E0637]: `'_` cannot be used here
-  --> $DIR/E0637.rs:1:16
+  --> $DIR/E0637.rs:1:24
    |
-LL | struct Foo<'a: '_>(&'a u8);
-   |                ^^ `'_` is a reserved lifetime name
+LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
+   |                        ^^ `'_` is a reserved lifetime name
 
-error[E0637]: `'_` cannot be used here
-  --> $DIR/E0637.rs:2:12
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/E0637.rs:13:13
    |
-LL | fn foo<'a: '_>(_: &'a u8) {}
-   |            ^^ `'_` is a reserved lifetime name
+LL |     T: Into<&u32>,
+   |             ^ explicit lifetime name needed here
 
-error[E0637]: `'_` cannot be used here
-  --> $DIR/E0637.rs:5:10
+error[E0106]: missing lifetime specifier
+  --> $DIR/E0637.rs:1:62
+   |
+LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
+   |                                  -------        -------      ^^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `str1` or `str2`
+help: consider introducing a named lifetime parameter
    |
-LL | impl<'a: '_> Bar<'a> {
-   |          ^^ `'_` is a reserved lifetime name
+LL | fn underscore_lifetime<'a, '_>(str1: &'a str, str2: &'a str) -> &'a str {
+   |                        +++            ~~             ~~          ~~
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0637`.
+Some errors have detailed explanations: E0106, E0637.
+For more information about an error, try `rustc --explain E0106`.
index 2f01f54c2d1ce5863eae6ab8a82b92afdc219939..b0c73c636c62ffd0a95dfef75f82bdb1e3bb26dd 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `foo` is ambiguous
   --> $DIR/E0659.rs:15:15
    |
 LL |     collider::foo();
    |               ^^^ ambiguous name
    |
+   = note: ambiguous because of multiple glob imports of a name in the same module
 note: `foo` could refer to the function imported here
   --> $DIR/E0659.rs:10:13
    |
index 3909b5301ade5ab672919e9d373c6692200b9d87..22792c11366ba3dda38e1d4102b264d8f2e661c9 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// only-i686
+// only-x86
 
 trait A {
     extern "fastcall" fn test1(i: i32);
index 8ce94aa71aae6e9172fc0fbfd7be185e49a22e75..717df57ec48485d2b57e56a729927dca03abfb38 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// only-i686
+// only-x86
 
 #![feature(abi_thiscall)]
 
index f625eb0890f05dc5efbd4b400f904b3038be6a0c..a283573c9fbd11afa437bf2884445766af3ecdbb 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 // revisions: x64 x32
 // [x64]only-x86_64
-// [x32]only-i686
+// [x32]only-x86
 
 #![feature(abi_vectorcall)]
 
diff --git a/src/test/ui/feature-gates/feature-gate-relaxed_struct_unsize.rs b/src/test/ui/feature-gates/feature-gate-relaxed_struct_unsize.rs
deleted file mode 100644 (file)
index 0cfd0a0..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// Test that we allow unsizing even if there is an unchanged param in the
-// field getting unsized.
-struct A<T, U: ?Sized + 'static>(T, B<T, U>);
-struct B<T, U: ?Sized>(T, U);
-
-fn main() {
-    let x: A<[u32; 1], [u32; 1]> = A([0; 1], B([0; 1], [0; 1]));
-    let y: &A<[u32; 1], [u32]> = &x; //~ ERROR mismatched types
-    assert_eq!(y.1.1.len(), 1);
-}
diff --git a/src/test/ui/feature-gates/feature-gate-relaxed_struct_unsize.stderr b/src/test/ui/feature-gates/feature-gate-relaxed_struct_unsize.stderr
deleted file mode 100644 (file)
index f62def4..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/feature-gate-relaxed_struct_unsize.rs:8:34
-   |
-LL |     let y: &A<[u32; 1], [u32]> = &x;
-   |            -------------------   ^^ expected slice `[u32]`, found array `[u32; 1]`
-   |            |
-   |            expected due to this
-   |
-   = note: expected reference `&A<[u32; 1], [u32]>`
-              found reference `&A<[u32; 1], [u32; 1]>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/feature-gates/feature-gate-type_changing_struct_update.rs b/src/test/ui/feature-gates/feature-gate-type_changing_struct_update.rs
new file mode 100644 (file)
index 0000000..520c147
--- /dev/null
@@ -0,0 +1,26 @@
+#[derive(Debug)]
+struct Machine<S> {
+    state: S,
+    common_field1: &'static str,
+    common_field2: i32,
+}
+#[derive(Debug)]
+struct State1;
+#[derive(Debug, PartialEq)]
+struct State2;
+
+fn update_to_state2() {
+    let m1: Machine<State1> = Machine {
+        state: State1,
+        common_field1: "hello",
+        common_field2: 2,
+    };
+    let m2: Machine<State2> = Machine {
+        state: State2,
+        ..m1 //~ ERROR mismatched types
+    };
+    // FIXME: this should trigger feature gate
+    assert_eq!(State2, m2.state);
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-type_changing_struct_update.stderr b/src/test/ui/feature-gates/feature-gate-type_changing_struct_update.stderr
new file mode 100644 (file)
index 0000000..9934fe6
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/feature-gate-type_changing_struct_update.rs:20:11
+   |
+LL |         ..m1
+   |           ^^ expected struct `State2`, found struct `State1`
+   |
+   = note: expected struct `Machine<State2>`
+              found struct `Machine<State1>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index c0d2df3753d2ca7756724dedf6b32425eeb20c47..9a12851f20e5f87036c7c04249d99b6ebf2d557c 100644 (file)
@@ -24,10 +24,10 @@ LL |     #[macro_use = "2700"] struct S;
    |
 help: the following are the possible correct uses
    |
-LL |     #[macro_use] struct S;
-   |     ~~~~~~~~~~~~
 LL |     #[macro_use(name1, name2, ...)] struct S;
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     #[macro_use] struct S;
+   |     ~~~~~~~~~~~~
 
 error: aborting due to 4 previous errors
 
index a036d10e6390248afc0966c5a30f7ff416372a0a..855749c14b9c3dc60bd5eb103c4cb914b9f6f96e 100644 (file)
@@ -1,4 +1,3 @@
-// min-llvm-version: 12.0
 // compile-flags: -C opt-level=3
 // run-pass
 
index d5cc5cfbe912d41e3bd81b9122207a26d42466cb..49ae87cbfe9dce4c73f81b0149d4bb6c6eabaa53 100644 (file)
@@ -1,34 +1,34 @@
-error[E0277]: the size for values of type `Self` cannot be known at compilation time
+error[E0277]: the trait bound `Self: Trait1` is not satisfied
   --> $DIR/issue-74816.rs:9:5
    |
 LL |     type Associated: Trait1 = Self;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait1` is not implemented for `Self`
    |
 note: required by a bound in `Trait2::Associated`
-  --> $DIR/issue-74816.rs:9:5
+  --> $DIR/issue-74816.rs:9:22
    |
 LL |     type Associated: Trait1 = Self;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait2::Associated`
+   |                      ^^^^^^ required by this bound in `Trait2::Associated`
 help: consider further restricting `Self`
    |
-LL | trait Trait2: Sized {
-   |             +++++++
+LL | trait Trait2: Trait1 {
+   |             ++++++++
 
-error[E0277]: the trait bound `Self: Trait1` is not satisfied
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
   --> $DIR/issue-74816.rs:9:5
    |
 LL |     type Associated: Trait1 = Self;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait1` is not implemented for `Self`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
 note: required by a bound in `Trait2::Associated`
-  --> $DIR/issue-74816.rs:9:22
+  --> $DIR/issue-74816.rs:9:5
    |
 LL |     type Associated: Trait1 = Self;
-   |                      ^^^^^^ required by this bound in `Trait2::Associated`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait2::Associated`
 help: consider further restricting `Self`
    |
-LL | trait Trait2: Trait1 {
-   |             ++++++++
+LL | trait Trait2: Sized {
+   |             +++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/generic-associated-types/issue-85921.rs b/src/test/ui/generic-associated-types/issue-85921.rs
new file mode 100644 (file)
index 0000000..df59f49
--- /dev/null
@@ -0,0 +1,19 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+
+trait Trait {
+    type Assoc<'a>;
+
+    fn with_assoc(f: impl FnOnce(Self::Assoc<'_>));
+}
+
+impl Trait for () {
+    type Assoc<'a> = i32;
+
+    fn with_assoc(f: impl FnOnce(Self::Assoc<'_>)) {
+        f(5i32)
+    }
+}
+
+fn main() {}
index 5d0fcbca552d6f09b24fef24ffddd6d132a192cc..d6978794e1e957304cda22c17a6f820f59cbf609 100644 (file)
@@ -20,13 +20,13 @@ LL |     for<'a> T: 'a,
    |                ^^
 
 error[E0311]: the parameter type `T` may not live long enough
-  --> $DIR/issue-86483.rs:9:19
+  --> $DIR/issue-86483.rs:9:5
    |
 LL | pub trait IceIce<T>
    |                  - help: consider adding an explicit lifetime bound...: `T: 'a`
 ...
 LL |     type Ice<'v>: IntoIterator<Item = &'v T>;
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
    |
 note: ...that is required by this bound
   --> $DIR/issue-86483.rs:7:16
diff --git a/src/test/ui/generic-associated-types/issue-87258_a.rs b/src/test/ui/generic-associated-types/issue-87258_a.rs
new file mode 100644 (file)
index 0000000..d9d1775
--- /dev/null
@@ -0,0 +1,24 @@
+#![feature(type_alias_impl_trait)]
+#![feature(generic_associated_types)]
+
+// See https://github.com/rust-lang/rust/issues/87258#issuecomment-883293367
+
+trait Trait1 {}
+
+struct Struct<'b>(&'b ());
+
+impl<'d> Trait1 for Struct<'d> {}
+
+pub trait Trait2 {
+    type FooFuture<'a>: Trait1;
+    fn foo<'a>() -> Self::FooFuture<'a>;
+}
+
+impl<'c, S: Trait2> Trait2 for &'c mut S {
+    type FooFuture<'a> = impl Trait1;
+    fn foo<'a>() -> Self::FooFuture<'a> { //~ ERROR
+        Struct(unimplemented!())
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-87258_a.stderr b/src/test/ui/generic-associated-types/issue-87258_a.stderr
new file mode 100644 (file)
index 0000000..93513a4
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/issue-87258_a.rs:19:21
+   |
+LL |     fn foo<'a>() -> Self::FooFuture<'a> {
+   |                     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: hidden type `Struct<'_>` captures lifetime '_#7r
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/src/test/ui/generic-associated-types/issue-87258_b.rs b/src/test/ui/generic-associated-types/issue-87258_b.rs
new file mode 100644 (file)
index 0000000..b29a978
--- /dev/null
@@ -0,0 +1,26 @@
+#![feature(type_alias_impl_trait)]
+#![feature(generic_associated_types)]
+
+// See https://github.com/rust-lang/rust/issues/87258#issuecomment-883293367
+
+trait Trait1 {}
+
+struct Struct<'b>(&'b ());
+
+impl<'d> Trait1 for Struct<'d> {}
+
+pub trait Trait2 {
+    type FooFuture<'a>: Trait1;
+    fn foo<'a>() -> Self::FooFuture<'a>;
+}
+
+type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1;
+
+impl<'c, S: Trait2> Trait2 for &'c mut S {
+    type FooFuture<'a> = Helper<'c, 'a, S>;
+    fn foo<'a>() -> Self::FooFuture<'a> { //~ ERROR
+        Struct(unimplemented!())
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-87258_b.stderr b/src/test/ui/generic-associated-types/issue-87258_b.stderr
new file mode 100644 (file)
index 0000000..e077a42
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/issue-87258_b.rs:21:21
+   |
+LL |     fn foo<'a>() -> Self::FooFuture<'a> {
+   |                     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: hidden type `Struct<'_>` captures lifetime '_#7r
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/src/test/ui/generic-associated-types/issue-88459.rs b/src/test/ui/generic-associated-types/issue-88459.rs
new file mode 100644 (file)
index 0000000..3b26a18
--- /dev/null
@@ -0,0 +1,19 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+
+trait Trait {
+    type Assoc<'a>;
+}
+
+fn f<T: Trait>(_: T, _: impl Fn(T::Assoc<'_>)) {}
+
+struct Type;
+
+impl Trait for Type {
+    type Assoc<'a> = ();
+}
+
+fn main() {
+    f(Type, |_|());
+}
index 50f90618e4db70d8c5e58c9f9cc913392fe46021..2c397d80b013eef1ba385258632c4522aaa3c73e 100644 (file)
@@ -6,10 +6,10 @@ LL | impl Tsized for () {}
    |
    = help: the trait `Sized` is not implemented for `[()]`
 note: required by a bound in `Tsized`
-  --> $DIR/issue-61631-default-type-param-can-reference-self-in-trait.rs:17:17
+  --> $DIR/issue-61631-default-type-param-can-reference-self-in-trait.rs:17:14
    |
 LL | trait Tsized<P: Sized = [Self]> {}
-   |                 ^^^^^ required by this bound in `Tsized`
+   |              ^ required by this bound in `Tsized`
 
 error: aborting due to previous error
 
index 738f151b0f60b17c8aee1845f5123bb30114a8b2..134d8af5bfb8aba42320695460111a4b87ca45cf 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 // edition:2021
-// compile-flags: -Zunstable-options
 
 fn main() {
     println!("hello, 2021");
diff --git a/src/test/ui/hidden-doc-associated-item.rs b/src/test/ui/hidden-doc-associated-item.rs
new file mode 100644 (file)
index 0000000..d431f9e
--- /dev/null
@@ -0,0 +1,15 @@
+// check-pass
+// See issue #85526.
+// This test should produce no warnings.
+
+#![deny(missing_docs)]
+//! Crate docs
+
+#[doc(hidden)]
+pub struct Foo;
+
+impl Foo {
+    pub fn bar() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-44005.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-44005.rs
new file mode 100644 (file)
index 0000000..f255eac
--- /dev/null
@@ -0,0 +1,31 @@
+// check-pass
+
+pub trait Foo<'a> {
+    type Bar;
+    fn foo(&'a self) -> Self::Bar;
+}
+
+impl<'a, 'b, T: 'a> Foo<'a> for &'b T {
+    type Bar = &'a T;
+    fn foo(&'a self) -> &'a T {
+        self
+    }
+}
+
+pub fn uncallable<T, F>(x: T, f: F)
+where
+    T: for<'a> Foo<'a>,
+    F: for<'a> Fn(<T as Foo<'a>>::Bar),
+{
+    f(x.foo());
+}
+
+pub fn catalyst(x: &i32) {
+    broken(x, |_| {})
+}
+
+pub fn broken<F: Fn(&i32)>(x: &i32, f: F) {
+    uncallable(x, |y| f(y));
+}
+
+fn main() {}
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-56556.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-56556.rs
new file mode 100644 (file)
index 0000000..768d1c3
--- /dev/null
@@ -0,0 +1,13 @@
+// check-pass
+
+fn foo<T>(t: T) -> usize
+where
+    for<'a> &'a T: IntoIterator,
+    for<'a> <&'a T as IntoIterator>::IntoIter: ExactSizeIterator,
+{
+    t.into_iter().len()
+}
+
+fn main() {
+    foo::<Vec<u32>>(vec![]);
+}
index 24ac566f9df0c646061a912dbc1ad503a560f096..7c3c72e04cb781d32091328e33310422e858e473 100644 (file)
@@ -77,7 +77,7 @@ fn task<P>(processor: P) -> Task
 }
 
 fn main() {
-    task(annotate( //~ type mismatch
+    task(annotate(
         //~^ the size
         //~^^ the trait bound
         Annotate::<RefMutFamily<usize>>::new(),
index b13226fef6e76fe7ada4ad5948fa3f7428d26faa..01b14660b6531aa98a6f17f289e90aba6d632ebb 100644 (file)
@@ -1,29 +1,3 @@
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/issue-62529-1.rs:80:10
-   |
-LL |       task(annotate(
-   |  _____----_^
-   | |     |
-   | |     required by a bound introduced by this call
-LL | |
-LL | |
-LL | |         Annotate::<RefMutFamily<usize>>::new(),
-LL | |         |value: &mut usize| {
-   | |         ------------------- found signature of `for<'r> fn(&'r mut usize) -> _`
-LL | |             *value = 2;
-LL | |         }
-LL | |     ));
-   | |_____^ expected signature of `for<'r> fn(<RefMutFamily<usize> as FamilyLt<'r>>::Out) -> _`
-   |
-note: required by a bound in `annotate`
-  --> $DIR/issue-62529-1.rs:44:8
-   |
-LL | fn annotate<F, Q>(_q: Annotate<Q>, func: F) -> impl Execute + 'static
-   |    -------- required by a bound in this
-LL | where
-LL |     F: for<'r> FnOnce(<<Q as Inject>::I as FamilyLt<'r>>::Out) + 'static,
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `annotate`
-
 error[E0277]: the size for values of type `impl Execute` cannot be known at compilation time
   --> $DIR/issue-62529-1.rs:80:10
    |
@@ -73,7 +47,6 @@ LL | fn task<P>(processor: P) -> Task
 LL | where P: Execute + 'static {
    |          ^^^^^^^ required by this bound in `task`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0277, E0631.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0277`.
index 87d1a250f7ae6dd3b47729605b0ae210272f65e2..3ced40230f012033de6307c24ac43f1001144b1a 100644 (file)
@@ -1,3 +1,5 @@
+// check-pass
+
 pub trait MyTrait<'a> {
     type Output: 'a;
     fn gimme_value(&self) -> Self::Output;
@@ -23,7 +25,7 @@ fn meow<T, F>(t: T, f: F)
 
 fn main() {
     let struc = MyStruct;
-    meow(struc, |foo| { //~ type mismatch
+    meow(struc, |foo| {
         println!("{:?}", foo);
     })
 }
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.stderr
deleted file mode 100644 (file)
index efc9568..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/issue-70120.rs:26:5
-   |
-LL |     meow(struc, |foo| {
-   |     ^^^^        ----- found signature of `for<'r> fn(&'r usize) -> _`
-   |     |
-   |     expected signature of `for<'any2> fn(<MyStruct as MyTrait<'any2>>::Output) -> _`
-   |
-note: required by a bound in `meow`
-  --> $DIR/issue-70120.rs:18:8
-   |
-LL | fn meow<T, F>(t: T, f: F)
-   |    ---- required by a bound in this
-...
-LL |     F: for<'any2> Fn(<T as MyTrait<'any2>>::Output),
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `meow`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr
new file mode 100644 (file)
index 0000000..119cec1
--- /dev/null
@@ -0,0 +1,92 @@
+error: implementation of `Parser` is not general enough
+  --> $DIR/issue-71955.rs:52:5
+   |
+LL |     foo(bar, "string", |s| s.len() == 5);
+   |     ^^^ implementation of `Parser` is not general enough
+   |
+   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+  --> $DIR/issue-71955.rs:52:5
+   |
+LL |     foo(bar, "string", |s| s.len() == 5);
+   |     ^^^ implementation of `Parser` is not general enough
+   |
+   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+  --> $DIR/issue-71955.rs:52:5
+   |
+LL |     foo(bar, "string", |s| s.len() == 5);
+   |     ^^^ implementation of `Parser` is not general enough
+   |
+   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+  --> $DIR/issue-71955.rs:52:5
+   |
+LL |     foo(bar, "string", |s| s.len() == 5);
+   |     ^^^ implementation of `Parser` is not general enough
+   |
+   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+  --> $DIR/issue-71955.rs:52:5
+   |
+LL |     foo(bar, "string", |s| s.len() == 5);
+   |     ^^^ implementation of `Parser` is not general enough
+   |
+   = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+  --> $DIR/issue-71955.rs:58:5
+   |
+LL |     foo(baz, "string", |s| s.0.len() == 5);
+   |     ^^^ implementation of `Parser` is not general enough
+   |
+   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+  --> $DIR/issue-71955.rs:58:5
+   |
+LL |     foo(baz, "string", |s| s.0.len() == 5);
+   |     ^^^ implementation of `Parser` is not general enough
+   |
+   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+  --> $DIR/issue-71955.rs:58:5
+   |
+LL |     foo(baz, "string", |s| s.0.len() == 5);
+   |     ^^^ implementation of `Parser` is not general enough
+   |
+   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+  --> $DIR/issue-71955.rs:58:5
+   |
+LL |     foo(baz, "string", |s| s.0.len() == 5);
+   |     ^^^ implementation of `Parser` is not general enough
+   |
+   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+  --> $DIR/issue-71955.rs:58:5
+   |
+LL |     foo(baz, "string", |s| s.0.len() == 5);
+   |     ^^^ implementation of `Parser` is not general enough
+   |
+   = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+   = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr
new file mode 100644 (file)
index 0000000..69ab446
--- /dev/null
@@ -0,0 +1,8 @@
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/issue-71955.rs:42:1
+   |
+LL | fn main() {
+   | ^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs
new file mode 100644 (file)
index 0000000..95e3b3d
--- /dev/null
@@ -0,0 +1,64 @@
+// ignore-compare-mode-nll
+// revisions: migrate nll
+// [nll]compile-flags: -Zborrowck=mir
+// check-fail
+
+#![feature(rustc_attrs)]
+
+trait Parser<'s> {
+    type Output;
+
+    fn call(&self, input: &'s str) -> (&'s str, Self::Output);
+}
+
+impl<'s, F, T> Parser<'s> for F
+where F: Fn(&'s str) -> (&'s str, T) {
+    type Output = T;
+    fn call(&self, input: &'s str) -> (&'s str, T) {
+        self(input)
+    }
+}
+
+fn foo<F1, F2>(
+    f1: F1,
+    base: &'static str,
+    f2: F2
+)
+where
+    F1: for<'a> Parser<'a>,
+    F2: FnOnce(&<F1 as Parser>::Output) -> bool
+{
+    let s: String = base.to_owned();
+    let str_ref = s.as_ref();
+    let (remaining, produced) = f1.call(str_ref);
+    assert!(f2(&produced));
+    assert_eq!(remaining.len(), 0);
+}
+
+struct Wrapper<'a>(&'a str);
+
+// Because nll currently succeeds and migrate doesn't
+#[rustc_error]
+fn main() {
+    //[nll]~^ fatal
+    fn bar<'a>(s: &'a str) -> (&'a str, &'a str) {
+        (&s[..1], &s[..])
+    }
+
+    fn baz<'a>(s: &'a str) -> (&'a str, Wrapper<'a>) {
+        (&s[..1], Wrapper(&s[..]))
+    }
+
+    foo(bar, "string", |s| s.len() == 5);
+    //[migrate]~^ ERROR implementation of `Parser` is not general enough
+    //[migrate]~| ERROR implementation of `Parser` is not general enough
+    //[migrate]~| ERROR implementation of `Parser` is not general enough
+    //[migrate]~| ERROR implementation of `Parser` is not general enough
+    //[migrate]~| ERROR implementation of `Parser` is not general enough
+    foo(baz, "string", |s| s.0.len() == 5);
+    //[migrate]~^ ERROR implementation of `Parser` is not general enough
+    //[migrate]~| ERROR implementation of `Parser` is not general enough
+    //[migrate]~| ERROR implementation of `Parser` is not general enough
+    //[migrate]~| ERROR implementation of `Parser` is not general enough
+    //[migrate]~| ERROR implementation of `Parser` is not general enough
+}
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-74261.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-74261.rs
new file mode 100644 (file)
index 0000000..93ccb42
--- /dev/null
@@ -0,0 +1,30 @@
+// check-pass
+
+use std::marker::PhantomData;
+
+trait A<'a> {
+    type B;
+    fn b(self) -> Self::B;
+}
+
+struct T;
+struct S<'a>(PhantomData<&'a ()>);
+
+impl<'a> A<'a> for T {
+    type B = S<'a>;
+    fn b(self) -> Self::B {
+        S(PhantomData)
+    }
+}
+
+fn s<TT, F>(t: TT, f: F)
+where
+    TT: for<'a> A<'a>,
+    F: for<'a> FnOnce(<TT as A<'a>>::B)
+{
+    f(t.b());
+}
+
+fn main() {
+    s(T, |_| {});
+}
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-76956.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-76956.rs
new file mode 100644 (file)
index 0000000..5834700
--- /dev/null
@@ -0,0 +1,15 @@
+// check-pass
+
+use std::ops::Deref;
+
+struct Data {
+    boxed: Box<&'static i32>
+}
+
+impl Data {
+    fn use_data(&self, user: impl for <'a> FnOnce(<Box<&'a i32> as Deref>::Target)) {
+        user(*self.boxed)
+    }
+}
+
+fn main() {}
index 454d7e5e9cdea8c97c43968bcb2ff226ed3bb8ae..80f099ce3c80210324aa02e897c43382779c0182 100644 (file)
@@ -37,8 +37,8 @@ trait Ty<'a> {
 fn main() {
     let v = Unit2.m(
         //~^ ERROR type mismatch
-        //~| ERROR type mismatch
         L {
+        //~^ ERROR type mismatch
             f : |x| { drop(x); Unit4 }
         });
 }
index 97f53bc70e44eeef6feea6ca9d9afd13fd83aa10..4c5c59c22099ae2abbfec71ff4d2900719a22e9e 100644 (file)
@@ -10,10 +10,16 @@ LL |     let v = Unit2.m(
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39] as FnOnce<((&'r u8,),)>>::Output == Unit3`
-  --> $DIR/issue-62203-hrtb-ice.rs:38:19
+  --> $DIR/issue-62203-hrtb-ice.rs:40:9
    |
-LL |     let v = Unit2.m(
-   |                   ^ expected struct `Unit4`, found struct `Unit3`
+LL |       let v = Unit2.m(
+   |                     - required by a bound introduced by this call
+LL |
+LL | /         L {
+LL | |
+LL | |             f : |x| { drop(x); Unit4 }
+LL | |         });
+   | |_________^ expected struct `Unit4`, found struct `Unit3`
    |
 note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39]>`
   --> $DIR/issue-62203-hrtb-ice.rs:17:16
diff --git a/src/test/ui/hrtb/issue-90177.rs b/src/test/ui/hrtb/issue-90177.rs
new file mode 100644 (file)
index 0000000..b151a9d
--- /dev/null
@@ -0,0 +1,32 @@
+// check-pass
+
+trait Base<'f> {
+    type Assoc;
+
+    fn do_something(&self);
+}
+
+trait ForAnyLifetime: for<'f> Base<'f> {}
+
+impl<T> ForAnyLifetime for T where T: for<'f> Base<'f> {}
+
+trait CanBeDynamic: ForAnyLifetime + for<'f> Base<'f, Assoc = ()> {}
+
+fn foo(a: &dyn CanBeDynamic) {
+    a.do_something();
+}
+
+struct S;
+
+impl<'a> Base<'a> for S {
+    type Assoc = ();
+
+    fn do_something(&self) {}
+}
+
+impl CanBeDynamic for S {}
+
+fn main() {
+    let s = S;
+    foo(&s);
+}
diff --git a/src/test/ui/hygiene/auxiliary/fields.rs b/src/test/ui/hygiene/auxiliary/fields.rs
new file mode 100644 (file)
index 0000000..733d11a
--- /dev/null
@@ -0,0 +1,73 @@
+#![feature(decl_macro)]
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum Field {
+    RootCtxt,
+    MacroCtxt,
+}
+
+#[rustfmt::skip]
+macro x(
+    $macro_name:ident,
+    $macro2_name:ident,
+    $type_name:ident,
+    $field_name:ident,
+    $const_name:ident
+) {
+    #[derive(Copy, Clone)]
+    pub struct $type_name {
+        pub field: Field,
+        pub $field_name: Field,
+    }
+
+    pub const $const_name: $type_name =
+        $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt };
+
+    #[macro_export]
+    macro_rules! $macro_name {
+        (check_fields_of $e:expr) => {{
+            let e = $e;
+            assert_eq!(e.field, Field::MacroCtxt);
+            assert_eq!(e.$field_name, Field::RootCtxt);
+        }};
+        (check_fields) => {{
+            assert_eq!($const_name.field, Field::MacroCtxt);
+            assert_eq!($const_name.$field_name, Field::RootCtxt);
+        }};
+        (construct) => {
+            $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt }
+        };
+    }
+
+    pub macro $macro2_name {
+        (check_fields_of $e:expr) => {{
+            let e = $e;
+            assert_eq!(e.field, Field::MacroCtxt);
+            assert_eq!(e.$field_name, Field::RootCtxt);
+        }},
+        (check_fields) => {{
+            assert_eq!($const_name.field, Field::MacroCtxt);
+            assert_eq!($const_name.$field_name, Field::RootCtxt);
+        }},
+        (construct) => {
+            $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt }
+        }
+    }
+}
+
+x!(test_fields, test_fields2, MyStruct, field, MY_CONST);
+
+pub fn check_fields(s: MyStruct) {
+    test_fields!(check_fields_of s);
+}
+
+pub fn check_fields_local() {
+    test_fields!(check_fields);
+    test_fields2!(check_fields);
+
+    let s1 = test_fields!(construct);
+    test_fields!(check_fields_of s1);
+
+    let s2 = test_fields2!(construct);
+    test_fields2!(check_fields_of s2);
+}
diff --git a/src/test/ui/hygiene/auxiliary/methods.rs b/src/test/ui/hygiene/auxiliary/methods.rs
new file mode 100644 (file)
index 0000000..23b9c61
--- /dev/null
@@ -0,0 +1,160 @@
+#![feature(decl_macro)]
+
+#[derive(PartialEq, Eq, Debug)]
+pub enum Method {
+    DefaultMacroCtxt,
+    DefaultRootCtxt,
+    OverrideMacroCtxt,
+    OverrideRootCtxt,
+}
+
+#[rustfmt::skip]
+macro x($macro_name:ident, $macro2_name:ident, $trait_name:ident, $method_name:ident) {
+    pub trait $trait_name {
+        fn method(&self) -> Method {
+            Method::DefaultMacroCtxt
+        }
+
+        fn $method_name(&self) -> Method {
+            Method::DefaultRootCtxt
+        }
+    }
+
+    impl $trait_name for () {}
+    impl $trait_name for bool {
+        fn method(&self) -> Method {
+            Method::OverrideMacroCtxt
+        }
+
+        fn $method_name(&self) -> Method {
+            Method::OverrideRootCtxt
+        }
+    }
+
+    #[macro_export]
+    macro_rules! $macro_name {
+        (check_resolutions) => {
+            assert_eq!(().method(), Method::DefaultMacroCtxt);
+            assert_eq!($trait_name::method(&()), Method::DefaultMacroCtxt);
+            assert_eq!(().$method_name(), Method::DefaultRootCtxt);
+            assert_eq!($trait_name::$method_name(&()), Method::DefaultRootCtxt);
+
+            assert_eq!(false.method(), Method::OverrideMacroCtxt);
+            assert_eq!($trait_name::method(&false), Method::OverrideMacroCtxt);
+            assert_eq!(false.$method_name(), Method::OverrideRootCtxt);
+            assert_eq!($trait_name::$method_name(&false), Method::OverrideRootCtxt);
+
+            assert_eq!('a'.method(), Method::DefaultMacroCtxt);
+            assert_eq!($trait_name::method(&'a'), Method::DefaultMacroCtxt);
+            assert_eq!('a'.$method_name(), Method::DefaultRootCtxt);
+            assert_eq!($trait_name::$method_name(&'a'), Method::DefaultRootCtxt);
+
+            assert_eq!(1i32.method(), Method::OverrideMacroCtxt);
+            assert_eq!($trait_name::method(&1i32), Method::OverrideMacroCtxt);
+            assert_eq!(1i32.$method_name(), Method::OverrideRootCtxt);
+            assert_eq!($trait_name::$method_name(&1i32), Method::OverrideRootCtxt);
+
+            assert_eq!(1i64.method(), Method::OverrideMacroCtxt);
+            assert_eq!($trait_name::method(&1i64), Method::OverrideMacroCtxt);
+            assert_eq!(1i64.$method_name(), Method::OverrideRootCtxt);
+            assert_eq!($trait_name::$method_name(&1i64), Method::OverrideRootCtxt);
+        };
+        (assert_no_override $v:expr) => {
+            assert_eq!($v.method(), Method::DefaultMacroCtxt);
+            assert_eq!($trait_name::method(&$v), Method::DefaultMacroCtxt);
+            assert_eq!($v.$method_name(), Method::DefaultRootCtxt);
+            assert_eq!($trait_name::$method_name(&$v), Method::DefaultRootCtxt);
+        };
+        (assert_override $v:expr) => {
+            assert_eq!($v.method(), Method::OverrideMacroCtxt);
+            assert_eq!($trait_name::method(&$v), Method::OverrideMacroCtxt);
+            assert_eq!($v.$method_name(), Method::OverrideRootCtxt);
+            assert_eq!($trait_name::$method_name(&$v), Method::OverrideRootCtxt);
+        };
+        (impl for $t:ty) => {
+            impl $trait_name for $t {
+                fn method(&self) -> Method {
+                    Method::OverrideMacroCtxt
+                }
+
+                fn $method_name(&self) -> Method {
+                    Method::OverrideRootCtxt
+                }
+            }
+        };
+    }
+
+    pub macro $macro2_name {
+        (check_resolutions) => {
+            assert_eq!(().method(), Method::DefaultMacroCtxt);
+            assert_eq!($trait_name::method(&()), Method::DefaultMacroCtxt);
+            assert_eq!(().$method_name(), Method::DefaultRootCtxt);
+            assert_eq!($trait_name::$method_name(&()), Method::DefaultRootCtxt);
+
+            assert_eq!(false.method(), Method::OverrideMacroCtxt);
+            assert_eq!($trait_name::method(&false), Method::OverrideMacroCtxt);
+            assert_eq!(false.$method_name(), Method::OverrideRootCtxt);
+            assert_eq!($trait_name::$method_name(&false), Method::OverrideRootCtxt);
+
+            assert_eq!('a'.method(), Method::DefaultMacroCtxt);
+            assert_eq!($trait_name::method(&'a'), Method::DefaultMacroCtxt);
+            assert_eq!('a'.$method_name(), Method::DefaultRootCtxt);
+            assert_eq!($trait_name::$method_name(&'a'), Method::DefaultRootCtxt);
+
+            assert_eq!(1i32.method(), Method::OverrideMacroCtxt);
+            assert_eq!($trait_name::method(&1i32), Method::OverrideMacroCtxt);
+            assert_eq!(1i32.$method_name(), Method::OverrideRootCtxt);
+            assert_eq!($trait_name::$method_name(&1i32), Method::OverrideRootCtxt);
+
+            assert_eq!(1i64.method(), Method::OverrideMacroCtxt);
+            assert_eq!($trait_name::method(&1i64), Method::OverrideMacroCtxt);
+            assert_eq!(1i64.$method_name(), Method::OverrideRootCtxt);
+            assert_eq!($trait_name::$method_name(&1i64), Method::OverrideRootCtxt);
+        },
+        (assert_no_override $v:expr) => {
+            assert_eq!($v.method(), Method::DefaultMacroCtxt);
+            assert_eq!($trait_name::method(&$v), Method::DefaultMacroCtxt);
+            assert_eq!($v.$method_name(), Method::DefaultRootCtxt);
+            assert_eq!($trait_name::$method_name(&$v), Method::DefaultRootCtxt);
+        },
+        (assert_override $v:expr) => {
+            assert_eq!($v.method(), Method::OverrideMacroCtxt);
+            assert_eq!($trait_name::method(&$v), Method::OverrideMacroCtxt);
+            assert_eq!($v.$method_name(), Method::OverrideRootCtxt);
+            assert_eq!($trait_name::$method_name(&$v), Method::OverrideRootCtxt);
+        },
+        (impl for $t:ty) => {
+            impl $trait_name for $t {
+                fn method(&self) -> Method {
+                    Method::OverrideMacroCtxt
+                }
+
+                fn $method_name(&self) -> Method {
+                    Method::OverrideRootCtxt
+                }
+            }
+        }
+    }
+}
+
+x!(test_trait, test_trait2, MyTrait, method);
+
+impl MyTrait for char {}
+test_trait!(impl for i32);
+test_trait2!(impl for i64);
+
+pub fn check_crate_local() {
+    test_trait!(check_resolutions);
+    test_trait2!(check_resolutions);
+}
+
+// Check that any comparison of idents at monomorphization time is correct
+pub fn check_crate_local_generic<T: MyTrait, U: MyTrait>(t: T, u: U) {
+    test_trait!(check_resolutions);
+    test_trait2!(check_resolutions);
+
+    test_trait!(assert_no_override t);
+    test_trait2!(assert_no_override t);
+    test_trait!(assert_override u);
+    test_trait2!(assert_override u);
+}
diff --git a/src/test/ui/hygiene/auxiliary/pub_hygiene.rs b/src/test/ui/hygiene/auxiliary/pub_hygiene.rs
new file mode 100644 (file)
index 0000000..47e76a6
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(decl_macro)]
+
+macro x() {
+    pub struct MyStruct;
+}
+
+x!();
diff --git a/src/test/ui/hygiene/auxiliary/use_by_macro.rs b/src/test/ui/hygiene/auxiliary/use_by_macro.rs
new file mode 100644 (file)
index 0000000..791cf03
--- /dev/null
@@ -0,0 +1,15 @@
+#![feature(decl_macro)]
+
+macro x($macro_name:ident) {
+    #[macro_export]
+    macro_rules! $macro_name {
+        (define) => {
+            pub struct MyStruct;
+        };
+        (create) => {
+            MyStruct {}
+        };
+    }
+}
+
+x!(my_struct);
diff --git a/src/test/ui/hygiene/auxiliary/variants.rs b/src/test/ui/hygiene/auxiliary/variants.rs
new file mode 100644 (file)
index 0000000..dbfcce1
--- /dev/null
@@ -0,0 +1,36 @@
+#![feature(decl_macro)]
+
+#[rustfmt::skip]
+macro x($macro_name:ident, $macro2_name:ident, $type_name:ident, $variant_name:ident) {
+    #[repr(u8)]
+    pub enum $type_name {
+        Variant = 0,
+        $variant_name = 1,
+    }
+
+    #[macro_export]
+    macro_rules! $macro_name {
+        () => {{
+            assert_eq!($type_name::Variant as u8, 0);
+            assert_eq!($type_name::$variant_name as u8, 1);
+            assert_eq!(<$type_name>::Variant as u8, 0);
+            assert_eq!(<$type_name>::$variant_name as u8, 1);
+        }};
+    }
+
+    pub macro $macro2_name {
+        () => {{
+            assert_eq!($type_name::Variant as u8, 0);
+            assert_eq!($type_name::$variant_name as u8, 1);
+            assert_eq!(<$type_name>::Variant as u8, 0);
+            assert_eq!(<$type_name>::$variant_name as u8, 1);
+        }},
+    }
+}
+
+x!(test_variants, test_variants2, MyEnum, Variant);
+
+pub fn check_variants() {
+    test_variants!();
+    test_variants2!();
+}
diff --git a/src/test/ui/hygiene/cross-crate-define-and-use.rs b/src/test/ui/hygiene/cross-crate-define-and-use.rs
new file mode 100644 (file)
index 0000000..94f1adf
--- /dev/null
@@ -0,0 +1,19 @@
+// Check that a marco from another crate can define an item in one expansion
+// and use it from another, without it being visible to everyone.
+// This requires that the definition of `my_struct` preserves the hygiene
+// information for the tokens in its definition.
+
+// check-pass
+// aux-build:use_by_macro.rs
+
+#![feature(type_name_of_val)]
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+enum MyStruct {}
+my_struct!(define);
+
+fn main() {
+    let x = my_struct!(create);
+}
diff --git a/src/test/ui/hygiene/cross-crate-fields.rs b/src/test/ui/hygiene/cross-crate-fields.rs
new file mode 100644 (file)
index 0000000..1bcd645
--- /dev/null
@@ -0,0 +1,24 @@
+// Test that fields on a struct defined in another crate are resolved correctly
+// their names differ only in `SyntaxContext`.
+
+// run-pass
+// aux-build:fields.rs
+
+extern crate fields;
+
+use fields::*;
+
+fn main() {
+    check_fields_local();
+
+    test_fields!(check_fields);
+    test_fields2!(check_fields);
+
+    let s1 = test_fields!(construct);
+    check_fields(s1);
+    test_fields!(check_fields_of s1);
+
+    let s2 = test_fields2!(construct);
+    check_fields(s2);
+    test_fields2!(check_fields_of s2);
+}
diff --git a/src/test/ui/hygiene/cross-crate-glob-hygiene.rs b/src/test/ui/hygiene/cross-crate-glob-hygiene.rs
new file mode 100644 (file)
index 0000000..de55766
--- /dev/null
@@ -0,0 +1,23 @@
+// Check that globs cannot import hygienic identifiers from a macro expansion
+// in another crate. `my_struct` is a `macro_rules` macro, so the struct it
+// defines is only not imported because `my_struct` is defined by a macros 2.0
+// macro.
+
+// aux-build:use_by_macro.rs
+
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+mod m {
+    use use_by_macro::*;
+
+    my_struct!(define);
+}
+
+use m::*;
+
+fn main() {
+    let x = my_struct!(create);
+    //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
+}
diff --git a/src/test/ui/hygiene/cross-crate-glob-hygiene.stderr b/src/test/ui/hygiene/cross-crate-glob-hygiene.stderr
new file mode 100644 (file)
index 0000000..7369e77
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
+  --> $DIR/cross-crate-glob-hygiene.rs:21:13
+   |
+LL |     let x = my_struct!(create);
+   |             ^^^^^^^^^^^^^^^^^^ not found in this scope
+   |
+   = note: this error originates in the macro `my_struct` (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 E0422`.
diff --git a/src/test/ui/hygiene/cross-crate-methods.rs b/src/test/ui/hygiene/cross-crate-methods.rs
new file mode 100644 (file)
index 0000000..0e6f57c
--- /dev/null
@@ -0,0 +1,33 @@
+// Test that methods defined in another crate are resolved correctly their
+// names differ only in `SyntaxContext`. This also checks that any name
+// resolution done when monomorphizing is correct.
+
+// run-pass
+// aux-build:methods.rs
+
+extern crate methods;
+
+use methods::*;
+
+struct A;
+struct B;
+struct C;
+
+impl MyTrait for A {}
+test_trait!(impl for B);
+test_trait2!(impl for C);
+
+fn main() {
+    check_crate_local();
+    check_crate_local_generic(A, B);
+    check_crate_local_generic(A, C);
+
+    test_trait!(check_resolutions);
+    test_trait2!(check_resolutions);
+    test_trait!(assert_no_override A);
+    test_trait2!(assert_no_override A);
+    test_trait!(assert_override B);
+    test_trait2!(assert_override B);
+    test_trait!(assert_override C);
+    test_trait2!(assert_override C);
+}
diff --git a/src/test/ui/hygiene/cross-crate-name-collision.rs b/src/test/ui/hygiene/cross-crate-name-collision.rs
new file mode 100644 (file)
index 0000000..8f11878
--- /dev/null
@@ -0,0 +1,12 @@
+// Check that two items defined in another crate that have identifiers that
+// only differ by `SyntaxContext` do not cause name collisions when imported
+// in another crate.
+
+// check-pass
+// aux-build:needs_hygiene.rs
+
+extern crate needs_hygiene;
+
+use needs_hygiene::*;
+
+fn main() {}
diff --git a/src/test/ui/hygiene/cross-crate-name-hiding-2.rs b/src/test/ui/hygiene/cross-crate-name-hiding-2.rs
new file mode 100644 (file)
index 0000000..3eacd77
--- /dev/null
@@ -0,0 +1,15 @@
+// Check that an identifier from a 2.0 macro in another crate cannot be
+// resolved with an identifier that's not from a macro expansion.
+
+// aux-build:use_by_macro.rs
+
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+my_struct!(define);
+
+fn main() {
+    let x = MyStruct {};
+    //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
+}
diff --git a/src/test/ui/hygiene/cross-crate-name-hiding-2.stderr b/src/test/ui/hygiene/cross-crate-name-hiding-2.stderr
new file mode 100644 (file)
index 0000000..46314cd
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
+  --> $DIR/cross-crate-name-hiding-2.rs:13:13
+   |
+LL |     let x = MyStruct {};
+   |             ^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0422`.
diff --git a/src/test/ui/hygiene/cross-crate-name-hiding.rs b/src/test/ui/hygiene/cross-crate-name-hiding.rs
new file mode 100644 (file)
index 0000000..dd76ecc
--- /dev/null
@@ -0,0 +1,13 @@
+// Check that an item defined by a 2.0 macro in another crate cannot be used in
+// another crate.
+
+// aux-build:pub_hygiene.rs
+
+extern crate pub_hygiene;
+
+use pub_hygiene::*;
+
+fn main() {
+    let x = MyStruct {};
+    //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
+}
diff --git a/src/test/ui/hygiene/cross-crate-name-hiding.stderr b/src/test/ui/hygiene/cross-crate-name-hiding.stderr
new file mode 100644 (file)
index 0000000..f8840c8
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
+  --> $DIR/cross-crate-name-hiding.rs:11:13
+   |
+LL |     let x = MyStruct {};
+   |             ^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0422`.
diff --git a/src/test/ui/hygiene/cross-crate-redefine.rs b/src/test/ui/hygiene/cross-crate-redefine.rs
new file mode 100644 (file)
index 0000000..3cb06b4
--- /dev/null
@@ -0,0 +1,14 @@
+// Check that items with identical `SyntaxContext` conflict even when that
+// context involves a mark from another crate.
+
+// aux-build:use_by_macro.rs
+
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+my_struct!(define);
+//~^ ERROR the name `MyStruct` is defined multiple times
+my_struct!(define);
+
+fn main() {}
diff --git a/src/test/ui/hygiene/cross-crate-redefine.stderr b/src/test/ui/hygiene/cross-crate-redefine.stderr
new file mode 100644 (file)
index 0000000..4f1419d
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0428]: the name `MyStruct` is defined multiple times
+  --> $DIR/cross-crate-redefine.rs:10:1
+   |
+LL | my_struct!(define);
+   | ^^^^^^^^^^^^^^^^^^ `MyStruct` redefined here
+LL |
+LL | my_struct!(define);
+   | ------------------ previous definition of the type `MyStruct` here
+   |
+   = note: `MyStruct` must be defined only once in the type namespace of this module
+   = note: this error originates in the macro `my_struct` (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 E0428`.
diff --git a/src/test/ui/hygiene/cross-crate-variants.rs b/src/test/ui/hygiene/cross-crate-variants.rs
new file mode 100644 (file)
index 0000000..efc73a2
--- /dev/null
@@ -0,0 +1,18 @@
+// Test that variants of an enum defined in another crate are resolved
+// correctly when their names differ only in `SyntaxContext`.
+
+// run-pass
+// aux-build:variants.rs
+
+extern crate variants;
+
+use variants::*;
+
+fn main() {
+    check_variants();
+
+    test_variants!();
+    test_variants2!();
+
+    assert_eq!(MyEnum::Variant as u8, 1);
+}
diff --git a/src/test/ui/hygiene/cross_crate_hygiene.rs b/src/test/ui/hygiene/cross_crate_hygiene.rs
deleted file mode 100644 (file)
index 7574296..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// check-pass
-// aux-build:needs_hygiene.rs
-
-extern crate needs_hygiene;
-
-use needs_hygiene::*;
-
-fn main() {}
index ef650b75b5634f4d97c4b4af3dbfac6f5b6084bd..e4c1c8ad293b7162ec96057576899463ead5aef0 100644 (file)
@@ -2,11 +2,14 @@ error[E0425]: cannot find value `Opaque` in this scope
   --> $DIR/rustc-macro-transparency.rs:26:5
    |
 LL |     Opaque;
-   |     ^^^^^^ help: a local variable with a similar name exists (notice the capitalization): `opaque`
+   |     ^^^^^^ not found in this scope
 
 error[E0423]: expected value, found macro `semitransparent`
   --> $DIR/rustc-macro-transparency.rs:29:5
    |
+LL |     struct SemiTransparent;
+   |     ----------------------- similarly named unit struct `SemiTransparent` defined here
+...
 LL |     semitransparent;
    |     ^^^^^^^^^^^^^^^ not a value
    |
@@ -14,10 +17,17 @@ help: use `!` to invoke the macro
    |
 LL |     semitransparent!;
    |                    +
+help: a unit struct with a similar name exists
+   |
+LL |     SemiTransparent;
+   |     ~~~~~~~~~~~~~~~
 
 error[E0423]: expected value, found macro `opaque`
   --> $DIR/rustc-macro-transparency.rs:30:5
    |
+LL |     struct Opaque;
+   |     -------------- similarly named unit struct `Opaque` defined here
+...
 LL |     opaque;
    |     ^^^^^^ not a value
    |
@@ -25,6 +35,10 @@ help: use `!` to invoke the macro
    |
 LL |     opaque!;
    |           +
+help: a unit struct with a similar name exists
+   |
+LL |     Opaque;
+   |     ~~~~~~
 
 error: aborting due to 3 previous errors
 
index 5a8e503601468992260526c53d546e1fbb2bb51e..8c53b4105bb8b838bedc96bcce33eed565c5d1bf 100644 (file)
@@ -1,11 +1,13 @@
 error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely
-  --> $DIR/auto-trait-leak2.rs:13:5
+  --> $DIR/auto-trait-leak2.rs:13:10
    |
 LL | fn before() -> impl Fn(i32) {
    |                ------------ within this `impl Fn<(i32,)>`
 ...
 LL |     send(before());
-   |     ^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
+   |     ---- ^^^^^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: within `impl Fn<(i32,)>`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
    = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:7:5: 7:22]`
@@ -17,10 +19,12 @@ LL | fn send<T: Send>(_: T) {}
    |            ^^^^ required by this bound in `send`
 
 error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely
-  --> $DIR/auto-trait-leak2.rs:16:5
+  --> $DIR/auto-trait-leak2.rs:16:10
    |
 LL |     send(after());
-   |     ^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
+   |     ---- ^^^^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
 ...
 LL | fn after() -> impl Fn(i32) {
    |               ------------ within this `impl Fn<(i32,)>`
index 828b5aac896beff3d71fb276d3dc3b0785502dfd..9610618ca11f65f47880ea724d092bed83d6d31b 100644 (file)
@@ -17,7 +17,7 @@ fn two(x: bool) -> impl Foo {
     //~| expected `i32`, found `u32`
 }
 
-fn sum_to(n: u32) -> impl Foo {
+fn sum_to(n: u32) -> impl Foo { //~ ERROR type annotations needed
     if n == 0 {
         0
     } else {
index 536a4726c6de225f02c2247332f6c399a92b49f6..d9819484a96126123a268201d97d08ef87b8e2b9 100644 (file)
@@ -34,7 +34,22 @@ LL |         n + sum_to(n - 1)
    |
    = help: the trait `Add<impl Foo>` is not implemented for `u32`
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error[E0283]: type annotations needed
+  --> $DIR/equality.rs:20:22
+   |
+LL | fn sum_to(n: u32) -> impl Foo {
+   |                      ^^^^^^^^ cannot infer type for type `{integer}`
+   |
+   = note: multiple `impl`s satisfying `{integer}: ToString` found in the `alloc` crate:
+           - impl ToString for i8;
+           - impl ToString for u8;
+note: required because of the requirements on the impl of `Foo` for `{integer}`
+  --> $DIR/equality.rs:5:26
+   |
+LL | impl<T: Copy + ToString> Foo for T {}
+   |                          ^^^     ^
+
+error: aborting due to 3 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0277, E0308.
+Some errors have detailed explanations: E0277, E0283, E0308.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr
deleted file mode 100644 (file)
index bfe656c..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ordinary-bounds-unrelated.rs:16:74
-   |
-LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
-   |                     --                                                   ^^^^^^^^^^^^^^^^^^
-   |                     |
-   |                     hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
-   |
-help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
-   |
-LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + 'b
-   |                                                                                             ++++
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0700`.
index a6bc8fec2838efb3f09f7551f3bb0f21b132e384..bfe656c7e2b491ae5f380e880b95f2562d532a95 100644 (file)
@@ -2,13 +2,14 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
   --> $DIR/ordinary-bounds-unrelated.rs:16:74
    |
 LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
-   |                                                                          ^^^^^^^^^^^^^^^^^^
+   |                     --                                                   ^^^^^^^^^^^^^^^^^^
+   |                     |
+   |                     hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
    |
-note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
-  --> $DIR/ordinary-bounds-unrelated.rs:16:74
+help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
    |
-LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
-   |                                                                          ^^^^^^^^^^^^^^^^^^
+LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + 'b
+   |                                                                                             ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr
deleted file mode 100644 (file)
index 75c2dd8..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ordinary-bounds-unsuited.rs:18:62
-   |
-LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
-   |                     --                                       ^^^^^^^^^^^^^^^^^^
-   |                     |
-   |                     hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
-   |
-help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
-   |
-LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + 'b
-   |                                                                                 ++++
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0700`.
index a219e74741541f68316b3e6d39297c1d84d5affe..75c2dd8e9d39edea0a964b8582c13032e588b45b 100644 (file)
@@ -2,13 +2,14 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
   --> $DIR/ordinary-bounds-unsuited.rs:18:62
    |
 LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
-   |                                                              ^^^^^^^^^^^^^^^^^^
+   |                     --                                       ^^^^^^^^^^^^^^^^^^
+   |                     |
+   |                     hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
    |
-note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
-  --> $DIR/ordinary-bounds-unsuited.rs:18:62
+help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
    |
-LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
-   |                                                              ^^^^^^^^^^^^^^^^^^
+LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + 'b
+   |                                                                                 ++++
 
 error: aborting due to previous error
 
index 812093e6e76213ed950eb1da6547f25125ddc4c7..eaf341248a180039bfa806f597de7f692c598a22 100644 (file)
@@ -1,31 +1,31 @@
-error: lifetime may not live long enough
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
   --> $DIR/must_outlive_least_region_or_bound.rs:3:23
    |
 LL | fn elided(x: &i32) -> impl Copy { x }
-   |              -        ^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+   |              ----     ^^^^^^^^^
    |              |
-   |              let's call the lifetime of this reference `'1`
+   |              hidden type `&i32` captures the anonymous lifetime defined here
    |
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
+help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
    |
 LL | fn elided(x: &i32) -> impl Copy + '_ { x }
    |                                 ++++
 
-error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:5:32
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/must_outlive_least_region_or_bound.rs:6:32
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
-   |             --                 ^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
+   |             --                 ^^^^^^^^^
    |             |
-   |             lifetime `'a` defined here
+   |             hidden type `&'a i32` captures the lifetime `'a` as defined here
    |
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
+help: to declare that the `impl Trait` captures 'a, you can add an explicit `'a` lifetime bound
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
    |                                          ++++
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:7:46
+  --> $DIR/must_outlive_least_region_or_bound.rs:9:46
    |
 LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
    |               -                              ^ returning this value requires that `'1` must outlive `'static`
@@ -35,7 +35,7 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
    = help: consider replacing `'1` with `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:9:55
+  --> $DIR/must_outlive_least_region_or_bound.rs:11:55
    |
 LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
    |              -- lifetime `'a` defined here            ^ returning this value requires that `'a` must outlive `'static`
@@ -43,7 +43,7 @@ LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
    = help: consider replacing `'a` with `'static`
 
 error[E0621]: explicit lifetime required in the type of `x`
-  --> $DIR/must_outlive_least_region_or_bound.rs:11:41
+  --> $DIR/must_outlive_least_region_or_bound.rs:13:41
    |
 LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
    |               ----                      ^ lifetime `'a` required
@@ -51,33 +51,36 @@ LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
    |               help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:22:24
+  --> $DIR/must_outlive_least_region_or_bound.rs:24:55
    |
 LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
-   |               -        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+   |               -                                       ^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
    |               |
    |               let's call the lifetime of this reference `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:28:69
+  --> $DIR/must_outlive_least_region_or_bound.rs:29:69
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |               -- lifetime `'a` defined here                         ^ returning this value requires that `'a` must outlive `'static`
    |
    = help: consider replacing `'a` with `'static`
 
-error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:32:61
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/must_outlive_least_region_or_bound.rs:33:61
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
-   |                          --  -- lifetime `'b` defined here  ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
-   |                          |
-   |                          lifetime `'a` defined here
+   |                              --                             ^^^^^^^^^^^^^^^^
+   |                              |
+   |                              hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:35:5: 35:31]` captures the lifetime `'b` as defined here
+   |
+help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
    |
-   = help: consider adding the following bound: `'b: 'a`
+LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) + 'b {
+   |                                                                              ++++
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:37:51
+  --> $DIR/must_outlive_least_region_or_bound.rs:38:51
    |
 LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
    |                                                   ^^^^^^^^^^^^^^^^^^^^
@@ -86,5 +89,5 @@ LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
 
 error: aborting due to 9 previous errors
 
-Some errors have detailed explanations: E0310, E0621.
+Some errors have detailed explanations: E0310, E0621, E0700.
 For more information about an error, try `rustc --explain E0310`.
index 51f488e45a6f3d14ce6cea95d318c3f06e126ef0..69d2843ff3f01b0f5184ee1c15209d638ad71a53 100644 (file)
@@ -1,8 +1,10 @@
 use std::fmt::Debug;
 
-fn elided(x: &i32) -> impl Copy { x } //~ ERROR E0759
+fn elided(x: &i32) -> impl Copy { x }
+//~^ ERROR: captures lifetime that does not appear in bounds
 
-fn explicit<'a>(x: &'a i32) -> impl Copy { x } //~ ERROR E0759
+fn explicit<'a>(x: &'a i32) -> impl Copy { x }
+//~^ ERROR: captures lifetime that does not appear in bounds
 
 fn elided2(x: &i32) -> impl Copy + 'static { x } //~ ERROR E0759
 
@@ -20,7 +22,6 @@ fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) } //~ ERROR E0759
 fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) } //~ ERROR E0759
 
 fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } //~ ERROR E0759
-//~^ ERROR E0759
 
 trait LifetimeTrait<'a> {}
 impl<'a> LifetimeTrait<'a> for &'a i32 {}
@@ -30,7 +31,7 @@ fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } //~ ERRO
 // Tests that a closure type containing 'b cannot be returned from a type where
 // only 'a was expected.
 fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
-    //~^ ERROR lifetime mismatch
+    //~^ ERROR: captures lifetime that does not appear in bounds
     move |_| println!("{}", y)
 }
 
index 81ba89b0e05f7d5a1c2ecac4ee82729049170696..d65dea7adc90b40f5f4501382f67d2820162eb52 100644 (file)
@@ -1,41 +1,31 @@
-error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/must_outlive_least_region_or_bound.rs:3:35
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/must_outlive_least_region_or_bound.rs:3:23
    |
 LL | fn elided(x: &i32) -> impl Copy { x }
-   |              ----                 ^ ...is captured here...
+   |              ----     ^^^^^^^^^
    |              |
-   |              this data with an anonymous lifetime `'_`...
-   |
-note: ...and is required to live as long as `'static` here
-  --> $DIR/must_outlive_least_region_or_bound.rs:3:23
+   |              hidden type `&i32` captures the anonymous lifetime defined here
    |
-LL | fn elided(x: &i32) -> impl Copy { x }
-   |                       ^^^^^^^^^
-help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
+help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
    |
 LL | fn elided(x: &i32) -> impl Copy + '_ { x }
    |                                 ++++
 
-error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/must_outlive_least_region_or_bound.rs:5:44
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/must_outlive_least_region_or_bound.rs:6:32
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
-   |                    -------                 ^ ...is captured here...
-   |                    |
-   |                    this data with lifetime `'a`...
+   |             --                 ^^^^^^^^^
+   |             |
+   |             hidden type `&'a i32` captures the lifetime `'a` as defined here
    |
-note: ...and is required to live as long as `'static` here
-  --> $DIR/must_outlive_least_region_or_bound.rs:5:32
-   |
-LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
-   |                                ^^^^^^^^^
-help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'a` lifetime bound
+help: to declare that the `impl Trait` captures 'a, you can add an explicit `'a` lifetime bound
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
    |                                          ++++
 
 error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/must_outlive_least_region_or_bound.rs:7:46
+  --> $DIR/must_outlive_least_region_or_bound.rs:9:46
    |
 LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
    |               ----                           ^ ...is captured here...
@@ -43,7 +33,7 @@ LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
    |               this data with an anonymous lifetime `'_`...
    |
 note: ...and is required to live as long as `'static` here
-  --> $DIR/must_outlive_least_region_or_bound.rs:7:24
+  --> $DIR/must_outlive_least_region_or_bound.rs:9:24
    |
 LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
    |                        ^^^^^^^^^^^^^^^^^^^
@@ -57,7 +47,7 @@ LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x }
    |               ~~~~~~~~~~~~
 
 error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/must_outlive_least_region_or_bound.rs:9:55
+  --> $DIR/must_outlive_least_region_or_bound.rs:11:55
    |
 LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
    |                     -------                           ^ ...is captured here...
@@ -65,7 +55,7 @@ LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
    |                     this data with lifetime `'a`...
    |
 note: ...and is required to live as long as `'static` here
-  --> $DIR/must_outlive_least_region_or_bound.rs:9:33
+  --> $DIR/must_outlive_least_region_or_bound.rs:11:33
    |
 LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
    |                                 ^^^^^^^^^^^^^^^^^^^
@@ -79,7 +69,7 @@ LL | fn explicit2<'a>(x: &'static i32) -> impl Copy + 'static { x }
    |                     ~~~~~~~~~~~~
 
 error[E0621]: explicit lifetime required in the type of `x`
-  --> $DIR/must_outlive_least_region_or_bound.rs:11:24
+  --> $DIR/must_outlive_least_region_or_bound.rs:13:24
    |
 LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
    |               ----     ^^^^^^^^^^^^^^ lifetime `'a` required
@@ -87,7 +77,7 @@ LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
    |               help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
 
 error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/must_outlive_least_region_or_bound.rs:22:65
+  --> $DIR/must_outlive_least_region_or_bound.rs:24:65
    |
 LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
    |               ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static`
@@ -101,34 +91,14 @@ help: to declare that the `impl Trait` captures data from argument `x`, you can
 LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
    |                                                    ++++
 
-error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/must_outlive_least_region_or_bound.rs:22:69
-   |
-LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
-   |               ---- this data with an anonymous lifetime `'_`...     ^ ...is captured here...
-   |
-note: ...and is required to live as long as `'static` here
-  --> $DIR/must_outlive_least_region_or_bound.rs:22:41
-   |
-LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
-   |                                         ^^^^^^^^^^
-help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
-   |
-LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) }
-   |                                       ++++
-help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
-   |
-LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
-   |                                                    ++++
-
 error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/must_outlive_least_region_or_bound.rs:28:69
+  --> $DIR/must_outlive_least_region_or_bound.rs:29:69
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |                      ------- this data with lifetime `'a`...        ^ ...is captured here...
    |
 note: ...and is required to live as long as `'static` here
-  --> $DIR/must_outlive_least_region_or_bound.rs:28:34
+  --> $DIR/must_outlive_least_region_or_bound.rs:29:34
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -141,17 +111,21 @@ help: alternatively, add an explicit `'static` bound to this reference
 LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x }
    |                      ~~~~~~~~~~~~
 
-error[E0623]: lifetime mismatch
-  --> $DIR/must_outlive_least_region_or_bound.rs:32:61
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/must_outlive_least_region_or_bound.rs:33:61
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
-   |                                                 -------     ^^^^^^^^^^^^^^^^
-   |                                                 |           |
-   |                                                 |           ...but data from `y` is returned here
-   |                                                 this parameter and the return type are declared with different lifetimes...
+   |                              --                             ^^^^^^^^^^^^^^^^
+   |                              |
+   |                              hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:35:5: 35:31]` captures the lifetime `'b` as defined here
+   |
+help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
+   |
+LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) + 'b {
+   |                                                                              ++++
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:37:51
+  --> $DIR/must_outlive_least_region_or_bound.rs:38:51
    |
 LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
    |                                 --                ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
@@ -159,7 +133,7 @@ LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
    |                                 help: consider adding an explicit lifetime bound...: `T: 'static +`
 
 error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/must_outlive_least_region_or_bound.rs:14:50
+  --> $DIR/must_outlive_least_region_or_bound.rs:16:50
    |
 LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
    |               ----                               ^ ...is captured here, requiring it to live as long as `'static`
@@ -172,7 +146,7 @@ LL | fn elided3(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) }
    |                                      ++++
 
 error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/must_outlive_least_region_or_bound.rs:16:59
+  --> $DIR/must_outlive_least_region_or_bound.rs:18:59
    |
 LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
    |                     -------                               ^ ...is captured here, requiring it to live as long as `'static`
@@ -185,7 +159,7 @@ LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) }
    |                                               ++++
 
 error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/must_outlive_least_region_or_bound.rs:18:60
+  --> $DIR/must_outlive_least_region_or_bound.rs:20:60
    |
 LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
    |               ----                                         ^ ...is captured here, requiring it to live as long as `'static`
@@ -202,7 +176,7 @@ LL | fn elided4(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) }
    |               ~~~~~~~~~~~~
 
 error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/must_outlive_least_region_or_bound.rs:20:69
+  --> $DIR/must_outlive_least_region_or_bound.rs:22:69
    |
 LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
    |                     ------- this data with lifetime `'a`...         ^ ...is captured here, requiring it to live as long as `'static`
@@ -216,7 +190,7 @@ help: alternatively, add an explicit `'static` bound to this reference
 LL | fn explicit4<'a>(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) }
    |                     ~~~~~~~~~~~~
 
-error: aborting due to 14 previous errors
+error: aborting due to 13 previous errors
 
-Some errors have detailed explanations: E0310, E0621, E0623, E0759.
+Some errors have detailed explanations: E0310, E0621, E0700, E0759.
 For more information about an error, try `rustc --explain E0310`.
index 30afc8646de3d1b8de4b7f908efdcda7bdf33a7e..c8ebed3bfd9ae9bd71ed642b52b101be776cfd5a 100644 (file)
@@ -9,12 +9,12 @@ help: the following traits are implemented but not in scope; perhaps add a `use`
    |
 LL | use foo::Bar;
    |
+LL | use no_method_suggested_traits::Reexported;
+   |
 LL | use no_method_suggested_traits::foo::PubPub;
    |
 LL | use no_method_suggested_traits::qux::PrivPub;
    |
-LL | use no_method_suggested_traits::Reexported;
-   |
 
 error[E0599]: no method named `method` found for struct `Rc<&mut Box<&u32>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:26:44
@@ -27,12 +27,12 @@ help: the following traits are implemented but not in scope; perhaps add a `use`
    |
 LL | use foo::Bar;
    |
+LL | use no_method_suggested_traits::Reexported;
+   |
 LL | use no_method_suggested_traits::foo::PubPub;
    |
 LL | use no_method_suggested_traits::qux::PrivPub;
    |
-LL | use no_method_suggested_traits::Reexported;
-   |
 
 error[E0599]: no method named `method` found for type `char` in the current scope
   --> $DIR/no-method-suggested-traits.rs:30:9
diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr
deleted file mode 100644 (file)
index a3aeff5..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-error: lifetime may not live long enough
-  --> $DIR/static-return-lifetime-infered.rs:6:35
-   |
-LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
-   |                         -         ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
-   |                         |
-   |                         let's call the lifetime of this reference `'1`
-   |
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
-   |
-LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
-   |                                                           ++++
-
-error: lifetime may not live long enough
-  --> $DIR/static-return-lifetime-infered.rs:9:37
-   |
-LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
-   |                    --               ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
-   |                    |
-   |                    lifetime `'a` defined here
-   |
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
-   |
-LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
-   |                                                             ++++
-
-error: aborting due to 2 previous errors
-
index 518c52f5de4d7bfb3b26ce59a59d6668a7259ced..d792c6eafb32f27ea889552ea03bea1b7fbfa288 100644 (file)
@@ -4,10 +4,14 @@ struct A {
 
 impl A {
     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
-        self.x.iter().map(|a| a.0) //~ ERROR E0759
+        //~^ ERROR: captures lifetime that does not appear in bounds
+        //~| ERROR: captures lifetime that does not appear in bounds
+        self.x.iter().map(|a| a.0)
     }
     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
-        self.x.iter().map(|a| a.0) //~ ERROR E0759
+        //~^ ERROR: captures lifetime that does not appear in bounds
+        //~| ERROR: captures lifetime that does not appear in bounds
+        self.x.iter().map(|a| a.0)
     }
 }
 
index ebd0b6a12818029b73ba225a23f63316b1589b07..0d68f8c825f70ee87c5b1f7f0b12db64b919ae4e 100644 (file)
@@ -1,43 +1,55 @@
-error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/static-return-lifetime-infered.rs:7:16
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/static-return-lifetime-infered.rs:6:35
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
-   |                         ----- this data with an anonymous lifetime `'_`...
-LL |         self.x.iter().map(|a| a.0)
-   |         ------ ^^^^
-   |         |
-   |         ...is captured here...
+   |                         -----     ^^^^^^^^^^^^^^^^^^^^^^^
+   |                         |
+   |                         hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:9:27: 9:34]>` captures the anonymous lifetime defined here
+   |
+help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
    |
-note: ...and is required to live as long as `'static` here
+LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
+   |                                                           ++++
+
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
   --> $DIR/static-return-lifetime-infered.rs:6:35
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^
-help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |                         -----     ^^^^^^^^^^^^^^^^^^^^^^^
+   |                         |
+   |                         hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:9:27: 9:34]>` captures the anonymous lifetime defined here
+   |
+help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
    |                                                           ++++
 
-error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/static-return-lifetime-infered.rs:10:16
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/static-return-lifetime-infered.rs:11:37
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
-   |                        -------- this data with lifetime `'a`...
-LL |         self.x.iter().map(|a| a.0)
-   |         ------ ^^^^
-   |         |
-   |         ...is captured here...
+   |                    --               ^^^^^^^^^^^^^^^^^^^^^^^
+   |                    |
+   |                    hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:14:27: 14:34]>` captures the lifetime `'a` as defined here
    |
-note: ...and is required to live as long as `'static` here
-  --> $DIR/static-return-lifetime-infered.rs:9:37
+help: to declare that the `impl Trait` captures 'a, you can add an explicit `'a` lifetime bound
+   |
+LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
+   |                                                             ++++
+
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/static-return-lifetime-infered.rs:11:37
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
-   |                                     ^^^^^^^^^^^^^^^^^^^^^^^
-help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound
+   |                    --               ^^^^^^^^^^^^^^^^^^^^^^^
+   |                    |
+   |                    hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:14:27: 14:34]>` captures the lifetime `'a` as defined here
+   |
+help: to declare that the `impl Trait` captures 'a, you can add an explicit `'a` lifetime bound
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
    |                                                             ++++
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0759`.
+For more information about this error, try `rustc --explain E0700`.
index 0dbcb5f1de3f9b17c5856ae297261b56443244ea..997a2741b382c8de1a7cc4efb1ffe58acda53681 100644 (file)
@@ -8,12 +8,13 @@ LL |     use a::foo;
    |
    = note: `foo` must be defined only once in the value namespace of this module
 
-error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `foo` is ambiguous
   --> $DIR/duplicate.rs:46:15
    |
 LL |     use self::foo::bar;
    |               ^^^ ambiguous name
    |
+   = note: ambiguous because of multiple glob imports of a name in the same module
 note: `foo` could refer to the module imported here
   --> $DIR/duplicate.rs:43:9
    |
@@ -27,12 +28,13 @@ LL |     use self::m2::*;
    |         ^^^^^^^^^^^
    = help: consider adding an explicit import of `foo` to disambiguate
 
-error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `foo` is ambiguous
   --> $DIR/duplicate.rs:35:8
    |
 LL |     f::foo();
    |        ^^^ ambiguous name
    |
+   = note: ambiguous because of multiple glob imports of a name in the same module
 note: `foo` could refer to the function imported here
   --> $DIR/duplicate.rs:24:13
    |
@@ -46,12 +48,13 @@ LL |     pub use b::*;
    |             ^^^^
    = help: consider adding an explicit import of `foo` to disambiguate
 
-error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `foo` is ambiguous
   --> $DIR/duplicate.rs:49:9
    |
 LL |         foo::bar();
    |         ^^^ ambiguous name
    |
+   = note: ambiguous because of multiple glob imports of a name in the same module
 note: `foo` could refer to the module imported here
   --> $DIR/duplicate.rs:43:9
    |
index 472824b84f4a1eda80ced77eee008946e0368fa3..c31c8840381537217a3ac5273b2561718a1da352 100644 (file)
@@ -9,12 +9,13 @@ LL | define_other_core!();
    |
    = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `Vec` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `Vec` is ambiguous
   --> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:13:9
    |
 LL |         Vec::panic!();
    |         ^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `Vec` could refer to the crate imported here
   --> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:5:9
    |
index 4ef446f93c860c39430a96685bcef26e4d6b9a47..aff2eff68ac86d708015eefa2019c87b024d9d1c 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `env` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `env` is ambiguous
   --> $DIR/glob-shadowing.rs:11:17
    |
 LL |         let x = env!("PATH");
    |                 ^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
    = note: `env` could refer to a macro from prelude
 note: `env` could also refer to the macro imported here
   --> $DIR/glob-shadowing.rs:9:9
@@ -13,12 +14,13 @@ LL |     use m::*;
    = help: consider adding an explicit import of `env` to disambiguate
    = help: or use `self::env` to refer to this macro unambiguously
 
-error[E0659]: `env` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `env` is ambiguous
   --> $DIR/glob-shadowing.rs:19:21
    |
 LL |             let x = env!("PATH");
    |                     ^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
    = note: `env` could refer to a macro from prelude
 note: `env` could also refer to the macro imported here
   --> $DIR/glob-shadowing.rs:17:13
@@ -27,12 +29,13 @@ LL |         use m::*;
    |             ^^^^
    = help: consider adding an explicit import of `env` to disambiguate
 
-error[E0659]: `fenv` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `fenv` is ambiguous
   --> $DIR/glob-shadowing.rs:29:21
    |
 LL |             let x = fenv!();
    |                     ^^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
 note: `fenv` could refer to the macro imported here
   --> $DIR/glob-shadowing.rs:27:13
    |
index bbec2aae825928ea4ef8e7ac3176c421efcf0aa3..a0e7bf8b61f6e4ceb79617cb9528b59be35952ee 100644 (file)
@@ -4,12 +4,13 @@ error[E0432]: unresolved import `nonexistent_module`
 LL |     use nonexistent_module::mac;
    |         ^^^^^^^^^^^^^^^^^^ maybe a missing crate `nonexistent_module`?
 
-error[E0659]: `mac` is ambiguous (`macro_rules` vs non-`macro_rules` from other module)
+error[E0659]: `mac` is ambiguous
   --> $DIR/issue-53269.rs:8:5
    |
 LL |     mac!();
    |     ^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a `macro_rules` name and a non-`macro_rules` name from another module
 note: `mac` could refer to the macro defined here
   --> $DIR/issue-53269.rs:3:1
    |
index a7a7cc8879e652716ab6c220b972fc4b1512274b..c38166ddea6aaf4e4d6358828fdcbb30303be6b2 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `S` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `S` is ambiguous
   --> $DIR/issue-55884-1.rs:19:12
    |
 LL |     use m::S;
    |            ^ ambiguous name
    |
+   = note: ambiguous because of multiple glob imports of a name in the same module
 note: `S` could refer to the struct imported here
   --> $DIR/issue-55884-1.rs:14:13
    |
index d78cc5230367d4932676fe4f27d1e06723eeff4a..2e4ba86237676090cb292469ee0b4b908317a816 100644 (file)
@@ -4,12 +4,13 @@ error[E0432]: unresolved import `empty::issue_56125`
 LL |     use empty::issue_56125;
    |         ^^^^^^^^^^^^^^^^^^ no `issue_56125` in `m3::empty`
 
-error[E0659]: `issue_56125` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `issue_56125` is ambiguous
   --> $DIR/issue-56125.rs:6:9
    |
 LL |     use issue_56125::last_segment::*;
    |         ^^^^^^^^^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
    = note: `issue_56125` could refer to a crate passed with `--extern`
    = help: use `::issue_56125` to refer to this crate unambiguously
 note: `issue_56125` could also refer to the module imported here
@@ -19,12 +20,13 @@ LL |     use issue_56125::last_segment::*;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: use `self::issue_56125` to refer to this module unambiguously
 
-error[E0659]: `issue_56125` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `issue_56125` is ambiguous
   --> $DIR/issue-56125.rs:11:9
    |
 LL |     use issue_56125::non_last_segment::non_last_segment::*;
    |         ^^^^^^^^^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
    = note: `issue_56125` could refer to a crate passed with `--extern`
    = help: use `::issue_56125` to refer to this crate unambiguously
 note: `issue_56125` could also refer to the module imported here
@@ -34,12 +36,13 @@ LL |     use issue_56125::non_last_segment::non_last_segment::*;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: use `self::issue_56125` to refer to this module unambiguously
 
-error[E0659]: `issue_56125` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `issue_56125` is ambiguous
   --> $DIR/issue-56125.rs:18:9
    |
 LL |     use issue_56125::*;
    |         ^^^^^^^^^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
    = note: `issue_56125` could refer to a crate passed with `--extern`
    = help: use `::issue_56125` to refer to this crate unambiguously
 note: `issue_56125` could also refer to the module imported here
index 174088e8f6c1197fb5f17a00b1f41cfc585fb928..1a3ca4edaca9be106d3cb5d12d22e8b6d6984d05 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `core` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `core` is ambiguous
   --> $DIR/issue-57539.rs:4:9
    |
 LL |     use core;
    |         ^^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
    = note: `core` could refer to a built-in crate
    = help: use `::core` to refer to this crate unambiguously
 note: `core` could also refer to the module imported here
index f809698fe1d4d725f0ffea3baa3065aa3a4fb06a..c048d2ea204202904d94bea1d31df44c42bcfaae 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `exported` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `exported` is ambiguous
   --> $DIR/local-modularized-tricky-fail-1.rs:28:1
    |
 LL | exported!();
    | ^^^^^^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
 note: `exported` could refer to the macro defined here
   --> $DIR/local-modularized-tricky-fail-1.rs:5:5
    |
@@ -22,12 +23,13 @@ LL | use inner1::*;
    = help: consider adding an explicit import of `exported` to disambiguate
    = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `exported` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `exported` is ambiguous
   --> $DIR/local-modularized-tricky-fail-1.rs:28:1
    |
 LL | exported!();
    | ^^^^^^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
 note: `exported` could refer to the macro defined here
   --> $DIR/local-modularized-tricky-fail-1.rs:5:5
    |
@@ -46,12 +48,13 @@ LL | use inner1::*;
    = help: consider adding an explicit import of `exported` to disambiguate
    = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `panic` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `panic` is ambiguous
   --> $DIR/local-modularized-tricky-fail-1.rs:36:5
    |
 LL |     panic!();
    |     ^^^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
    = note: `panic` could refer to a macro from prelude
 note: `panic` could also refer to the macro defined here
   --> $DIR/local-modularized-tricky-fail-1.rs:11:5
@@ -66,12 +69,13 @@ LL |       define_panic!();
    = help: use `crate::panic` to refer to this macro unambiguously
    = note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `include` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `include` is ambiguous
   --> $DIR/local-modularized-tricky-fail-1.rs:47:1
    |
 LL | include!();
    | ^^^^^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
    = note: `include` could refer to a macro from prelude
 note: `include` could also refer to the macro defined here
   --> $DIR/local-modularized-tricky-fail-1.rs:17:5
index a5b90008272cf3494f1b49bd338758147a7aaf12..5f113ce2bee5df8045f87d635c07fa083796b5bf 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `bar` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `bar` is ambiguous
   --> $DIR/macro-paths.rs:13:5
    |
 LL |     bar::m! {
    |     ^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
 note: `bar` could refer to the module defined here
   --> $DIR/macro-paths.rs:14:9
    |
@@ -16,12 +17,13 @@ LL |     use foo::*;
    |         ^^^^^^
    = help: consider adding an explicit import of `bar` to disambiguate
 
-error[E0659]: `baz` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `baz` is ambiguous
   --> $DIR/macro-paths.rs:23:5
    |
 LL |     baz::m! {
    |     ^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `baz` could refer to the module defined here
   --> $DIR/macro-paths.rs:24:9
    |
index 27b34fe0c01fa8ab4ca548bb4f25e373ad09e088..110548d1d6ae1604784e8f4768d875ea3da40639 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `m` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/macros.rs:16:5
    |
 LL |     m! {
    |     ^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
 note: `m` could refer to the macro imported here
   --> $DIR/macros.rs:18:13
    |
@@ -16,12 +17,13 @@ LL |     use two_macros::*;
    |         ^^^^^^^^^^^^^
    = help: consider adding an explicit import of `m` to disambiguate
 
-error[E0659]: `m` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/macros.rs:16:5
    |
 LL |     m! {
    |     ^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
 note: `m` could refer to the macro imported here
   --> $DIR/macros.rs:18:13
    |
@@ -34,12 +36,13 @@ LL |     use two_macros::*;
    |         ^^^^^^^^^^^^^
    = help: consider adding an explicit import of `m` to disambiguate
 
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/macros.rs:30:9
    |
 LL |         m! {
    |         ^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro imported here
   --> $DIR/macros.rs:31:17
    |
index d79c719d826472d2f1668fc7171ec783e07c31c8..fd7e99165b551c40ad824042d33913e402e2454b 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `Foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `Foo` is ambiguous
   --> $DIR/rfc-1560-warning-cycle.rs:9:17
    |
 LL |         fn f(_: Foo) {}
    |                 ^^^ ambiguous name
    |
+   = note: ambiguous because of multiple glob imports of a name in the same module
 note: `Foo` could refer to the struct imported here
   --> $DIR/rfc-1560-warning-cycle.rs:7:13
    |
index 2fcbb2a045cb32edd31d37913c0c923d71d7ae0b..6ffb31c20e60a21e894468c603cdd18bbb6217e4 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `panic` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `panic` is ambiguous
   --> $DIR/shadow_builtin_macros.rs:15:14
    |
 LL |     fn f() { panic!(); }
    |              ^^^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
    = note: `panic` could refer to a macro from prelude
 note: `panic` could also refer to the macro imported here
   --> $DIR/shadow_builtin_macros.rs:14:9
@@ -13,12 +14,13 @@ LL |     use foo::*;
    = help: consider adding an explicit import of `panic` to disambiguate
    = help: or use `self::panic` to refer to this macro unambiguously
 
-error[E0659]: `panic` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `panic` is ambiguous
   --> $DIR/shadow_builtin_macros.rs:33:5
    |
 LL |     panic!();
    |     ^^^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
    = note: `panic` could refer to a macro from prelude
 note: `panic` could also refer to the macro defined here
   --> $DIR/shadow_builtin_macros.rs:30:9
@@ -30,12 +32,13 @@ LL |     m!();
    |     ---- in this macro invocation
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `n` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `n` is ambiguous
   --> $DIR/shadow_builtin_macros.rs:49:5
    |
 LL |     n!();
    |     ^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
 note: `n` could refer to the macro imported here
   --> $DIR/shadow_builtin_macros.rs:48:9
    |
@@ -49,12 +52,13 @@ note: `n` could also refer to the macro imported here
 LL | #[macro_use(n)]
    |             ^
 
-error[E0659]: `panic` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `panic` is ambiguous
   --> $DIR/shadow_builtin_macros.rs:20:14
    |
 LL |     fn f() { panic!(); }
    |              ^^^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
    = note: `panic` could refer to a macro from prelude
 note: `panic` could also refer to the macro imported here
   --> $DIR/shadow_builtin_macros.rs:19:26
index b15efd6c770eb2ccae0e8f5faec1fda60c067b42..0546b6b51b27342f71de3f2bbf09ef055d7f4c0b 100644 (file)
@@ -2,15 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/mismatched_trait_impl-2.rs:8:5
    |
 LL |     fn deref(&self) -> &dyn Trait {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Struct) -> &dyn Trait`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Struct) -> &'1 (dyn Trait + '1)`
    |
   ::: $SRC_DIR/core/src/ops/deref.rs:LL:COL
    |
 LL |     fn deref(&self) -> &Self::Target;
-   |     --------------------------------- expected `fn(&Struct) -> &(dyn Trait + 'static)`
+   |     --------------------------------- expected `fn(&'1 Struct) -> &'1 (dyn Trait + 'static)`
    |
-   = note: expected `fn(&Struct) -> &(dyn Trait + 'static)`
-              found `fn(&Struct) -> &dyn Trait`
+   = note: expected `fn(&'1 Struct) -> &'1 (dyn Trait + 'static)`
+              found `fn(&'1 Struct) -> &'1 (dyn Trait + '1)`
    = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
    = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
index 149c2aeb958c0712ce8f8c4d10ca7b8a3fc16e0e..c7a90c57add836b83d5f75a39b565a2693c58521 100644 (file)
@@ -2,13 +2,13 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/mismatched_trait_impl.rs:9:5
    |
 LL |     fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
-   |     ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32`
+   |     ---------------------------------------------- expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
 ...
 LL |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32`
    |
-   = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
-              found `fn(&i32, &u32, &u32) -> &u32`
+   = note: expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
+              found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32`
    = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
    = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
index 9a0bd827850cf5f0c59e307cb4e4c5cc2c47135f..84e5339122ead338eee30d7ad1e85c932e43d22f 100644 (file)
@@ -2,13 +2,13 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/mismatched_trait_impl.rs:9:5
    |
 LL |     fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
-   |     ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32`
+   |     ---------------------------------------------- expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
 ...
 LL |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32`
    |
-   = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
-              found `fn(&i32, &u32, &u32) -> &u32`
+   = note: expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
+              found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32`
    = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
    = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
index 17fad571385dc7815351ce80280c849422b14be2..739847c5cd5405e79143c0d8af9a20347ed22857 100644 (file)
@@ -6,7 +6,10 @@ LL |         .get(&"key".into())
    |          |
    |          cannot infer type for type parameter `Q` declared on the associated function `get`
    |
-   = note: cannot satisfy `String: Borrow<_>`
+   = note: multiple `impl`s satisfying `String: Borrow<_>` found in the following crates: `alloc`, `core`:
+           - impl Borrow<str> for String;
+           - impl<T> Borrow<T> for T
+             where T: ?Sized;
 
 error: aborting due to previous error
 
index 3c9d864c4263910f89113db7c68704d5fdc87dc1..0077c73474818e181af889ba661ee676e9946eae 100644 (file)
@@ -6,7 +6,11 @@ LL |         if String::from("a") == "a".try_into().unwrap() {}
    |                              |
    |                              cannot infer type
    |
-   = note: cannot satisfy `String: PartialEq<_>`
+   = note: multiple `impl`s satisfying `String: PartialEq<_>` found in the `alloc` crate:
+           - impl PartialEq for String;
+           - impl<'a, 'b> PartialEq<&'a str> for String;
+           - impl<'a, 'b> PartialEq<Cow<'a, str>> for String;
+           - impl<'a, 'b> PartialEq<str> for String;
 
 error: aborting due to previous error
 
index 8fbdc0c39c6aa38edce10d2f98470a2b06533879..a3171187e69e58d236a68abd471f9512f073bccf 100644 (file)
@@ -7,6 +7,7 @@ const fn not_fn_items() {
     //~^ ERROR expected a `FnOnce<()>` closure
     const_eval_select((), 42, 0xDEADBEEF);
     //~^ ERROR expected a `FnOnce<()>` closure
+    //~| ERROR expected a `FnOnce<()>` closure
 }
 
 const fn foo(n: i32) -> i32 {
index 78647e92138c2ccaa8dd3cd29001265654afea8b..5e1ab584d80cf2f9fa75b3bbc8af88489d3b315c 100644 (file)
@@ -1,8 +1,8 @@
 error[E0277]: expected a `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
-  --> $DIR/const-eval-select-bad.rs:6:34
+  --> $DIR/const-eval-select-bad.rs:6:27
    |
 LL |     const_eval_select((), || {}, || {});
-   |     -----------------            ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
+   |     -----------------     ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
    |     |
    |     required by a bound introduced by this call
    |
@@ -15,10 +15,10 @@ LL |     F: ~const FnOnce<ARG, Output = RET>,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
 
 error[E0277]: expected a `FnOnce<()>` closure, found `{integer}`
-  --> $DIR/const-eval-select-bad.rs:8:31
+  --> $DIR/const-eval-select-bad.rs:8:27
    |
 LL |     const_eval_select((), 42, 0xDEADBEEF);
-   |     -----------------         ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}`
+   |     -----------------     ^^ expected an `FnOnce<()>` closure, found `{integer}`
    |     |
    |     required by a bound introduced by this call
    |
@@ -30,8 +30,24 @@ note: required by a bound in `const_eval_select`
 LL |     F: ~const FnOnce<ARG, Output = RET>,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
 
+error[E0277]: expected a `FnOnce<()>` closure, found `{integer}`
+  --> $DIR/const-eval-select-bad.rs:8:31
+   |
+LL |     const_eval_select((), 42, 0xDEADBEEF);
+   |     -----------------         ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `FnOnce<()>` is not implemented for `{integer}`
+   = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
+note: required by a bound in `const_eval_select`
+  --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
+   |
+LL |     G: FnOnce<ARG, Output = RET> + ~const Drop,
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+
 error[E0271]: type mismatch resolving `<fn(i32) -> bool {bar} as FnOnce<(i32,)>>::Output == i32`
-  --> $DIR/const-eval-select-bad.rs:27:5
+  --> $DIR/const-eval-select-bad.rs:28:5
    |
 LL |     const_eval_select((1,), foo, bar);
    |     ^^^^^^^^^^^^^^^^^ expected `i32`, found `bool`
@@ -43,13 +59,13 @@ LL |     G: FnOnce<ARG, Output = RET> + ~const Drop,
    |                    ^^^^^^^^^^^^ required by this bound in `const_eval_select`
 
 error[E0631]: type mismatch in function arguments
-  --> $DIR/const-eval-select-bad.rs:32:37
+  --> $DIR/const-eval-select-bad.rs:33:32
    |
 LL | const fn foo(n: i32) -> i32 {
    | --------------------------- found signature of `fn(i32) -> _`
 ...
 LL |     const_eval_select((true,), foo, baz);
-   |     -----------------               ^^^ expected signature of `fn(bool) -> _`
+   |     -----------------          ^^^ expected signature of `fn(bool) -> _`
    |     |
    |     required by a bound introduced by this call
    |
@@ -59,7 +75,7 @@ note: required by a bound in `const_eval_select`
 LL |     F: ~const FnOnce<ARG, Output = RET>,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0271, E0277, E0631.
 For more information about an error, try `rustc --explain E0271`.
index 7597824e08f9d3550d5b790b997d52e6d7d4810d..09e20c0c777314202c0c0fe590ae82b3de989be0 100644 (file)
@@ -1,21 +1,11 @@
-error[E0283]: type annotations needed
+error[E0282]: type annotations needed
   --> $DIR/issue-16966.rs:2:5
    |
 LL |     panic!(std::default::Default::default());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `M` declared on the function `begin_panic`
    |
-   = note: cannot satisfy `_: Any`
-note: required by a bound in `begin_panic`
-  --> $SRC_DIR/std/src/panicking.rs:LL:COL
-   |
-LL | pub fn begin_panic<M: Any + Send>(msg: M) -> ! {
-   |                       ^^^ required by this bound in `begin_panic`
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider specifying the type argument in the function call
-   |
-LL |         $crate::rt::begin_panic::<M>($msg)
-   |                                +++++
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0283`.
+For more information about this error, try `rustc --explain E0282`.
index c2f6fc21acd7f6445286232866ef79249a04a8d1..92742b50619e011746406ff19c536dac0f72f97e 100644 (file)
@@ -10,7 +10,7 @@ note: required by a bound in `std::hash::Hash::hash`
   --> $SRC_DIR/core/src/hash/mod.rs:LL:COL
    |
 LL |     fn hash<H: Hasher>(&self, state: &mut H);
-   |                ^^^^^^ required by this bound in `std::hash::Hash::hash`
+   |             ^ required by this bound in `std::hash::Hash::hash`
    = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
index 584b05ec44d3fed5b1ce957a7c45a44b87090245..0bfbf538486deadd62245c4ec4f1bfd7b790c2a9 100644 (file)
@@ -5,7 +5,10 @@ LL | enum Delicious {
    | -------------- variant or associated item `PIE` not found here
 ...
 LL |     ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
-   |                                                       ^^^ variant or associated item not found in `Delicious`
+   |                                                       ^^^
+   |                                                       |
+   |                                                       variant or associated item not found in `Delicious`
+   |                                                       help: there is a variant with a similar name: `Pie`
 
 error: aborting due to previous error
 
index e6cec722978dd609a167cc390773fcbbc29e13a8..b345e90178742ee0049c08d733b604f2a1df7a0d 100644 (file)
@@ -1,4 +1,4 @@
-error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Next`
+error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized`
   --> $DIR/issue-23122-2.rs:9:17
    |
 LL |     type Next = <GetNext<T::Next> as Next>::Next;
index f00d5d32bbf28d6bc40fcfdb732e3cdebd512587..3b011f58b259d798ae98367bffa3d6df956d6c46 100644 (file)
@@ -4,7 +4,13 @@ error[E0283]: type annotations needed
 LL |     let _ = <S5<_>>::xxx;
    |             ^^^^^^^^^^^^ cannot infer type for struct `S5<_>`
    |
-   = note: cannot satisfy `S5<_>: Foo`
+note: multiple `impl`s satisfying `S5<_>: Foo` found
+  --> $DIR/issue-29147.rs:17:1
+   |
+LL | impl Foo for S5<u32> { fn xxx(&self) {} }
+   | ^^^^^^^^^^^^^^^^^^^^
+LL | impl Foo for S5<u64> { fn xxx(&self) {} }
+   | ^^^^^^^^^^^^^^^^^^^^
 note: required by `Foo::xxx`
   --> $DIR/issue-29147.rs:10:13
    |
index abed18d81f8d31d27882ad7ba2d74bb01c7e65b0..d93ffcb2262eb362edb6e0cd773599847741b139 100644 (file)
@@ -29,6 +29,7 @@ impl<T> Front for Vec<T> {
 
 struct M(PtrBack<Vec<M>>);
 
+#[allow(unused_must_use)]
 fn main() {
     std::mem::size_of::<M>();
 }
index 3b2d232e61f7e5c8c559c8835ca8e949df59d52a..11c23e5b659b7af06385f33dd0f0bd4ab1c9cf00 100644 (file)
@@ -1,8 +1,10 @@
 error[E0277]: `Rc<Foo>` cannot be shared between threads safely
-  --> $DIR/issue-40827.rs:14:5
+  --> $DIR/issue-40827.rs:14:7
    |
 LL |     f(Foo(Arc::new(Bar::B(None))));
-   |     ^ `Rc<Foo>` cannot be shared between threads safely
+   |     - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rc<Foo>` cannot be shared between threads safely
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: within `Bar`, the trait `Sync` is not implemented for `Rc<Foo>`
 note: required because it appears within the type `Bar`
@@ -23,10 +25,12 @@ LL | fn f<T: Send>(_: T) {}
    |         ^^^^ required by this bound in `f`
 
 error[E0277]: `Rc<Foo>` cannot be sent between threads safely
-  --> $DIR/issue-40827.rs:14:5
+  --> $DIR/issue-40827.rs:14:7
    |
 LL |     f(Foo(Arc::new(Bar::B(None))));
-   |     ^ `Rc<Foo>` cannot be sent between threads safely
+   |     - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rc<Foo>` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: within `Bar`, the trait `Send` is not implemented for `Rc<Foo>`
 note: required because it appears within the type `Bar`
diff --git a/src/test/ui/issues/issue-44005.rs b/src/test/ui/issues/issue-44005.rs
deleted file mode 100644 (file)
index ab3b921..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-pub trait Foo<'a> {
-    type Bar;
-    fn foo(&'a self) -> Self::Bar;
-}
-
-impl<'a, 'b, T: 'a> Foo<'a> for &'b T {
-    type Bar = &'a T;
-    fn foo(&'a self) -> &'a T {
-        self
-    }
-}
-
-pub fn uncallable<T, F>(x: T, f: F)
-where
-    T: for<'a> Foo<'a>,
-    F: for<'a> Fn(<T as Foo<'a>>::Bar),
-{
-    f(x.foo());
-}
-
-pub fn catalyst(x: &i32) {
-    broken(x, |_| {})
-}
-
-pub fn broken<F: Fn(&i32)>(x: &i32, f: F) {
-    uncallable(x, |y| f(y));
-    //~^ type mismatch
-}
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-44005.stderr b/src/test/ui/issues/issue-44005.stderr
deleted file mode 100644 (file)
index 307e444..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/issue-44005.rs:26:5
-   |
-LL |     uncallable(x, |y| f(y));
-   |     ^^^^^^^^^^    -------- found signature of `for<'r> fn(&'r i32) -> _`
-   |     |
-   |     expected signature of `for<'a> fn(<&i32 as Foo<'a>>::Bar) -> _`
-   |
-note: required by a bound in `uncallable`
-  --> $DIR/issue-44005.rs:16:8
-   |
-LL | pub fn uncallable<T, F>(x: T, f: F)
-   |        ---------- required by a bound in this
-...
-LL |     F: for<'a> Fn(<T as Foo<'a>>::Bar),
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `uncallable`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0631`.
index d88397fd7e15d2f68639e4e0cfb76d8767875381..df76a985559d08481719a915195ff666e87acd2e 100644 (file)
@@ -12,10 +12,10 @@ LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
    |
    = note: cannot satisfy `_: Tt`
 note: required by a bound in `Tt::const_val`
-  --> $DIR/issue-54954.rs:5:27
+  --> $DIR/issue-54954.rs:5:24
    |
 LL |     const fn const_val<T: Sized>() -> usize {
-   |                           ^^^^^ required by this bound in `Tt::const_val`
+   |                        ^ required by this bound in `Tt::const_val`
 
 error: aborting due to 2 previous errors
 
index e04dec24e445e9d1e625f715cf0a4e958adca493..6e030f1cc487573adfdf21f91b0fbbcf45e3004c 100644 (file)
@@ -1,6 +1,5 @@
 // run-fail
 // compile-flags: -C opt-level=3
-// min-llvm-version: 11.0
 // error-pattern: index out of bounds: the len is 0 but the index is 16777216
 // ignore-wasm no panic or subprocess support
 // ignore-emscripten no panic or subprocess support
index f1935ae253463ced17157bb2ff23fa66682e3b42..a53aadcfad0240eb41c132986970b597da111c77 100644 (file)
@@ -27,4 +27,5 @@ fn test(self, other: u64) -> u64 {
 fn main() {
     let xs: Vec<u64> = vec![1, 2, 3];
     println!("{}", 23u64.test(xs.iter().sum())); //~ ERROR: type annotations needed
+    //~^ ERROR type annotations needed
 }
index 430bbcabf83e81ad976abad619e2fb5f989d63aa..da84a6b52da2bd28e6bdc888aea7619f450943ce 100644 (file)
@@ -4,6 +4,26 @@ error[E0284]: type annotations needed: cannot satisfy `<u64 as Test<_>>::Output
 LL |     println!("{}", 23u64.test(xs.iter().sum()));
    |                          ^^^^ cannot satisfy `<u64 as Test<_>>::Output == _`
 
-error: aborting due to previous error
+error[E0283]: type annotations needed
+  --> $DIR/issue-69455.rs:29:26
+   |
+LL |     println!("{}", 23u64.test(xs.iter().sum()));
+   |                          ^^^^ cannot infer type for type parameter `Rhs` declared on the trait `Test`
+   |
+note: multiple `impl`s satisfying `u64: Test<_>` found
+  --> $DIR/issue-69455.rs:11:1
+   |
+LL | impl Test<u32> for u64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Test<u64> for u64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^
+help: consider specifying the type argument in the method call
+   |
+LL |     println!("{}", 23u64.test(xs.iter().sum::<S>()));
+   |                                            +++++
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0283, E0284.
+For more information about an error, try `rustc --explain E0283`.
index cc7f1fa0f558056be74f56ba0475e22f822d2bd7..7a76e9ef205ff18c73bf3f1538331d51f1a1d67c 100644 (file)
@@ -28,5 +28,6 @@ fn main() {
     let b: [u8; 3] = [0u8; 3];
 
     0u16.foo(b); //~ ERROR type annotations needed
+    //~^ ERROR type annotations needed
     //<u16 as Foo<[(); 3]>>::foo(0u16, b);
 }
index 776370331a4c9193cd2c568ea14b0a3eab1e6b47..ecf78e48e0e2af68b276a8b26cc8a8dbece5b730 100644 (file)
@@ -4,6 +4,22 @@ error[E0284]: type annotations needed: cannot satisfy `<u8 as Element<_>>::Array
 LL |     0u16.foo(b);
    |          ^^^ cannot satisfy `<u8 as Element<_>>::Array == [u8; 3]`
 
-error: aborting due to previous error
+error[E0283]: type annotations needed
+  --> $DIR/issue-69683.rs:30:10
+   |
+LL |     0u16.foo(b);
+   |          ^^^ cannot infer type for type parameter `I` declared on the trait `Foo`
+   |
+note: multiple `impl`s satisfying `u8: Element<_>` found
+  --> $DIR/issue-69683.rs:5:1
+   |
+LL | impl<T> Element<()> for T {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl<T: Element<S>, S> Element<[S; 3]> for T {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0283, E0284.
+For more information about an error, try `rustc --explain E0283`.
index 4edbd9ca15de7d5bac3031f745d3e39fe2a07893..916a7832c6886e537174f895792a9d166e959f97 100644 (file)
@@ -5,10 +5,13 @@ fn no_err() {
 
 fn err() {
     String::from("x".as_ref()); //~ ERROR type annotations needed
+    //~^ ERROR type annotations needed
 }
 
 fn arg_pat_closure_err() {
     |x| String::from("x".as_ref()); //~ ERROR type annotations needed
+    //~^ ERROR type annotations needed
+    //~| ERROR type annotations needed
 }
 
 fn local_pat_closure_err() {
@@ -17,12 +20,14 @@ fn local_pat_closure_err() {
 
 fn err_first_arg_pat() {
     String::from("x".as_ref()); //~ ERROR type annotations needed
+    //~^ ERROR type annotations needed
     |x: String| x;
 }
 
 fn err_second_arg_pat() {
     |x: String| x;
     String::from("x".as_ref()); //~ ERROR type annotations needed
+    //~^ ERROR type annotations needed
 }
 
 fn err_mid_arg_pat() {
@@ -31,6 +36,7 @@ fn err_mid_arg_pat() {
     |x: String| x;
     |x: String| x;
     String::from("x".as_ref()); //~ ERROR type annotations needed
+    //~^ ERROR type annotations needed
     |x: String| x;
     |x: String| x;
     |x: String| x;
@@ -39,12 +45,14 @@ fn err_mid_arg_pat() {
 
 fn err_first_local_pat() {
     String::from("x".as_ref()); //~ ERROR type annotations needed
+    //~^ ERROR type annotations needed
     let _ = String::from("x");
 }
 
 fn err_second_local_pat() {
     let _ = String::from("x");
     String::from("x".as_ref()); //~ ERROR type annotations needed
+    //~^ ERROR type annotations needed
 }
 
 fn err_mid_local_pat() {
@@ -53,6 +61,7 @@ fn err_mid_local_pat() {
     let _ = String::from("x");
     let _ = String::from("x");
     String::from("x".as_ref()); //~ ERROR type annotations needed
+    //~^ ERROR type annotations needed
     let _ = String::from("x");
     let _ = String::from("x");
     let _ = String::from("x");
index af3459a7d2d6fec7194d42c57f85009d3acfc8d3..1747ca5bb04b89c15ac765404186f42f942cbfdd 100644 (file)
@@ -4,36 +4,89 @@ error[E0283]: type annotations needed
 LL |     String::from("x".as_ref());
    |     ^^^^^^^^^^^^ cannot infer type for reference `&_`
    |
-   = note: cannot satisfy `String: From<&_>`
+   = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+           - impl<> From<&String> for String;
+           - impl<> From<&str> for String;
 note: required by `from`
   --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
    |
 LL |     fn from(_: T) -> Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0283]: type annotations needed
+  --> $DIR/issue-72690.rs:7:22
+   |
+LL |     String::from("x".as_ref());
+   |                  ----^^^^^^--
+   |                  |   |
+   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
+   |                  this method call resolves to `&T`
+   |
+   = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<OsStr> for str;
+           - impl AsRef<Path> for str;
+           - impl AsRef<[u8]> for str;
+           - impl AsRef<str> for str;
+
 error[E0282]: type annotations needed
-  --> $DIR/issue-72690.rs:11:6
+  --> $DIR/issue-72690.rs:12:6
    |
 LL |     |x| String::from("x".as_ref());
    |      ^ consider giving this closure parameter a type
 
+error[E0283]: type annotations needed
+  --> $DIR/issue-72690.rs:12:9
+   |
+LL |     |x| String::from("x".as_ref());
+   |         ^^^^^^^^^^^^ cannot infer type for reference `&_`
+   |
+   = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+           - impl<> From<&String> for String;
+           - impl<> From<&str> for String;
+note: required by `from`
+  --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
+   |
+LL |     fn from(_: T) -> Self;
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0283]: type annotations needed
+  --> $DIR/issue-72690.rs:12:26
+   |
+LL |     |x| String::from("x".as_ref());
+   |                      ----^^^^^^--
+   |                      |   |
+   |                      |   cannot infer type for type parameter `T` declared on the trait `AsRef`
+   |                      this method call resolves to `&T`
+   |
+   = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<OsStr> for str;
+           - impl AsRef<Path> for str;
+           - impl AsRef<[u8]> for str;
+           - impl AsRef<str> for str;
+
 error[E0283]: type annotations needed for `&T`
-  --> $DIR/issue-72690.rs:15:17
+  --> $DIR/issue-72690.rs:18:17
    |
 LL |     let _ = "x".as_ref();
    |         -       ^^^^^^ cannot infer type for type parameter `T` declared on the trait `AsRef`
    |         |
    |         consider giving this pattern the explicit type `&T`, where the type parameter `T` is specified
    |
-   = note: cannot satisfy `str: AsRef<_>`
+   = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<OsStr> for str;
+           - impl AsRef<Path> for str;
+           - impl AsRef<[u8]> for str;
+           - impl AsRef<str> for str;
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-72690.rs:19:5
+  --> $DIR/issue-72690.rs:22:5
    |
 LL |     String::from("x".as_ref());
    |     ^^^^^^^^^^^^ cannot infer type for reference `&_`
    |
-   = note: cannot satisfy `String: From<&_>`
+   = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+           - impl<> From<&String> for String;
+           - impl<> From<&str> for String;
 note: required by `from`
   --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
    |
@@ -41,12 +94,29 @@ LL |     fn from(_: T) -> Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-72690.rs:25:5
+  --> $DIR/issue-72690.rs:22:22
+   |
+LL |     String::from("x".as_ref());
+   |                  ----^^^^^^--
+   |                  |   |
+   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
+   |                  this method call resolves to `&T`
+   |
+   = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<OsStr> for str;
+           - impl AsRef<Path> for str;
+           - impl AsRef<[u8]> for str;
+           - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+  --> $DIR/issue-72690.rs:29:5
    |
 LL |     String::from("x".as_ref());
    |     ^^^^^^^^^^^^ cannot infer type for reference `&_`
    |
-   = note: cannot satisfy `String: From<&_>`
+   = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+           - impl<> From<&String> for String;
+           - impl<> From<&str> for String;
 note: required by `from`
   --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
    |
@@ -54,12 +124,29 @@ LL |     fn from(_: T) -> Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-72690.rs:33:5
+  --> $DIR/issue-72690.rs:29:22
+   |
+LL |     String::from("x".as_ref());
+   |                  ----^^^^^^--
+   |                  |   |
+   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
+   |                  this method call resolves to `&T`
+   |
+   = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<OsStr> for str;
+           - impl AsRef<Path> for str;
+           - impl AsRef<[u8]> for str;
+           - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+  --> $DIR/issue-72690.rs:38:5
    |
 LL |     String::from("x".as_ref());
    |     ^^^^^^^^^^^^ cannot infer type for reference `&_`
    |
-   = note: cannot satisfy `String: From<&_>`
+   = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+           - impl<> From<&String> for String;
+           - impl<> From<&str> for String;
 note: required by `from`
   --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
    |
@@ -67,12 +154,29 @@ LL |     fn from(_: T) -> Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-72690.rs:41:5
+  --> $DIR/issue-72690.rs:38:22
+   |
+LL |     String::from("x".as_ref());
+   |                  ----^^^^^^--
+   |                  |   |
+   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
+   |                  this method call resolves to `&T`
+   |
+   = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<OsStr> for str;
+           - impl AsRef<Path> for str;
+           - impl AsRef<[u8]> for str;
+           - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+  --> $DIR/issue-72690.rs:47:5
    |
 LL |     String::from("x".as_ref());
    |     ^^^^^^^^^^^^ cannot infer type for reference `&_`
    |
-   = note: cannot satisfy `String: From<&_>`
+   = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+           - impl<> From<&String> for String;
+           - impl<> From<&str> for String;
 note: required by `from`
   --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
    |
@@ -80,12 +184,29 @@ LL |     fn from(_: T) -> Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-72690.rs:47:5
+  --> $DIR/issue-72690.rs:47:22
+   |
+LL |     String::from("x".as_ref());
+   |                  ----^^^^^^--
+   |                  |   |
+   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
+   |                  this method call resolves to `&T`
+   |
+   = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<OsStr> for str;
+           - impl AsRef<Path> for str;
+           - impl AsRef<[u8]> for str;
+           - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+  --> $DIR/issue-72690.rs:54:5
    |
 LL |     String::from("x".as_ref());
    |     ^^^^^^^^^^^^ cannot infer type for reference `&_`
    |
-   = note: cannot satisfy `String: From<&_>`
+   = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+           - impl<> From<&String> for String;
+           - impl<> From<&str> for String;
 note: required by `from`
   --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
    |
@@ -93,19 +214,51 @@ LL |     fn from(_: T) -> Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-72690.rs:55:5
+  --> $DIR/issue-72690.rs:54:22
+   |
+LL |     String::from("x".as_ref());
+   |                  ----^^^^^^--
+   |                  |   |
+   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
+   |                  this method call resolves to `&T`
+   |
+   = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<OsStr> for str;
+           - impl AsRef<Path> for str;
+           - impl AsRef<[u8]> for str;
+           - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+  --> $DIR/issue-72690.rs:63:5
    |
 LL |     String::from("x".as_ref());
    |     ^^^^^^^^^^^^ cannot infer type for reference `&_`
    |
-   = note: cannot satisfy `String: From<&_>`
+   = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+           - impl<> From<&String> for String;
+           - impl<> From<&str> for String;
 note: required by `from`
   --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
    |
 LL |     fn from(_: T) -> Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 9 previous errors
+error[E0283]: type annotations needed
+  --> $DIR/issue-72690.rs:63:22
+   |
+LL |     String::from("x".as_ref());
+   |                  ----^^^^^^--
+   |                  |   |
+   |                  |   cannot infer type for type parameter `T` declared on the trait `AsRef`
+   |                  this method call resolves to `&T`
+   |
+   = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+           - impl AsRef<OsStr> for str;
+           - impl AsRef<Path> for str;
+           - impl AsRef<[u8]> for str;
+           - impl AsRef<str> for str;
+
+error: aborting due to 18 previous errors
 
 Some errors have detailed explanations: E0282, E0283.
 For more information about an error, try `rustc --explain E0282`.
index 54df7fccaa5c00fe97c9fc813fefa3600d90639a..59bb98a340a5f894803cdf0d2fab79e10a48d67a 100644 (file)
@@ -120,10 +120,10 @@ LL | | }
    | |_^
 help: try to construct one of the enum's variants
    |
-LL |     let x = A::TupleWithFields(3);
-   |             ~~~~~~~~~~~~~~~~~~
 LL |     let x = A::Tuple(3);
    |             ~~~~~~~~
+LL |     let x = A::TupleWithFields(3);
+   |             ~~~~~~~~~~~~~~~~~~
 
 error[E0532]: expected tuple struct or tuple variant, found enum `A`
   --> $DIR/issue-73427.rs:42:12
@@ -145,10 +145,10 @@ LL | | }
    | |_^
 help: try to match against one of the enum's variants
    |
-LL |     if let A::TupleWithFields(3) = x { }
-   |            ~~~~~~~~~~~~~~~~~~
 LL |     if let A::Tuple(3) = x { }
    |            ~~~~~~~~
+LL |     if let A::TupleWithFields(3) = x { }
+   |            ~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 6 previous errors
 
index ec54ed005173b148fc37bbe146e4e7736caad086..158317efe4782c9b1e23014e26503f5c76a304d3 100644 (file)
@@ -1,6 +1,5 @@
 // check-pass
 // edition:2021
-// compile-flags: -Zunstable-options
 
 use std::array::IntoIter;
 use std::ops::Deref;
diff --git a/src/test/ui/iterators/rsplit-clone.rs b/src/test/ui/iterators/rsplit-clone.rs
new file mode 100644 (file)
index 0000000..911da74
--- /dev/null
@@ -0,0 +1,11 @@
+// check-pass
+
+// RSplit<T, P> previously required T: Clone in order to be Clone
+
+struct NotClone;
+
+fn main() {
+    let elements = [NotClone, NotClone, NotClone];
+    let rsplit = elements.rsplit(|_| false);
+    rsplit.clone();
+}
diff --git a/src/test/ui/let-else/issue-89960.rs b/src/test/ui/let-else/issue-89960.rs
new file mode 100644 (file)
index 0000000..8fd55ad
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(let_else)]
+
+fn main() {
+    // FIXME: more precise diagnostics
+    let Some(ref mut meow) = Some(()) else { return };
+    //~^ ERROR: cannot borrow value as mutable, as `val` is not declared as mutable
+}
diff --git a/src/test/ui/let-else/issue-89960.stderr b/src/test/ui/let-else/issue-89960.stderr
new file mode 100644 (file)
index 0000000..697f04d
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0596]: cannot borrow value as mutable, as `val` is not declared as mutable
+  --> $DIR/issue-89960.rs:5:14
+   |
+LL |     let Some(ref mut meow) = Some(()) else { return };
+   |     ---------^^^^^^^^^^^^-----------------------------
+   |     |        |
+   |     |        cannot borrow as mutable
+   |     help: consider changing this to be mutable: `mut val`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
index 6551e24cc83d063376dd6a066269ea9f4f587618..edee6576244722e0d093a3cf49350c4579285c72 100644 (file)
@@ -4,7 +4,7 @@ error: a `&&` expression cannot be directly assigned in `let...else`
 LL |     let true = true && false else { return };
    |                ^^^^^^^^^^^^^
    |
-help: wrap the expression in parenthesis
+help: wrap the expression in parentheses
    |
 LL |     let true = (true && false) else { return };
    |                +             +
@@ -15,7 +15,7 @@ error: a `||` expression cannot be directly assigned in `let...else`
 LL |     let true = true || false else { return };
    |                ^^^^^^^^^^^^^
    |
-help: wrap the expression in parenthesis
+help: wrap the expression in parentheses
    |
 LL |     let true = (true || false) else { return };
    |                +             +
index eac029c848b20ada60838cc0cab55d844302fb26..51051bbd4d8d6c9fb0af145b22572ab11ab46626 100644 (file)
@@ -4,7 +4,7 @@ error: right curly brace `}` before `else` in a `let...else` statement not allow
 LL |     let Some(1) = { Some(1) } else {
    |                             ^
    |
-help: try wrapping the expression in parenthesis
+help: try wrapping the expression in parentheses
    |
 LL |     let Some(1) = ({ Some(1) }) else {
    |                   +           +
@@ -15,7 +15,7 @@ error: right curly brace `}` before `else` in a `let...else` statement not allow
 LL |     let Some(1) = loop { break Some(1) } else {
    |                                        ^
    |
-help: try wrapping the expression in parenthesis
+help: try wrapping the expression in parentheses
    |
 LL |     let Some(1) = (loop { break Some(1) }) else {
    |                   +                      +
@@ -26,7 +26,7 @@ error: right curly brace `}` before `else` in a `let...else` statement not allow
 LL |     let 2 = 1 + match 1 { n => n } else {
    |                                  ^
    |
-help: try wrapping the expression in parenthesis
+help: try wrapping the expression in parentheses
    |
 LL |     let 2 = 1 + (match 1 { n => n }) else {
    |                 +                  +
@@ -37,7 +37,7 @@ error: right curly brace `}` before `else` in a `let...else` statement not allow
 LL |     let Some(1) = unsafe { unsafe_fn() } else {
    |                                        ^
    |
-help: try wrapping the expression in parenthesis
+help: try wrapping the expression in parentheses
    |
 LL |     let Some(1) = (unsafe { unsafe_fn() }) else {
    |                   +                      +
diff --git a/src/test/ui/let-else/let-else-if.rs b/src/test/ui/let-else/let-else-if.rs
new file mode 100644 (file)
index 0000000..c3a1733
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(let_else)]
+
+fn main() {
+    let Some(_) = Some(()) else if true {
+        //~^ ERROR conditional `else if` is not supported for `let...else`
+        return;
+    } else {
+        return;
+    };
+}
diff --git a/src/test/ui/let-else/let-else-if.stderr b/src/test/ui/let-else/let-else-if.stderr
new file mode 100644 (file)
index 0000000..38c739f
--- /dev/null
@@ -0,0 +1,18 @@
+error: conditional `else if` is not supported for `let...else`
+  --> $DIR/let-else-if.rs:4:33
+   |
+LL |     let Some(_) = Some(()) else if true {
+   |                                 ^^ expected `{`
+   |
+help: try placing this code inside a block
+   |
+LL ~     let Some(_) = Some(()) else { if true {
+LL +
+LL +         return;
+LL +     } else {
+LL +         return;
+LL ~     } };
+   |
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/issue-90170-elision-mismatch.fixed b/src/test/ui/lifetimes/issue-90170-elision-mismatch.fixed
new file mode 100644 (file)
index 0000000..0bc889e
--- /dev/null
@@ -0,0 +1,9 @@
+// run-rustfix
+
+pub fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+pub fn foo2<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/issue-90170-elision-mismatch.nll.stderr b/src/test/ui/lifetimes/issue-90170-elision-mismatch.nll.stderr
new file mode 100644 (file)
index 0000000..a5bc745
--- /dev/null
@@ -0,0 +1,29 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-90170-elision-mismatch.rs:3:40
+   |
+LL | pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); }
+   |                        -        -      ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |                        |        |
+   |                        |        let's call the lifetime of this reference `'1`
+   |                        let's call the lifetime of this reference `'2`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-90170-elision-mismatch.rs:5:44
+   |
+LL | pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); }
+   |                         -           -      ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |                         |           |
+   |                         |           let's call the lifetime of this reference `'1`
+   |                         let's call the lifetime of this reference `'2`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-90170-elision-mismatch.rs:7:63
+   |
+LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); }
+   |                                               -        -      ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |                                               |        |
+   |                                               |        let's call the lifetime of this reference `'1`
+   |                                               let's call the lifetime of this reference `'2`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/lifetimes/issue-90170-elision-mismatch.rs b/src/test/ui/lifetimes/issue-90170-elision-mismatch.rs
new file mode 100644 (file)
index 0000000..1d6573c
--- /dev/null
@@ -0,0 +1,9 @@
+// run-rustfix
+
+pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/issue-90170-elision-mismatch.stderr b/src/test/ui/lifetimes/issue-90170-elision-mismatch.stderr
new file mode 100644 (file)
index 0000000..7fa092c
--- /dev/null
@@ -0,0 +1,45 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/issue-90170-elision-mismatch.rs:3:47
+   |
+LL | pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); }
+   |                        ---      ---           ^ ...but data from `y` flows into `x` here
+   |                                 |
+   |                                 these two types are declared with different lifetimes...
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+   |
+LL | pub fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+   |           ++++              ++          ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/issue-90170-elision-mismatch.rs:5:51
+   |
+LL | pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); }
+   |                         ------      ---           ^ ...but data from `y` flows into `x` here
+   |                                     |
+   |                                     these two types are declared with different lifetimes...
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+   |
+LL | pub fn foo2<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+   |            ++++              ~~          ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/issue-90170-elision-mismatch.rs:7:70
+   |
+LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); }
+   |                                               ---      ---           ^ ...but data from `y` flows into `x` here
+   |                                                        |
+   |                                                        these two types are declared with different lifetimes...
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+   |
+LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+   |                                                ++          ++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
index 0aff80c6fbdd3c3fb3f316c75ea0f8a940e7a597..5c793636778ea2c9505bcb81e5f4416c5e7bf838 100644 (file)
@@ -5,6 +5,12 @@ LL | fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) {
    |                                   ---           --- these two types are declared with different lifetimes...
 LL |     *v = x;
    |          ^ ...but data from `x` flows here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(&mut (ref mut v, w): &mut (&'a u8, &u8), x: &'a u8) {
+   |       ++++                             ++               ++
 
 error: aborting due to previous error
 
index 2e5ff6782d3b65ac0f617879e7cb025caa750893..1a7b4fca1ba7846729a02f714d3d06597142675f 100644 (file)
@@ -5,6 +5,12 @@ LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
    |                     ---                 --- these two types are declared with different lifetimes...
 LL |     z.push((x,y));
    |             ^ ...but data flows into `z` here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(z: &mut Vec<(&'a u8,&u8)>, (x, y): (&'a u8, &u8)) {
+   |       ++++               ++                     ++
 
 error[E0623]: lifetime mismatch
   --> $DIR/ex3-both-anon-regions-3.rs:2:15
@@ -13,6 +19,12 @@ LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
    |                         ---                  --- these two types are declared with different lifetimes...
 LL |     z.push((x,y));
    |               ^ ...but data flows into `z` here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(z: &mut Vec<(&u8,&'a u8)>, (x, y): (&u8, &'a u8)) {
+   |       ++++                   ++                      ++
 
 error: aborting due to 2 previous errors
 
index d2cc3dba6a4336cce5781dd19a8b6249d50f26f8..6ed3528bb9faac790382bea6d763496425066ea0 100644 (file)
@@ -5,6 +5,12 @@ LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
    |                               ---      --- these two types are declared with different lifetimes...
 LL |   y.push(z);
    |          ^ ...but data from `z` flows into `y` here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(x:fn(&u8, &u8), y: Vec<&'a u8>, z: &'a u8) {
+   |       ++++                         ++          ++
 
 error: aborting due to previous error
 
index 2acc4eaf60f557dc1510588e1e5c794dc0b0fb0a..ede1631db271c46593a8f68186fabb5a7a988984 100644 (file)
@@ -5,6 +5,12 @@ LL | fn foo(x:Box<dyn Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) {
    |                     ---  --- these two types are declared with different lifetimes...
 LL |   y.push(z);
    |          ^ ...but data from `z` flows into `y` here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(x:Box<dyn Fn(&'a u8, &'a u8)> , y: Vec<&u8>, z: &u8) {
+   |       ++++               ++      ++
 
 error: aborting due to previous error
 
index b2784827672b8fb165d45c6b5f286673d7cc1589..cf405c0de3f0b40924f451f4cc424696217ec7de 100644 (file)
@@ -5,6 +5,12 @@ LL | fn foo(x: &mut Vec<&u8>, y: &u8) {
    |                    ---      --- these two types are declared with different lifetimes...
 LL |     x.push(y);
    |            ^ ...but data from `y` flows into `x` here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) {
+   |       ++++              ++          ++
 
 error: aborting due to previous error
 
index 060e6954403c0f3a8f0ddf8410bce301d7e3f564..3040a8512ce1d9b9fbf050796590fb78de9b45d8 100644 (file)
@@ -2,13 +2,13 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/lifetime-mismatch-between-trait-and-impl.rs:6:5
    |
 LL |     fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32;
-   |     ------------------------------------------- expected `fn(&i32, &'a i32) -> &'a i32`
+   |     ------------------------------------------- expected `fn(&'1 i32, &'a i32) -> &'a i32`
 ...
 LL |     fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &i32) -> &i32`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'1 i32) -> &'1 i32`
    |
-   = note: expected `fn(&i32, &'a i32) -> &'a i32`
-              found `fn(&i32, &i32) -> &i32`
+   = note: expected `fn(&'1 i32, &'a i32) -> &'a i32`
+              found `fn(&'1 i32, &'1 i32) -> &'1 i32`
    = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
    = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
 
index 3fab9148392beae16e234badeeae7c8bfcf367ee..3a3d81176d691363bd6488e7bc2d8fb7f78ee668 100644 (file)
@@ -1,6 +1,6 @@
 // --force-warn $LINT causes $LINT (which is deny-by-default) to warn
 // despite $LINT being allowed on command line
-// compile-flags: -A const_err --force-warn const_err -Zunstable-options
+// compile-flags: -A const_err --force-warn const_err
 // check-pass
 
 const C: i32 = 1 / 0;
index 4eb05b538b0baea63e6e4c9c9bdc75272e98d7e1..9736027452a8df0811863d80ea2d3c1cceaa7e9f 100644 (file)
@@ -1,6 +1,6 @@
 // --force-warn $LINT_GROUP causes $LINT (which is warn-by-default) to warn
 // despite $LINT being allowed on command line
-// compile-flags: -A bare-trait-objects --force-warn rust-2018-idioms -Zunstable-options
+// compile-flags: -A bare-trait-objects --force-warn rust-2018-idioms
 // check-pass
 
 pub trait SomeTrait {}
index d2cb3417be68a272c412622ac06afdc40994f8c1..267e7b45f0c2137c3666950640ffc551332c68c2 100644 (file)
@@ -1,6 +1,6 @@
 // --force-warn $LINT causes $LINT (which is warn-by-default) to warn
 // despite being allowed in one submodule (but not the other)
-// compile-flags: --force-warn dead_code -Zunstable-options
+// compile-flags: --force-warn dead_code
 // check-pass
 
 mod one {
index fa25a1f8a842a906fd9c140e61aae4c253c8a77f..d1d4f5602f271eeb0bb1034c5279667cc55f0659 100644 (file)
@@ -1,5 +1,5 @@
 // --force-warn warnings is an error
-// compile-flags: --force-warn warnings -Zunstable-options
+// compile-flags: --force-warn warnings
 // error-pattern: `warnings` lint group is not supported
 
 fn main() {}
index 03f5788b527d3fabfd50bfcfddd9f1325a0874a9..1faeed33704511d900175c73dfe6577a2b283179 100644 (file)
@@ -2,8 +2,6 @@ error[E0602]: `warnings` lint group is not supported with ´--force-warn´
 
 error[E0602]: `warnings` lint group is not supported with ´--force-warn´
 
-error[E0602]: `warnings` lint group is not supported with ´--force-warn´
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0602`.
diff --git a/src/test/ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs b/src/test/ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs
new file mode 100644 (file)
index 0000000..425e270
--- /dev/null
@@ -0,0 +1,9 @@
+// check-pass
+// Allowing the code lint should work without warning and
+// the text flow char in the comment should be ignored.
+
+#![allow(text_direction_codepoint_in_comment)]
+
+fn main() {
+    // U+2066 LEFT-TO-RIGHT ISOLATE follows:⁦⁦
+}
diff --git a/src/test/ui/lint/must_not_suspend/gated.rs b/src/test/ui/lint/must_not_suspend/gated.rs
new file mode 100644 (file)
index 0000000..acb81b0
--- /dev/null
@@ -0,0 +1,14 @@
+// edition:2018
+#![deny(must_not_suspend)]  //~ ERROR the `must_not_suspend`
+//~| ERROR the `must_not_suspend`
+//~| ERROR the `must_not_suspend`
+
+async fn other() {}
+
+pub async fn uhoh(m: std::sync::Mutex<()>) {
+    let _guard = m.lock().unwrap(); //~ ERROR `MutexGuard` held across
+    other().await;
+}
+
+fn main() {
+}
diff --git a/src/test/ui/lint/must_not_suspend/gated.stderr b/src/test/ui/lint/must_not_suspend/gated.stderr
new file mode 100644 (file)
index 0000000..be077de
--- /dev/null
@@ -0,0 +1,54 @@
+error[E0658]: the `must_not_suspend` lint is unstable
+  --> $DIR/gated.rs:2:1
+   |
+LL | #![deny(must_not_suspend)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
+   = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
+
+error[E0658]: the `must_not_suspend` lint is unstable
+  --> $DIR/gated.rs:2:1
+   |
+LL | #![deny(must_not_suspend)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
+   = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
+
+error[E0658]: the `must_not_suspend` lint is unstable
+  --> $DIR/gated.rs:2:1
+   |
+LL | #![deny(must_not_suspend)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
+   = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
+
+error: `MutexGuard` held across a suspend point, but should not be
+  --> $DIR/gated.rs:9:9
+   |
+LL |     let _guard = m.lock().unwrap();
+   |         ^^^^^^
+LL |     other().await;
+   |     ------------- the value is held across this suspend point
+   |
+note: the lint level is defined here
+  --> $DIR/gated.rs:2:9
+   |
+LL | #![deny(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
+note: holding a MutexGuard across suspend points can cause deadlocks, delays, and cause Futures to not implement `Send`
+  --> $DIR/gated.rs:9:9
+   |
+LL |     let _guard = m.lock().unwrap();
+   |         ^^^^^^
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+  --> $DIR/gated.rs:9:9
+   |
+LL |     let _guard = m.lock().unwrap();
+   |         ^^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/lint/must_not_suspend/issue-89562.rs b/src/test/ui/lint/must_not_suspend/issue-89562.rs
new file mode 100644 (file)
index 0000000..acdb36f
--- /dev/null
@@ -0,0 +1,19 @@
+// edition:2018
+// run-pass
+
+use std::sync::Mutex;
+
+// Copied from the issue. Allow-by-default for now, so run-pass
+pub async fn foo() {
+    let foo = Mutex::new(1);
+    let lock = foo.lock().unwrap();
+
+    // Prevent mutex lock being held across `.await` point.
+    drop(lock);
+
+    bar().await;
+}
+
+async fn bar() {}
+
+fn main() {}
index 596249b2e4e4fa8efd4eebb4b7bea11a3b6359c9..7bb895e7d36438f143181273f304f4d2c017f374 100644 (file)
@@ -1,4 +1,5 @@
 // edition:2018
+#![feature(must_not_suspend)]
 #![deny(must_not_suspend)]
 
 async fn other() {}
index 093f581264f36c3eea29df0367f2453293618c60..dde506c19e72501b9bb7fdce98902506890c2e08 100644 (file)
@@ -1,5 +1,5 @@
 error: `MutexGuard` held across a suspend point, but should not be
-  --> $DIR/mutex.rs:7:9
+  --> $DIR/mutex.rs:8:9
    |
 LL |     let _guard = m.lock().unwrap();
    |         ^^^^^^
@@ -7,17 +7,17 @@ LL |     other().await;
    |     ------------- the value is held across this suspend point
    |
 note: the lint level is defined here
-  --> $DIR/mutex.rs:2:9
+  --> $DIR/mutex.rs:3:9
    |
 LL | #![deny(must_not_suspend)]
    |         ^^^^^^^^^^^^^^^^
 note: holding a MutexGuard across suspend points can cause deadlocks, delays, and cause Futures to not implement `Send`
-  --> $DIR/mutex.rs:7:9
+  --> $DIR/mutex.rs:8:9
    |
 LL |     let _guard = m.lock().unwrap();
    |         ^^^^^^
 help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
-  --> $DIR/mutex.rs:7:9
+  --> $DIR/mutex.rs:8:9
    |
 LL |     let _guard = m.lock().unwrap();
    |         ^^^^^^
index 50a696ba52322adb11dab5942328ae665f85fb2d..7fdea66a23517d5967e4241685820d499471f4e9 100644 (file)
@@ -1,6 +1,7 @@
 // edition:2018
 // run-pass
 #![feature(must_not_suspend)]
+#![warn(must_not_suspend)]
 
 #[must_not_suspend = "You gotta use Umm's, ya know?"]
 struct Umm {
index 24f52275b430afe1114bc69926318f92970e8335..42374d4acac275f304fab03cccada0f7f85734e9 100644 (file)
@@ -1,19 +1,23 @@
 warning: `Umm` held across a suspend point, but should not be
-  --> $DIR/warn.rs:20:9
+  --> $DIR/warn.rs:21:9
    |
 LL |     let _guard = bar();
    |         ^^^^^^
 LL |     other().await;
    |     ------------- the value is held across this suspend point
    |
-   = note: `#[warn(must_not_suspend)]` on by default
+note: the lint level is defined here
+  --> $DIR/warn.rs:4:9
+   |
+LL | #![warn(must_not_suspend)]
+   |         ^^^^^^^^^^^^^^^^
 note: You gotta use Umm's, ya know?
-  --> $DIR/warn.rs:20:9
+  --> $DIR/warn.rs:21:9
    |
 LL |     let _guard = bar();
    |         ^^^^^^
 help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
-  --> $DIR/warn.rs:20:9
+  --> $DIR/warn.rs:21:9
    |
 LL |     let _guard = bar();
    |         ^^^^^^
index 15ee19755bffc504ab84086542be1f91912eb7f3..c4004540467488bc5319d45436bc5153b6750e72 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: --error-format json -Zunstable-options
+// compile-flags: --error-format json
 // run-rustfix
 
 // The output for humans should just highlight the whole span without showing
index d72df21e09ae264c8a253850b77f15b65401bdba..962c8bdd7d78957dcf7c837f8f1685cdbffe8734 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: --error-format json -Zunstable-options
+// compile-flags: --error-format json
 // run-rustfix
 
 // The output for humans should just highlight the whole span without showing
index 498c25d2e1c44ed4a2318ef21f6170e9861a2b0c..169fb824021ed6e4eea48bb74b0ce135a10fdfdf 100644 (file)
@@ -1,4 +1,4 @@
-{"message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":596,"byte_end":597,"line_start":16,"line_end":16,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));
+{"message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":577,"byte_end":578,"line_start":16,"line_end":16,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));
   --> $DIR/unused_parens_json_suggestion.rs:16:14
    |
 LL |     let _a = (1 / (2 + 3));
index 1d891d328dd5ab3123026c7a3c5e4154c9c9066d..8a57cd57385f31238c90f3327b72924dc5852b48 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: --error-format json -Zunstable-options
+// compile-flags: --error-format json
 // run-rustfix
 
 // The output for humans should just highlight the whole span without showing
index 494cd1845063012aa507356732dab1e076c23786..952332d54e9c10f0e94f2a644551502c90b2a37f 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: --error-format json -Zunstable-options
+// compile-flags: --error-format json
 // run-rustfix
 
 // The output for humans should just highlight the whole span without showing
index 08291b10fcc204f284fe3347f193846bc10c1b51..43367aaa9113b67fbe28c01104edb6dbb8953dc9 100644 (file)
@@ -1,4 +1,4 @@
-{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":500,"byte_end":501,"line_start":17,"line_end":17,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":"    if (_b) {
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":481,"byte_end":482,"line_start":17,"line_end":17,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":"    if (_b) {
   --> $DIR/unused_parens_remove_json_suggestion.rs:17:8
    |
 LL |     if (_b) {
@@ -16,7 +16,7 @@ LL +     if _b {
    | 
 
 "}
-{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":631,"byte_end":632,"line_start":28,"line_end":28,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":"    if(c) {
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":612,"byte_end":613,"line_start":28,"line_end":28,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":"    if(c) {
   --> $DIR/unused_parens_remove_json_suggestion.rs:28:7
    |
 LL |     if(c) {
@@ -29,7 +29,7 @@ LL +     if c {
    | 
 
 "}
-{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":711,"byte_end":712,"line_start":32,"line_end":32,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":"    if (c){
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":692,"byte_end":693,"line_start":32,"line_end":32,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":"    if (c){
   --> $DIR/unused_parens_remove_json_suggestion.rs:32:8
    |
 LL |     if (c){
@@ -42,7 +42,7 @@ LL +     if c {
    | 
 
 "}
-{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":794,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":807,"byte_end":808,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":794,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":807,"byte_end":808,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
+{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":774,"byte_end":775,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":788,"byte_end":789,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":774,"byte_end":775,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":788,"byte_end":789,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
   --> $DIR/unused_parens_remove_json_suggestion.rs:36:11
    |
 LL |     while (false && true){
@@ -55,7 +55,7 @@ LL +     while false && true {
    | 
 
 "}
-{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":821,"byte_end":822,"line_start":37,"line_end":37,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":"        if (c) {
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":802,"byte_end":803,"line_start":37,"line_end":37,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":"        if (c) {
   --> $DIR/unused_parens_remove_json_suggestion.rs:37:12
    |
 LL |         if (c) {
@@ -68,7 +68,7 @@ LL +         if c {
    | 
 
 "}
-{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":918,"byte_end":919,"line_start":43,"line_end":43,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":"    while(true && false) {
+{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":899,"byte_end":900,"line_start":43,"line_end":43,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":"    while(true && false) {
   --> $DIR/unused_parens_remove_json_suggestion.rs:43:10
    |
 LL |     while(true && false) {
@@ -81,7 +81,7 @@ LL +     while true && false {
    | 
 
 "}
-{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":987,"byte_end":988,"line_start":44,"line_end":44,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":"        for _ in (0 .. 3){
+{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":968,"byte_end":969,"line_start":44,"line_end":44,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":"        for _ in (0 .. 3){
   --> $DIR/unused_parens_remove_json_suggestion.rs:44:18
    |
 LL |         for _ in (0 .. 3){
@@ -94,7 +94,7 @@ LL +         for _ in 0 .. 3 {
    | 
 
 "}
-{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1088,"byte_end":1089,"line_start":49,"line_end":49,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"    for _ in (0 .. 3) {
+{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1069,"byte_end":1070,"line_start":49,"line_end":49,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":"    for _ in (0 .. 3) {
   --> $DIR/unused_parens_remove_json_suggestion.rs:49:14
    |
 LL |     for _ in (0 .. 3) {
@@ -107,7 +107,7 @@ LL +     for _ in 0 .. 3 {
    | 
 
 "}
-{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1147,"byte_end":1148,"line_start":50,"line_end":50,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":"        while (true && false) {
+{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1128,"byte_end":1129,"line_start":50,"line_end":50,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":"        while (true && false) {
   --> $DIR/unused_parens_remove_json_suggestion.rs:50:15
    |
 LL |         while (true && false) {
index d9a0a9f005432be49f75f161b5e94b6f125eb3eb..330aa6acf3550295a56b83e341b7fe861fc1bee0 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `m` is ambiguous (`macro_rules` vs non-`macro_rules` from other module)
+error[E0659]: `m` is ambiguous
   --> $DIR/ambiguity-legacy-vs-modern.rs:31:9
    |
 LL |         m!()
    |         ^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a `macro_rules` name and a non-`macro_rules` name from another module
 note: `m` could refer to the macro defined here
   --> $DIR/ambiguity-legacy-vs-modern.rs:26:5
    |
@@ -15,12 +16,13 @@ note: `m` could also refer to the macro defined here
 LL |         macro m() { 0 }
    |         ^^^^^^^^^^^^^^^
 
-error[E0659]: `m` is ambiguous (`macro_rules` vs non-`macro_rules` from other module)
+error[E0659]: `m` is ambiguous
   --> $DIR/ambiguity-legacy-vs-modern.rs:43:5
    |
 LL |     m!()
    |     ^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a `macro_rules` name and a non-`macro_rules` name from another module
 note: `m` could refer to the macro defined here
   --> $DIR/ambiguity-legacy-vs-modern.rs:40:9
    |
index 7bbb8eddb7137317917e78845071ad06c6e0e9ba..4a864c2e92718f08d89d93b0ca943ebdb14b8bdb 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `std` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `std` is ambiguous
   --> $DIR/macro-path-prelude-shadowing.rs:29:9
    |
 LL |         std::panic!();
    |         ^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
    = note: `std` could refer to a built-in crate
 note: `std` could also refer to the module imported here
   --> $DIR/macro-path-prelude-shadowing.rs:27:9
index 58224b70734dac193642ad01c833409bf1e74bd6..a052b43ac10e408ca40ab019064aa744642a61e1 100644 (file)
@@ -10,12 +10,13 @@ LL | m1!();
    = note: macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)
    = note: this error originates in the macro `m1` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `foo` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `foo` is ambiguous
   --> $DIR/macro-shadowing.rs:17:1
    |
 LL | foo!();
    | ^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `foo` could refer to the macro defined here
   --> $DIR/macro-shadowing.rs:10:5
    |
diff --git a/src/test/ui/macros/missing-bang-in-decl.fixed b/src/test/ui/macros/missing-bang-in-decl.fixed
new file mode 100644 (file)
index 0000000..b1aa329
--- /dev/null
@@ -0,0 +1,16 @@
+// run-rustfix
+
+#![allow(unused_macros)]
+
+macro_rules! foo {
+    //~^ ERROR expected `!` after `macro_rules`
+    () => {};
+}
+
+macro_rules! bar {
+    //~^ ERROR expected `!` after `macro_rules`
+    //~^^ ERROR macro names aren't followed by a `!`
+    () => {};
+}
+
+fn main() {}
diff --git a/src/test/ui/macros/missing-bang-in-decl.rs b/src/test/ui/macros/missing-bang-in-decl.rs
new file mode 100644 (file)
index 0000000..8393f15
--- /dev/null
@@ -0,0 +1,16 @@
+// run-rustfix
+
+#![allow(unused_macros)]
+
+macro_rules foo {
+    //~^ ERROR expected `!` after `macro_rules`
+    () => {};
+}
+
+macro_rules bar! {
+    //~^ ERROR expected `!` after `macro_rules`
+    //~^^ ERROR macro names aren't followed by a `!`
+    () => {};
+}
+
+fn main() {}
diff --git a/src/test/ui/macros/missing-bang-in-decl.stderr b/src/test/ui/macros/missing-bang-in-decl.stderr
new file mode 100644 (file)
index 0000000..dfabafb
--- /dev/null
@@ -0,0 +1,20 @@
+error: expected `!` after `macro_rules`
+  --> $DIR/missing-bang-in-decl.rs:5:1
+   |
+LL | macro_rules foo {
+   | ^^^^^^^^^^^ help: add a `!`: `macro_rules!`
+
+error: expected `!` after `macro_rules`
+  --> $DIR/missing-bang-in-decl.rs:10:1
+   |
+LL | macro_rules bar! {
+   | ^^^^^^^^^^^ help: add a `!`: `macro_rules!`
+
+error: macro names aren't followed by a `!`
+  --> $DIR/missing-bang-in-decl.rs:10:16
+   |
+LL | macro_rules bar! {
+   |                ^ help: remove the `!`
+
+error: aborting due to 3 previous errors
+
index 6b1191670743382fe3725361d42b29fb5c75ae8c..dedefac5c464c9a842d1454b5f9d60dfe2be3f42 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `bar` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `bar` is ambiguous
   --> $DIR/out-of-order-shadowing.rs:5:1
    |
 LL | bar!();
    | ^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `bar` could refer to the macro defined here
   --> $DIR/out-of-order-shadowing.rs:4:1
    |
index 4912166883260164dd2d54705f4bb6d003b802f1..99b27a5cab123088cdd80a6c4f1ead1bb3d02da0 100644 (file)
@@ -1,4 +1,4 @@
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/restricted-shadowing-legacy.rs:101:13
    |
 LL |             m!();
@@ -7,6 +7,7 @@ LL |             m!();
 LL | include!();
    | ---------- in this macro invocation
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro defined here
   --> $DIR/restricted-shadowing-legacy.rs:88:9
    |
@@ -25,7 +26,7 @@ LL | include!();
    | ---------- in this macro invocation
    = note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/restricted-shadowing-legacy.rs:139:42
    |
 LL |         macro_rules! gen_invoc { () => { m!() } }
@@ -34,6 +35,7 @@ LL |         macro_rules! gen_invoc { () => { m!() } }
 LL | include!();
    | ---------- in this macro invocation
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro defined here
   --> $DIR/restricted-shadowing-legacy.rs:88:9
    |
@@ -52,7 +54,7 @@ LL | include!();
    | ---------- in this macro invocation
    = note: this error originates in the macro `gen_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/restricted-shadowing-legacy.rs:148:9
    |
 LL |         m!();
@@ -61,6 +63,7 @@ LL |         m!();
 LL | include!();
    | ---------- in this macro invocation
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro defined here
   --> $DIR/restricted-shadowing-legacy.rs:88:9
    |
@@ -79,7 +82,7 @@ LL | include!();
    | ---------- in this macro invocation
    = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/restricted-shadowing-legacy.rs:164:9
    |
 LL |         m!();
@@ -88,6 +91,7 @@ LL |         m!();
 LL | include!();
    | ---------- in this macro invocation
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro defined here
   --> $DIR/restricted-shadowing-legacy.rs:88:9
    |
@@ -106,7 +110,7 @@ LL | include!();
    | ---------- in this macro invocation
    = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/restricted-shadowing-legacy.rs:180:13
    |
 LL |             m!();
@@ -115,6 +119,7 @@ LL |             m!();
 LL | include!();
    | ---------- in this macro invocation
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro defined here
   --> $DIR/restricted-shadowing-legacy.rs:88:9
    |
@@ -133,7 +138,7 @@ LL | include!();
    | ---------- in this macro invocation
    = note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/restricted-shadowing-legacy.rs:218:42
    |
 LL |         macro_rules! gen_invoc { () => { m!() } }
@@ -142,6 +147,7 @@ LL |         macro_rules! gen_invoc { () => { m!() } }
 LL | include!();
    | ---------- in this macro invocation
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro defined here
   --> $DIR/restricted-shadowing-legacy.rs:88:9
    |
@@ -160,7 +166,7 @@ LL | include!();
    | ---------- in this macro invocation
    = note: this error originates in the macro `gen_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/restricted-shadowing-legacy.rs:232:9
    |
 LL |         m!();
@@ -169,6 +175,7 @@ LL |         m!();
 LL | include!();
    | ---------- in this macro invocation
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro defined here
   --> $DIR/restricted-shadowing-legacy.rs:88:9
    |
@@ -187,7 +194,7 @@ LL | include!();
    | ---------- in this macro invocation
    = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/restricted-shadowing-legacy.rs:262:42
    |
 LL |         macro_rules! gen_invoc { () => { m!() } }
@@ -196,6 +203,7 @@ LL |         macro_rules! gen_invoc { () => { m!() } }
 LL | include!();
    | ---------- in this macro invocation
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro defined here
   --> $DIR/restricted-shadowing-legacy.rs:88:9
    |
index 62639eeb1192a9a256babd3f71241d3551ae1c5e..b169e63132e450eafef64bc0ba7e3c60c69a7909 100644 (file)
@@ -1,4 +1,4 @@
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/restricted-shadowing-modern.rs:104:17
    |
 LL |                 m!();
@@ -7,6 +7,7 @@ LL |                 m!();
 LL | include!();
    | ---------- in this macro invocation
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro defined here
   --> $DIR/restricted-shadowing-modern.rs:91:9
    |
@@ -25,7 +26,7 @@ LL | include!();
    | ---------- in this macro invocation
    = note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/restricted-shadowing-modern.rs:147:33
    |
 LL |             macro gen_invoc() { m!() }
@@ -34,6 +35,7 @@ LL |             macro gen_invoc() { m!() }
 LL | include!();
    | ---------- in this macro invocation
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro defined here
   --> $DIR/restricted-shadowing-modern.rs:91:9
    |
@@ -52,7 +54,7 @@ LL | include!();
    | ---------- in this macro invocation
    = note: this error originates in the macro `gen_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/restricted-shadowing-modern.rs:156:13
    |
 LL |             m!();
@@ -61,6 +63,7 @@ LL |             m!();
 LL | include!();
    | ---------- in this macro invocation
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro defined here
   --> $DIR/restricted-shadowing-modern.rs:91:9
    |
@@ -79,7 +82,7 @@ LL | include!();
    | ---------- in this macro invocation
    = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/restricted-shadowing-modern.rs:172:13
    |
 LL |             m!();
@@ -88,6 +91,7 @@ LL |             m!();
 LL | include!();
    | ---------- in this macro invocation
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro defined here
   --> $DIR/restricted-shadowing-modern.rs:91:9
    |
@@ -106,7 +110,7 @@ LL | include!();
    | ---------- in this macro invocation
    = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/restricted-shadowing-modern.rs:190:17
    |
 LL |                 m!();
@@ -115,6 +119,7 @@ LL |                 m!();
 LL | include!();
    | ---------- in this macro invocation
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro defined here
   --> $DIR/restricted-shadowing-modern.rs:91:9
    |
@@ -133,7 +138,7 @@ LL | include!();
    | ---------- in this macro invocation
    = note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
   --> $DIR/restricted-shadowing-modern.rs:233:33
    |
 LL |             macro gen_invoc() { m!() }
@@ -142,6 +147,7 @@ LL |             macro gen_invoc() { m!() }
 LL | include!();
    | ---------- in this macro invocation
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `m` could refer to the macro defined here
   --> $DIR/restricted-shadowing-modern.rs:91:9
    |
index e4a94d56f12b02bc1454d3d45123ba5021e4f74b..c1cc6cdaf53fa3b4106d0886751de0480102f3d8 100644 (file)
@@ -4,7 +4,13 @@ error[E0283]: type annotations needed
 LL | impl<'a> A for (&'static (), &'a ()) {}
    |          ^ cannot infer type for tuple `(&'static (), &'a ())`
    |
-   = note: cannot satisfy `(&'static (), &'a ()): A`
+note: multiple `impl`s satisfying `(&'static (), &'a ()): A` found
+  --> $DIR/region-overlap.rs:5:1
+   |
+LL | impl<'a> A for (&'static (), &'a ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<'a> A for (&'a (), &'static ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `A`
   --> $DIR/region-overlap.rs:4:1
    |
@@ -17,7 +23,13 @@ error[E0283]: type annotations needed
 LL | impl<'a> A for (&'a (), &'static ()) {}
    |          ^ cannot infer type for tuple `(&'a (), &'static ())`
    |
-   = note: cannot satisfy `(&'a (), &'static ()): A`
+note: multiple `impl`s satisfying `(&'a (), &'static ()): A` found
+  --> $DIR/region-overlap.rs:5:1
+   |
+LL | impl<'a> A for (&'static (), &'a ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<'a> A for (&'a (), &'static ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `A`
   --> $DIR/region-overlap.rs:4:1
    |
index f5497c1d16de61257a39b1df56029f20477a283d..9143a8cdd59bc915e1daff145d699adcb6fa5cd6 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 // edition:2021
-// compile-flags: -Zunstable-options
 
 // regression test for https://github.com/rust-lang/rust/pull/85678
 
index 49fe7d1324ca8ea9433fc95caacc767d953dd82d..7b2fc34e1af12637ec8d6e77255d58f4119eb9dc 100644 (file)
@@ -23,7 +23,7 @@ fn m1() {
     // we couldn't infer the type of the vector just based on calling foo()...
     let mut x = Vec::new();
     //~^ ERROR type annotations needed
-    x.foo();
+    x.foo(); //~ ERROR type annotations needed
 }
 
 fn m2() {
index 4b494c961158a32de6db7a2d45d25c5509c3916b..f33672433dee41c028d158f99d364d79c5d37ca3 100644 (file)
@@ -6,6 +6,21 @@ LL |     let mut x = Vec::new();
    |         |
    |         consider giving `x` the explicit type `Vec<T>`, where the type parameter `T` is specified
 
+error[E0283]: type annotations needed
+  --> $DIR/method-ambig-one-trait-unknown-int-type.rs:26:7
+   |
+LL |     x.foo();
+   |       ^^^ cannot infer type for struct `Vec<_>`
+   |
+note: multiple `impl`s satisfying `Vec<_>: Foo` found
+  --> $DIR/method-ambig-one-trait-unknown-int-type.rs:9:1
+   |
+LL | impl Foo for Vec<usize> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Foo for Vec<isize> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0308]: mismatched types
   --> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20
    |
@@ -19,7 +34,7 @@ help: you can convert an `isize` to a `usize` and panic if the converted value d
 LL |     let y: usize = x.foo().try_into().unwrap();
    |                           ++++++++++++++++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0282, E0308.
+Some errors have detailed explanations: E0282, E0283, E0308.
 For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/mir-dataflow/indirect-mutation-offset.rs b/src/test/ui/mir-dataflow/indirect-mutation-offset.rs
deleted file mode 100644 (file)
index 374a9f7..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-// compile-flags: -Zunleash-the-miri-inside-of-you
-
-// This test demonstrates a shortcoming of the `MaybeMutBorrowedLocals` analysis. It does not
-// handle code that takes a reference to one field of a struct, then use pointer arithmetic to
-// transform it to another field of that same struct that may have interior mutability. For now,
-// this is UB, but this may change in the future. See [rust-lang/unsafe-code-guidelines#134].
-//
-// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
-
-#![feature(core_intrinsics, rustc_attrs, const_raw_ptr_deref)]
-
-use std::cell::UnsafeCell;
-use std::intrinsics::rustc_peek;
-
-#[repr(C)]
-struct PartialInteriorMut {
-    zst: [i32; 0],
-    cell: UnsafeCell<i32>,
-}
-
-#[rustc_mir(rustc_peek_indirectly_mutable,stop_after_dataflow)]
-const BOO: i32 = {
-    let x = PartialInteriorMut {
-        zst: [],
-        cell: UnsafeCell::new(0),
-    };
-
-    let p_zst: *const _ = &x.zst ; // Doesn't cause `x` to get marked as indirectly mutable.
-
-    let rmut_cell = unsafe {
-        // Take advantage of the fact that `zst` and `cell` are at the same location in memory.
-        // This trick would work with any size type if miri implemented `ptr::offset`.
-        let p_cell = p_zst as *const UnsafeCell<i32>;
-
-        let pmut_cell = (*p_cell).get();
-        &mut *pmut_cell
-    };
-
-    *rmut_cell = 42;  // Mutates `x` indirectly even though `x` is not marked indirectly mutable!!!
-    let val = *rmut_cell;
-    rustc_peek(x); //~ ERROR rustc_peek: bit not set
-
-    val
-};
-
-fn main() {
-    println!("{}", BOO);
-}
diff --git a/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr b/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr
deleted file mode 100644 (file)
index 1d5287c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-error: rustc_peek: bit not set
-  --> $DIR/indirect-mutation-offset.rs:41:5
-   |
-LL |     rustc_peek(x);
-   |     ^^^^^^^^^^^^^
-
-error: stop_after_dataflow ended compilation
-
-error: aborting due to 2 previous errors
-
index 9867addaf38e7ac23d1e62507b107481078be061..2a2c23c94212f17f434c0e287e70c28ee2f845f2 100644 (file)
@@ -2,13 +2,13 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/issue-75361-mismatched-impl.rs:18:3
    |
 LL |   fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType>>;
-   |   --------------------------------------------------------------------- expected `fn(&T) -> Box<(dyn MyTrait<Item = &T> + 'static)>`
+   |   --------------------------------------------------------------------- expected `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + 'static)>`
 ...
 LL |   fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType> + '_> {
-   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&T) -> Box<dyn MyTrait<Item = &T>>`
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + '1)>`
    |
-   = note: expected `fn(&T) -> Box<(dyn MyTrait<Item = &T> + 'static)>`
-              found `fn(&T) -> Box<dyn MyTrait<Item = &T>>`
+   = note: expected `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + 'static)>`
+              found `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + '1)>`
 help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
   --> $DIR/issue-75361-mismatched-impl.rs:12:55
    |
index 8ec478cd63fa1264db5eb40e35920258f4ea846e..9e1f4e1fe4ea9b12496a64fc6193d2769bf10e55 100644 (file)
@@ -1,8 +1,10 @@
 error[E0277]: `NoSync` cannot be shared between threads safely
-  --> $DIR/mutable-enum-indirect.rs:17:5
+  --> $DIR/mutable-enum-indirect.rs:17:9
    |
 LL |     bar(&x);
-   |     ^^^ `NoSync` cannot be shared between threads safely
+   |     --- ^^ `NoSync` cannot be shared between threads safely
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: within `&Foo`, the trait `Sync` is not implemented for `NoSync`
 note: required because it appears within the type `Foo`
index a5455a3f9eb7b1bf7e3628f53b40c4145d8e9bac..e29ba09b3694dbabcc901566b2d72813a67f55c0 100644 (file)
@@ -6,7 +6,8 @@
 struct Foo<'a>(&'a [u8]);
 
 impl<'a> Foo<'a> {
-    fn make_it(&self) -> impl Iterator<Item = u8> { //~ ERROR lifetime may not live
+    fn make_it(&self) -> impl Iterator<Item = u8> {
+        //~^ ERROR: captures lifetime that does not appear in bounds
         self.0.iter().copied()
     }
 }
index 60b1552701af91eb75e2ba87db04791fa23e54ae..6c7cd0c8254938c8b1f49c5abe5dd03cca59eb1c 100644 (file)
@@ -1,10 +1,11 @@
-error: lifetime may not live long enough
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
   --> $DIR/issue-73159-rpit-static.rs:9:26
    |
 LL | impl<'a> Foo<'a> {
-   |      -- lifetime `'a` defined here
+   |      -- hidden type `Copied<std::slice::Iter<'a, u8>>` captures the lifetime `'a` as defined here
 LL |     fn make_it(&self) -> impl Iterator<Item = u8> {
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0700`.
diff --git a/src/test/ui/nll/issue-78561.rs b/src/test/ui/nll/issue-78561.rs
new file mode 100644 (file)
index 0000000..55147fc
--- /dev/null
@@ -0,0 +1,23 @@
+// check-pass
+#![feature(type_alias_impl_trait)]
+
+pub trait Trait {
+    type A;
+
+    fn f() -> Self::A;
+}
+
+pub trait Tr2<'a, 'b> {}
+
+pub struct A<T>(T);
+pub trait Tr {
+    type B;
+}
+
+impl<'a, 'b, T: Tr<B = dyn Tr2<'a, 'b>>> Trait for A<T> {
+    type A = impl core::fmt::Debug;
+
+    fn f() -> Self::A {}
+}
+
+fn main() {}
index bcdf643c0b9d1136001d98643105630f55fe0231..8af23aad7261b80a3bdba5c104be56bcb8abb76f 100644 (file)
@@ -8,7 +8,7 @@ trait Foo<'a> {
 impl<'a, T> Foo<'a> for T { }
 
 fn foo<'a, T>(x: &T) -> impl Foo<'a> {
-//~^ ERROR explicit lifetime required in the type of `x` [E0621]
+//~^ ERROR captures lifetime that does not appear in bounds
     x
 }
 
index d05fc793967ae22912d3825bad331f396a52973c..21d1eea54e6c517dcb41a16ca1d51d80b50b9832 100644 (file)
@@ -1,14 +1,16 @@
-error[E0621]: explicit lifetime required in the type of `x`
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
   --> $DIR/impl-trait-captures.rs:10:25
    |
 LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
-   |                         ^^^^^^^^^^^^ lifetime `ReEarlyBound(0, 'a)` required
+   |                  --     ^^^^^^^^^^^^
+   |                  |
+   |                  hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[e9f4]::foo), BrAnon(0)) T` captures the anonymous lifetime defined here
    |
-help: add explicit lifetime `ReEarlyBound(0, 'a)` to the type of `x`
+help: to declare that the `impl Trait` captures ReFree(DefId(0:8 ~ impl_trait_captures[e9f4]::foo), BrAnon(0)), you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[e9f4]::foo), BrAnon(0))` lifetime bound
    |
-LL | fn foo<'a, T>(x: &ReEarlyBound(0, 'a) T) -> impl Foo<'a> {
-   |                  ~~~~~~~~~~~~~~~~~~~~~~
+LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[e9f4]::foo), BrAnon(0)) {
+   |                                      ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0621`.
+For more information about this error, try `rustc --explain E0700`.
index 814f3473828e3bd406ee2af575b7735b31c8dafa..b5a14b551dc2d799b7200c39cbf6408000b45678 100644 (file)
@@ -1,8 +1,10 @@
 error[E0277]: `NoSend` cannot be sent between threads safely
-  --> $DIR/no_send-enum.rs:16:5
+  --> $DIR/no_send-enum.rs:16:9
    |
 LL |     bar(x);
-   |     ^^^ `NoSend` cannot be sent between threads safely
+   |     --- ^ `NoSend` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: within `Foo`, the trait `Send` is not implemented for `NoSend`
 note: required because it appears within the type `Foo`
index ad837863be9ed428659cb133594e770251508d5a..5b453e0da3bbdff1452cb73cbc7b29cd24bbf3af 100644 (file)
@@ -1,8 +1,10 @@
 error[E0277]: `NoSync` cannot be shared between threads safely
-  --> $DIR/no_share-enum.rs:14:5
+  --> $DIR/no_share-enum.rs:14:9
    |
 LL |     bar(x);
-   |     ^^^ `NoSync` cannot be shared between threads safely
+   |     --- ^ `NoSync` cannot be shared between threads safely
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: within `Foo`, the trait `Sync` is not implemented for `NoSync`
 note: required because it appears within the type `Foo`
index ac0cf0f1f08fa785e79f8a2fd96c1184f3dab773..a8d3c8680faae46907328f7e684eb1dc500e3d6b 100644 (file)
@@ -6,10 +6,10 @@ LL | #[rustc_on_unimplemented]
    |
 help: the following are the possible correct uses
    |
-LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")]
-   |
 LL | #[rustc_on_unimplemented = "message"]
    |
+LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")]
+   |
 
 error[E0230]: there is no parameter `C` on trait `BadAnnotation2`
   --> $DIR/bad-annotation.rs:22:1
diff --git a/src/test/ui/panics/location-detail-panic-no-column.rs b/src/test/ui/panics/location-detail-panic-no-column.rs
new file mode 100644 (file)
index 0000000..673e638
--- /dev/null
@@ -0,0 +1,7 @@
+// run-fail
+// check-run-results
+// compile-flags: -Zlocation-detail=line,file
+
+fn main() {
+    panic!("column-redacted");
+}
diff --git a/src/test/ui/panics/location-detail-panic-no-column.run.stderr b/src/test/ui/panics/location-detail-panic-no-column.run.stderr
new file mode 100644 (file)
index 0000000..9f35623
--- /dev/null
@@ -0,0 +1,2 @@
+thread 'main' panicked at 'column-redacted', $DIR/location-detail-panic-no-column.rs:6:0
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/test/ui/panics/location-detail-panic-no-file.rs b/src/test/ui/panics/location-detail-panic-no-file.rs
new file mode 100644 (file)
index 0000000..0e5d52c
--- /dev/null
@@ -0,0 +1,7 @@
+// run-fail
+// check-run-results
+// compile-flags: -Zlocation-detail=line,column
+
+fn main() {
+    panic!("file-redacted");
+}
diff --git a/src/test/ui/panics/location-detail-panic-no-file.run.stderr b/src/test/ui/panics/location-detail-panic-no-file.run.stderr
new file mode 100644 (file)
index 0000000..1e07e3a
--- /dev/null
@@ -0,0 +1,2 @@
+thread 'main' panicked at 'file-redacted', <redacted>:6:5
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/test/ui/panics/location-detail-panic-no-line.rs b/src/test/ui/panics/location-detail-panic-no-line.rs
new file mode 100644 (file)
index 0000000..57f6d0e
--- /dev/null
@@ -0,0 +1,7 @@
+// run-fail
+// check-run-results
+// compile-flags: -Zlocation-detail=file,column
+
+fn main() {
+    panic!("line-redacted");
+}
diff --git a/src/test/ui/panics/location-detail-panic-no-line.run.stderr b/src/test/ui/panics/location-detail-panic-no-line.run.stderr
new file mode 100644 (file)
index 0000000..cc3f162
--- /dev/null
@@ -0,0 +1,2 @@
+thread 'main' panicked at 'line-redacted', $DIR/location-detail-panic-no-line.rs:0:5
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/test/ui/panics/location-detail-unwrap-no-file.rs b/src/test/ui/panics/location-detail-unwrap-no-file.rs
new file mode 100644 (file)
index 0000000..d7f96f0
--- /dev/null
@@ -0,0 +1,8 @@
+// run-fail
+// check-run-results
+// compile-flags: -Zlocation-detail=line,column
+
+fn main() {
+    let opt: Option<u32> = None;
+    opt.unwrap();
+}
diff --git a/src/test/ui/panics/location-detail-unwrap-no-file.run.stderr b/src/test/ui/panics/location-detail-unwrap-no-file.run.stderr
new file mode 100644 (file)
index 0000000..f8f84b5
--- /dev/null
@@ -0,0 +1,2 @@
+thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', <redacted>:7:9
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/test/ui/parser/auxiliary/issue-89971-outer-attr-following-inner-attr-ice.rs b/src/test/ui/parser/auxiliary/issue-89971-outer-attr-following-inner-attr-ice.rs
new file mode 100644 (file)
index 0000000..e5604b8
--- /dev/null
@@ -0,0 +1,13 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(ICE)]
+pub fn derive(_: TokenStream) -> TokenStream {
+    r#"#[allow(missing_docs)] struct X { }"#.parse().unwrap()
+}
diff --git a/src/test/ui/parser/issue-89971-outer-attr-following-inner-attr-ice.rs b/src/test/ui/parser/issue-89971-outer-attr-following-inner-attr-ice.rs
new file mode 100644 (file)
index 0000000..fe67d98
--- /dev/null
@@ -0,0 +1,15 @@
+// aux-build:issue-89971-outer-attr-following-inner-attr-ice.rs
+
+#[macro_use]
+extern crate issue_89971_outer_attr_following_inner_attr_ice;
+
+fn main() {
+    Mew();
+    X {};
+}
+
+#![deny(missing_docs)]
+//~^ ERROR an inner attribute is not permitted in this context
+#[derive(ICE)]
+#[deny(missing_docs)]
+struct Mew();
diff --git a/src/test/ui/parser/issue-89971-outer-attr-following-inner-attr-ice.stderr b/src/test/ui/parser/issue-89971-outer-attr-following-inner-attr-ice.stderr
new file mode 100644 (file)
index 0000000..34a6ab0
--- /dev/null
@@ -0,0 +1,18 @@
+error: an inner attribute is not permitted in this context
+  --> $DIR/issue-89971-outer-attr-following-inner-attr-ice.rs:11:1
+   |
+LL | #![deny(missing_docs)]
+   | ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | struct Mew();
+   | ------------- the inner attribute doesn't annotate this struct
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
+help: to annotate the struct, change the attribute from inner to outer style
+   |
+LL - #![deny(missing_docs)]
+LL + #[deny(missing_docs)]
+   | 
+
+error: aborting due to previous error
+
index 8080dbc332ae7146d13648157bc3e64fde3f2f77..053b428bd12cc60131c00550f275c3a20d22681b 100644 (file)
@@ -9,7 +9,7 @@ fn main() {
 
     for ( elem in vec ) {
         //~^ ERROR expected one of `)`, `,`, `@`, or `|`, found keyword `in`
-        //~| ERROR unexpected parenthesis surrounding `for` loop head
+        //~| ERROR unexpected parentheses surrounding `for` loop head
         const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
     }
 }
index 21991348327b36e99d5f4c67b9aa5e2057b91a91..fa55970dbd129096fff13178bce7d1225027e42f 100644 (file)
@@ -4,13 +4,13 @@ error: expected one of `)`, `,`, `@`, or `|`, found keyword `in`
 LL |     for ( elem in vec ) {
    |                ^^ expected one of `)`, `,`, `@`, or `|`
 
-error: unexpected parenthesis surrounding `for` loop head
+error: unexpected parentheses surrounding `for` loop head
   --> $DIR/recover-for-loop-parens-around-head.rs:10:9
    |
 LL |     for ( elem in vec ) {
    |         ^             ^
    |
-help: remove parenthesis in `for` loop
+help: remove parentheses in `for` loop
    |
 LL -     for ( elem in vec ) {
 LL +     for  elem in vec  {
diff --git a/src/test/ui/parser/unicode-control-codepoints.rs b/src/test/ui/parser/unicode-control-codepoints.rs
new file mode 100644 (file)
index 0000000..5af0b58
--- /dev/null
@@ -0,0 +1,39 @@
+fn main() {
+    // if access_level != "us‫e‪r" { // Check if admin
+    //~^ ERROR unicode codepoint changing visible direction of text present in comment
+    println!("us\u{202B}e\u{202A}r");
+    println!("{:?}", r#"us\u{202B}e\u{202A}r"#);
+    println!("{:?}", b"us\u{202B}e\u{202A}r");
+    //~^ ERROR unicode escape in byte string
+    //~| ERROR unicode escape in byte string
+    println!("{:?}", br##"us\u{202B}e\u{202A}r"##);
+
+    println!("{:?}", "/*‮ } ⁦if isAdmin⁩ ⁦ begin admins only ");
+    //~^ ERROR unicode codepoint changing visible direction of text present in literal
+
+    println!("{:?}", r##"/*‮ } ⁦if isAdmin⁩ ⁦ begin admins only "##);
+    //~^ ERROR unicode codepoint changing visible direction of text present in literal
+    println!("{:?}", b"/*‮ } ⁦if isAdmin⁩ ⁦ begin admins only ");
+    //~^ ERROR non-ASCII character in byte constant
+    //~| ERROR non-ASCII character in byte constant
+    //~| ERROR non-ASCII character in byte constant
+    //~| ERROR non-ASCII character in byte constant
+    println!("{:?}", br##"/*‮ } ⁦if isAdmin⁩ ⁦ begin admins only "##);
+    //~^ ERROR raw byte string must be ASCII
+    //~| ERROR raw byte string must be ASCII
+    //~| ERROR raw byte string must be ASCII
+    //~| ERROR raw byte string must be ASCII
+    println!("{:?}", '‮');
+    //~^ ERROR unicode codepoint changing visible direction of text present in literal
+}
+
+//"/*‮ } ⁦if isAdmin⁩ ⁦ begin admins only */"
+//~^ ERROR unicode codepoint changing visible direction of text present in comment
+
+/**  '‮'); */fn foo() {}
+//~^ ERROR unicode codepoint changing visible direction of text present in doc comment
+
+/**
+ *
+ *  '‮'); */fn bar() {}
+//~^^^ ERROR unicode codepoint changing visible direction of text present in doc comment
diff --git a/src/test/ui/parser/unicode-control-codepoints.stderr b/src/test/ui/parser/unicode-control-codepoints.stderr
new file mode 100644 (file)
index 0000000..71509fe
--- /dev/null
@@ -0,0 +1,192 @@
+error: unicode escape in byte string
+  --> $DIR/unicode-control-codepoints.rs:6:26
+   |
+LL |     println!("{:?}", b"us\u{202B}e\u{202A}r");
+   |                          ^^^^^^^^ unicode escape in byte string
+   |
+   = help: unicode escape sequences cannot be used as a byte or in a byte string
+
+error: unicode escape in byte string
+  --> $DIR/unicode-control-codepoints.rs:6:35
+   |
+LL |     println!("{:?}", b"us\u{202B}e\u{202A}r");
+   |                                   ^^^^^^^^ unicode escape in byte string
+   |
+   = help: unicode escape sequences cannot be used as a byte or in a byte string
+
+error: non-ASCII character in byte constant
+  --> $DIR/unicode-control-codepoints.rs:16:26
+   |
+LL |     println!("{:?}", b"/* } if isAdmin  begin admins only ");
+   |                          ^ byte constant must be ASCII but is '\u{202e}'
+   |
+help: if you meant to use the UTF-8 encoding of '\u{202e}', use \xHH escapes
+   |
+LL |     println!("{:?}", b"/*\xE2\x80\xAE } if isAdmin  begin admins only ");
+   |                          ~~~~~~~~~~~~
+
+error: non-ASCII character in byte constant
+  --> $DIR/unicode-control-codepoints.rs:16:30
+   |
+LL |     println!("{:?}", b"/* } if isAdmin  begin admins only ");
+   |                             ^ byte constant must be ASCII but is '\u{2066}'
+   |
+help: if you meant to use the UTF-8 encoding of '\u{2066}', use \xHH escapes
+   |
+LL |     println!("{:?}", b"/* } \xE2\x81\xA6if isAdmin  begin admins only ");
+   |                             ~~~~~~~~~~~~
+
+error: non-ASCII character in byte constant
+  --> $DIR/unicode-control-codepoints.rs:16:41
+   |
+LL |     println!("{:?}", b"/* } if isAdmin  begin admins only ");
+   |                                       ^ byte constant must be ASCII but is '\u{2069}'
+   |
+help: if you meant to use the UTF-8 encoding of '\u{2069}', use \xHH escapes
+   |
+LL |     println!("{:?}", b"/* } if isAdmin\xE2\x81\xA9  begin admins only ");
+   |                                       ~~~~~~~~~~~~
+
+error: non-ASCII character in byte constant
+  --> $DIR/unicode-control-codepoints.rs:16:43
+   |
+LL |     println!("{:?}", b"/* } if isAdmin  begin admins only ");
+   |                                        ^ byte constant must be ASCII but is '\u{2066}'
+   |
+help: if you meant to use the UTF-8 encoding of '\u{2066}', use \xHH escapes
+   |
+LL |     println!("{:?}", b"/* } if isAdmin \xE2\x81\xA6 begin admins only ");
+   |                                        ~~~~~~~~~~~~
+
+error: raw byte string must be ASCII
+  --> $DIR/unicode-control-codepoints.rs:21:29
+   |
+LL |     println!("{:?}", br##"/* } if isAdmin  begin admins only "##);
+   |                             ^ must be ASCII but is '\u{202e}'
+
+error: raw byte string must be ASCII
+  --> $DIR/unicode-control-codepoints.rs:21:33
+   |
+LL |     println!("{:?}", br##"/* } if isAdmin  begin admins only "##);
+   |                                ^ must be ASCII but is '\u{2066}'
+
+error: raw byte string must be ASCII
+  --> $DIR/unicode-control-codepoints.rs:21:44
+   |
+LL |     println!("{:?}", br##"/* } if isAdmin  begin admins only "##);
+   |                                          ^ must be ASCII but is '\u{2069}'
+
+error: raw byte string must be ASCII
+  --> $DIR/unicode-control-codepoints.rs:21:46
+   |
+LL |     println!("{:?}", br##"/* } if isAdmin  begin admins only "##);
+   |                                           ^ must be ASCII but is '\u{2066}'
+
+error: unicode codepoint changing visible direction of text present in comment
+  --> $DIR/unicode-control-codepoints.rs:2:5
+   |
+LL |     // if access_level != "user" { // Check if admin
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^
+   |     |                        ||
+   |     |                        |'\u{202a}'
+   |     |                        '\u{202b}'
+   |     this comment contains invisible unicode text flow control codepoints
+   |
+   = note: `#[deny(text_direction_codepoint_in_comment)]` on by default
+   = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+   = help: if their presence wasn't intentional, you can remove them
+
+error: unicode codepoint changing visible direction of text present in comment
+  --> $DIR/unicode-control-codepoints.rs:30:1
+   |
+LL | //"/* } if isAdmin  begin admins only */"
+   | ^^^^^-^^-^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^
+   | |    |  |         ||
+   | |    |  |         |'\u{2066}'
+   | |    |  |         '\u{2069}'
+   | |    |  '\u{2066}'
+   | |    '\u{202e}'
+   | this comment contains invisible unicode text flow control codepoints
+   |
+   = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+   = help: if their presence wasn't intentional, you can remove them
+
+error: unicode codepoint changing visible direction of text present in literal
+  --> $DIR/unicode-control-codepoints.rs:11:22
+   |
+LL |     println!("{:?}", "/* } if isAdmin  begin admins only ");
+   |                      ^^^-^^-^^^^^^^^^--^^^^^^^^^^^^^^^^^^^
+   |                      |  |  |         ||
+   |                      |  |  |         |'\u{2066}'
+   |                      |  |  |         '\u{2069}'
+   |                      |  |  '\u{2066}'
+   |                      |  '\u{202e}'
+   |                      this literal contains invisible unicode text flow control codepoints
+   |
+   = note: `#[deny(text_direction_codepoint_in_literal)]` on by default
+   = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+   = help: if their presence wasn't intentional, you can remove them
+help: if you want to keep them but make them visible in your source code, you can escape them
+   |
+LL |     println!("{:?}", "/*\u{202e} } \u{2066}if isAdmin\u{2069} \u{2066} begin admins only ");
+   |                         ~~~~~~~~   ~~~~~~~~          ~~~~~~~~ ~~~~~~~~
+
+error: unicode codepoint changing visible direction of text present in literal
+  --> $DIR/unicode-control-codepoints.rs:14:22
+   |
+LL |     println!("{:?}", r##"/* } if isAdmin  begin admins only "##);
+   |                      ^^^^^^-^^-^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^
+   |                      |     |  |         ||
+   |                      |     |  |         |'\u{2066}'
+   |                      |     |  |         '\u{2069}'
+   |                      |     |  '\u{2066}'
+   |                      |     '\u{202e}'
+   |                      this literal contains invisible unicode text flow control codepoints
+   |
+   = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+   = help: if their presence wasn't intentional, you can remove them
+help: if you want to keep them but make them visible in your source code, you can escape them
+   |
+LL |     println!("{:?}", r##"/*\u{202e} } \u{2066}if isAdmin\u{2069} \u{2066} begin admins only "##);
+   |                            ~~~~~~~~   ~~~~~~~~          ~~~~~~~~ ~~~~~~~~
+
+error: unicode codepoint changing visible direction of text present in literal
+  --> $DIR/unicode-control-codepoints.rs:26:22
+   |
+LL |     println!("{:?}", '');
+   |                      ^-
+   |                      ||
+   |                      |'\u{202e}'
+   |                      this literal contains an invisible unicode text flow control codepoint
+   |
+   = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+   = help: if their presence wasn't intentional, you can remove them
+help: if you want to keep them but make them visible in your source code, you can escape them
+   |
+LL |     println!("{:?}", '\u{202e}');
+   |                       ~~~~~~~~
+
+error: unicode codepoint changing visible direction of text present in doc comment
+  --> $DIR/unicode-control-codepoints.rs:33:1
+   |
+LL | /**  ''); */fn foo() {}
+   | ^^^^^^^^^^^^ this doc comment contains an invisible unicode text flow control codepoint
+   |
+   = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+   = note: if their presence wasn't intentional, you can remove them
+   = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}'
+
+error: unicode codepoint changing visible direction of text present in doc comment
+  --> $DIR/unicode-control-codepoints.rs:36:1
+   |
+LL | / /**
+LL | |  *
+LL | |  *  ''); */fn bar() {}
+   | |___________^ this doc comment contains an invisible unicode text flow control codepoint
+   |
+   = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+   = note: if their presence wasn't intentional, you can remove them
+   = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}'
+
+error: aborting due to 17 previous errors
+
index a3023ee906de83496c756d1d7dfe4191fb3c3f84..ae28c1403753a05e6f0edc1fbbe358042350becc 100644 (file)
@@ -5,7 +5,7 @@
 // the tuple struct pattern, has 0 fields, but requires 1 field.
 //
 // In emitting E0023, we try to see if this is a case of e.g., `Some(a, b, c)` but where
-// the scrutinee was of type `Some((a, b, c))`, and suggest that parenthesis be added.
+// the scrutinee was of type `Some((a, b, c))`, and suggest that parentheses be added.
 //
 // However, we did not account for the expected type being different than the tuple pattern type.
 // This caused an issue when the tuple pattern type (`P<T>`) was generic.
diff --git a/src/test/ui/pattern/non-structural-match-types.rs b/src/test/ui/pattern/non-structural-match-types.rs
new file mode 100644 (file)
index 0000000..713418f
--- /dev/null
@@ -0,0 +1,14 @@
+// edition:2021
+#![allow(incomplete_features)]
+#![allow(unreachable_code)]
+#![feature(const_async_blocks)]
+#![feature(inline_const)]
+
+fn main() {
+    match loop {} {
+        const { || {} } => {}, //~ ERROR cannot be used in patterns
+    }
+    match loop {} {
+        const { async {} } => {}, //~ ERROR cannot be used in patterns
+    }
+}
diff --git a/src/test/ui/pattern/non-structural-match-types.stderr b/src/test/ui/pattern/non-structural-match-types.stderr
new file mode 100644 (file)
index 0000000..91fed81
--- /dev/null
@@ -0,0 +1,14 @@
+error: `[closure@$DIR/non-structural-match-types.rs:9:17: 9:22]` cannot be used in patterns
+  --> $DIR/non-structural-match-types.rs:9:9
+   |
+LL |         const { || {} } => {},
+   |         ^^^^^^^^^^^^^^^
+
+error: `impl Future` cannot be used in patterns
+  --> $DIR/non-structural-match-types.rs:12:9
+   |
+LL |         const { async {} } => {},
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
index 97f1ef2c90ae070a75dff1df10d397e939148d88..dea1e21e77fe359e30662c39c9291d4ed53cc4e0 100644 (file)
@@ -12,6 +12,7 @@ fn bar<I>() {
 
 #[rustc_polymorphize_error]
 fn foo<I, T>(_: I)
+//~^ ERROR item has unused generic parameters
 where
     I: Iterator<Item = T>,
 {
@@ -20,6 +21,7 @@ fn foo<I, T>(_: I)
 
 #[rustc_polymorphize_error]
 fn baz<I, T>(_: I)
+//~^ ERROR item has unused generic parameters
 where
     std::iter::Repeat<I>: Iterator<Item = T>,
 {
@@ -40,6 +42,7 @@ impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E>
     #[rustc_polymorphize_error]
     fn next(&mut self) -> Option<Self::Item> {
         self.find(|_| true)
+        //~^ ERROR item has unused generic parameters
     }
 }
 
@@ -53,6 +56,7 @@ impl Baz<u32> for u16 {}
 
 #[rustc_polymorphize_error]
 fn quux<A, B, C: Default>() -> usize
+//~^ ERROR item has unused generic parameters
 where
     A: Baz<B>,
     B: Baz<C>,
@@ -69,6 +73,7 @@ impl Foobar<u32, u32> for () {}
 
 #[rustc_polymorphize_error]
 fn foobar<F, G>() -> usize
+//~^ ERROR item has unused generic parameters
 where
     (): Foobar<F, G>,
 {
index c23730fc995e7fd5058753aafecb6f408832f8bf..5fc51e58d728a3ec3d5a191ef65abd0a4c956bb1 100644 (file)
@@ -1,8 +1,45 @@
+error: item has unused generic parameters
+  --> $DIR/predicates.rs:14:4
+   |
+LL | fn foo<I, T>(_: I)
+   |    ^^^    - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/predicates.rs:23:4
+   |
+LL | fn baz<I, T>(_: I)
+   |    ^^^    - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/predicates.rs:44:19
+   |
+LL | impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E>
+   |          -         - generic parameter `E` is unused
+   |          |
+   |          generic parameter `I` is unused
+...
+LL |         self.find(|_| true)
+   |                   ^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/predicates.rs:58:4
+   |
+LL | fn quux<A, B, C: Default>() -> usize
+   |    ^^^^ -  - generic parameter `B` is unused
+   |         |
+   |         generic parameter `A` is unused
+
+error: item has unused generic parameters
+  --> $DIR/predicates.rs:75:4
+   |
+LL | fn foobar<F, G>() -> usize
+   |    ^^^^^^ - generic parameter `F` is unused
+
 error: item has unused generic parameters
   --> $DIR/predicates.rs:9:4
    |
 LL | fn bar<I>() {
    |    ^^^ - generic parameter `I` is unused
 
-error: aborting due to previous error
+error: aborting due to 6 previous errors
 
index 882f314655d8377092265a0880836e1b97bc67f3..c2a33ce1f59b38549e5fd6196863f26ff25481ea 100644 (file)
@@ -23,13 +23,7 @@ LL | pub fn foo() {}
 
 error: requires `sized` lang_item
 
-error: requires `sized` lang_item
-
-error: requires `sized` lang_item
-
-error: requires `sized` lang_item
-
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0432, E0603.
 For more information about an error, try `rustc --explain E0432`.
index 42ce456d962a1562bf81db8b1762099e74059a95..22c1e48b07d947391692d0596ed413658362a724 100644 (file)
@@ -6,12 +6,6 @@ LL |     use bar::gpriv;
 
 error: requires `sized` lang_item
 
-error: requires `sized` lang_item
-
-error: requires `sized` lang_item
-
-error: requires `sized` lang_item
-
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0432`.
index f926eee9d92b282deddff6f52ff1437bc6edb05e..ec8666f93f096392d13343e876983af073e7bba8 100644 (file)
@@ -1,5 +1,6 @@
 // aux-crate:priv:priv_dep=priv_dep.rs
 // aux-build:pub_dep.rs
+// compile-flags: -Zunstable-options
 #![deny(exported_private_dependencies)]
 
 // This crate is a private dependency
index e6b4d33f10316e4ee36e8644e0de76f4f9a2a819..f64b8569015d8fc881c2c50dd5d44cdd20a21b04 100644 (file)
@@ -1,23 +1,23 @@
 error: type `OtherType` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:20:5
+  --> $DIR/pub-priv1.rs:21:5
    |
 LL |     pub field: OtherType,
    |     ^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/pub-priv1.rs:3:9
+  --> $DIR/pub-priv1.rs:4:9
    |
 LL | #![deny(exported_private_dependencies)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: type `OtherType` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:27:5
+  --> $DIR/pub-priv1.rs:28:5
    |
 LL |     pub fn pub_fn(param: OtherType) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: trait `OtherTrait` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:34:5
+  --> $DIR/pub-priv1.rs:35:5
    |
 LL |     type Foo: OtherTrait;
    |     ^^^^^^^^^^^^^^^^^^^^^
index 65d8bcd9972e65bf82b6c1b9ecbcccaf34379d24..695ea69c8e65284bd80c7e77d9bf2b3382e5eab2 100644 (file)
@@ -35,5 +35,5 @@ fn main() {
 }
 
 use deny as allow;
-#[allow(unused)] //~ ERROR `allow` is ambiguous (built-in attribute vs any other name)
+#[allow(unused)] //~ ERROR `allow` is ambiguous
 fn builtin_renamed() {}
index 1ad991db3be4450e6861de7ae4dadd516871d27d..0f4ddc065a7420cd384a6cbae36611de6e7e0f30 100644 (file)
@@ -4,12 +4,13 @@ error[E0425]: cannot find value `NonExistent` in this scope
 LL |     NonExistent;
    |     ^^^^^^^^^^^ not found in this scope
 
-error[E0659]: `repr` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `repr` is ambiguous
   --> $DIR/ambiguous-builtin-attrs.rs:9:3
    |
 LL | #[repr(C)]
    |   ^^^^ ambiguous name
    |
+   = note: ambiguous because of a name conflict with a builtin attribute
    = note: `repr` could refer to a built-in attribute
 note: `repr` could also refer to the attribute macro imported here
   --> $DIR/ambiguous-builtin-attrs.rs:6:5
@@ -18,12 +19,13 @@ LL | use builtin_attrs::*;
    |     ^^^^^^^^^^^^^^^^
    = help: use `crate::repr` to refer to this attribute macro unambiguously
 
-error[E0659]: `repr` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `repr` is ambiguous
   --> $DIR/ambiguous-builtin-attrs.rs:11:19
    |
 LL | #[cfg_attr(all(), repr(C))]
    |                   ^^^^ ambiguous name
    |
+   = note: ambiguous because of a name conflict with a builtin attribute
    = note: `repr` could refer to a built-in attribute
 note: `repr` could also refer to the attribute macro imported here
   --> $DIR/ambiguous-builtin-attrs.rs:6:5
@@ -32,12 +34,13 @@ LL | use builtin_attrs::*;
    |     ^^^^^^^^^^^^^^^^
    = help: use `crate::repr` to refer to this attribute macro unambiguously
 
-error[E0659]: `repr` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `repr` is ambiguous
   --> $DIR/ambiguous-builtin-attrs.rs:20:34
    |
 LL | fn non_macro_expanded_location<#[repr(C)] T>() {
    |                                  ^^^^ ambiguous name
    |
+   = note: ambiguous because of a name conflict with a builtin attribute
    = note: `repr` could refer to a built-in attribute
 note: `repr` could also refer to the attribute macro imported here
   --> $DIR/ambiguous-builtin-attrs.rs:6:5
@@ -46,12 +49,13 @@ LL | use builtin_attrs::*;
    |     ^^^^^^^^^^^^^^^^
    = help: use `crate::repr` to refer to this attribute macro unambiguously
 
-error[E0659]: `repr` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `repr` is ambiguous
   --> $DIR/ambiguous-builtin-attrs.rs:24:11
    |
 LL |         #[repr(C)]
    |           ^^^^ ambiguous name
    |
+   = note: ambiguous because of a name conflict with a builtin attribute
    = note: `repr` could refer to a built-in attribute
 note: `repr` could also refer to the attribute macro imported here
   --> $DIR/ambiguous-builtin-attrs.rs:6:5
@@ -60,12 +64,13 @@ LL | use builtin_attrs::*;
    |     ^^^^^^^^^^^^^^^^
    = help: use `crate::repr` to refer to this attribute macro unambiguously
 
-error[E0659]: `allow` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `allow` is ambiguous
   --> $DIR/ambiguous-builtin-attrs.rs:38:3
    |
 LL | #[allow(unused)]
    |   ^^^^^ ambiguous name
    |
+   = note: ambiguous because of a name conflict with a builtin attribute
    = note: `allow` could refer to a built-in attribute
 note: `allow` could also refer to the built-in attribute imported here
   --> $DIR/ambiguous-builtin-attrs.rs:37:5
@@ -74,12 +79,13 @@ LL | use deny as allow;
    |     ^^^^^^^^^^^^^
    = help: use `crate::allow` to refer to this built-in attribute unambiguously
 
-error[E0659]: `feature` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `feature` is ambiguous
   --> $DIR/ambiguous-builtin-attrs.rs:3:4
    |
 LL | #![feature(decl_macro)]
    |    ^^^^^^^ ambiguous name
    |
+   = note: ambiguous because of a name conflict with a builtin attribute
    = note: `feature` could refer to a built-in attribute
 note: `feature` could also refer to the attribute macro imported here
   --> $DIR/ambiguous-builtin-attrs.rs:6:5
index df462903fc077609c8889277b92ce90be7e6aa46..d8287eb73db01ae4958f7f94927b6ff016b78b3a 100644 (file)
@@ -33,12 +33,13 @@ LL |             gen_helper_use!();
            crate::empty_helper
    = note: this error originates in the macro `gen_helper_use` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0659]: `empty_helper` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `empty_helper` is ambiguous
   --> $DIR/derive-helper-shadowing.rs:26:13
    |
 LL |         use empty_helper;
    |             ^^^^^^^^^^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
 note: `empty_helper` could refer to the derive helper attribute defined here
   --> $DIR/derive-helper-shadowing.rs:22:10
    |
@@ -51,12 +52,13 @@ LL | use test_macros::empty_attr as empty_helper;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: use `crate::empty_helper` to refer to this attribute macro unambiguously
 
-error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `empty_helper` is ambiguous
   --> $DIR/derive-helper-shadowing.rs:19:3
    |
 LL | #[empty_helper]
    |   ^^^^^^^^^^^^ ambiguous name
    |
+   = note: ambiguous because of a name conflict with a derive helper attribute
 note: `empty_helper` could refer to the derive helper attribute defined here
   --> $DIR/derive-helper-shadowing.rs:22:10
    |
index e5f967416c92239a4ac281cb4a811646a6e9f543..471f317edf96479f64ac9bbc3beadf5d934aaf71 100644 (file)
                             //~| ERROR cannot find type `OuterAttr` in this scope
 struct S;
 
-#[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope
-                                     //~| WARN cannot find type `OuterDerive` in this scope
+#[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope
+                                     //~| ERROR cannot find type `OuterDerive` in this scope
                                      //~| WARN this was previously accepted
                                      //~| WARN this was previously accepted
 struct Z;
 
 fn inner_block() {
-    #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope
-                                        //~| WARN cannot find type `OuterDerive` in this scope
+    #[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope
+                                        //~| ERROR cannot find type `OuterDerive` in this scope
                                         //~| WARN this was previously accepted
                                         //~| WARN this was previously accepted
     struct InnerZ;
index be58cc40ed299036753e7ee41df2c60f3a7a7563..a2c1b82b15f6872f9aff80a4b3346048543db653 100644 (file)
@@ -38,18 +38,18 @@ LL | #[generate_mod::check_attr]
            OuterAttr
    = note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
   --> $DIR/generate-mod.rs:16:10
    |
 LL | #[derive(generate_mod::CheckDerive)]
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
    |
-   = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
+   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
   --> $DIR/generate-mod.rs:16:10
    |
 LL | #[derive(generate_mod::CheckDerive)]
@@ -57,9 +57,9 @@ LL | #[derive(generate_mod::CheckDerive)]
    |
    = 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 #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
   --> $DIR/generate-mod.rs:23:14
    |
 LL |     #[derive(generate_mod::CheckDerive)]
@@ -67,9 +67,9 @@ LL |     #[derive(generate_mod::CheckDerive)]
    |
    = 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 #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
   --> $DIR/generate-mod.rs:23:14
    |
 LL |     #[derive(generate_mod::CheckDerive)]
@@ -77,25 +77,25 @@ LL |     #[derive(generate_mod::CheckDerive)]
    |
    = 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 #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 4 previous errors; 4 warnings emitted
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0412`.
 Future incompatibility report: Future breakage diagnostic:
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
   --> $DIR/generate-mod.rs:16:10
    |
 LL | #[derive(generate_mod::CheckDerive)]
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
    |
-   = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
+   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
   --> $DIR/generate-mod.rs:16:10
    |
 LL | #[derive(generate_mod::CheckDerive)]
@@ -103,10 +103,10 @@ LL | #[derive(generate_mod::CheckDerive)]
    |
    = 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 #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
   --> $DIR/generate-mod.rs:23:14
    |
 LL |     #[derive(generate_mod::CheckDerive)]
@@ -114,10 +114,10 @@ LL |     #[derive(generate_mod::CheckDerive)]
    |
    = 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 #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
   --> $DIR/generate-mod.rs:23:14
    |
 LL |     #[derive(generate_mod::CheckDerive)]
@@ -125,7 +125,7 @@ LL |     #[derive(generate_mod::CheckDerive)]
    |
    = 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 #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
 warning: cannot find type `FromOutside` in this scope
index 2b742771d6f2c7dede3574c71e7577bdd4747a5d..3a2a6fa2253fae3901fd15ac8308e6663d56dded 100644 (file)
@@ -1,4 +1,3 @@
-// check-pass
 // aux-build:pin-project-internal-0.4.0.rs
 // compile-flags: -Z span-debug
 
@@ -24,7 +23,7 @@ macro_rules! other {
     }
 
     struct Foo;
-    impl_macros!(Foo); //~ WARN  using an old version
+    impl_macros!(Foo); //~ ERROR  using an old version
                        //~| WARN this was previously
     arrays!(Foo);
     other!(Foo);
@@ -41,9 +40,9 @@ macro_rules! other {
     }
 
     struct Foo;
-    impl_macros!(Foo); //~  WARN using an old version
+    impl_macros!(Foo); //~  ERROR using an old version
                        //~| WARN this was previously
-    arrays!(Foo); //~  WARN using an old version
+    arrays!(Foo); //~  ERROR using an old version
                   //~| WARN this was previously
     other!(Foo);
 }
@@ -52,7 +51,7 @@ mod actix_web_test {
     include!("actix-web/src/extract.rs");
 
     struct Foo;
-    tuple_from_req!(Foo); //~ WARN using an old version
+    tuple_from_req!(Foo); //~ ERROR using an old version
     //~| WARN this was previously
 }
 
@@ -60,7 +59,7 @@ mod actix_web_version_test {
     include!("actix-web-2.0.0/src/extract.rs");
 
     struct Foo;
-    tuple_from_req!(Foo); //~ WARN using an old version
+    tuple_from_req!(Foo); //~ ERROR using an old version
     //~| WARN this was previously
 }
 
index 1a56291896c76b993a8b347193e25ebcd28e111a..bd9ba6a09fce5cc0b40ab46d4050c43dfd9cc74b 100644 (file)
@@ -1,27 +1,27 @@
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
   --> $DIR/time-macros-impl/src/lib.rs:5:32
    |
 LL |         #[my_macro] struct One($name);
    |                                ^^^^^
    |
-  ::: $DIR/group-compat-hack.rs:27:5
+  ::: $DIR/group-compat-hack.rs:26:5
    |
 LL |     impl_macros!(Foo);
    |     ----------------- in this macro invocation
    |
-   = note: `#[warn(proc_macro_back_compat)]` on by default
+   = note: `#[deny(proc_macro_back_compat)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
-   = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
   --> $DIR/time-macros-impl-0.1.0/src/lib.rs:5:32
    |
 LL |         #[my_macro] struct One($name);
    |                                ^^^^^
    |
-  ::: $DIR/group-compat-hack.rs:44:5
+  ::: $DIR/group-compat-hack.rs:43:5
    |
 LL |     impl_macros!(Foo);
    |     ----------------- in this macro invocation
@@ -29,15 +29,15 @@ LL |     impl_macros!(Foo);
    = 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
-   = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: using an old version of `js-sys`
+error: using an old version of `js-sys`
   --> $DIR/js-sys-0.3.17/src/lib.rs:5:32
    |
 LL |         #[my_macro] struct Two($name);
    |                                ^^^^^
    |
-  ::: $DIR/group-compat-hack.rs:46:5
+  ::: $DIR/group-compat-hack.rs:45:5
    |
 LL |     arrays!(Foo);
    |     ------------ in this macro invocation
@@ -45,15 +45,15 @@ LL |     arrays!(Foo);
    = 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: older versions of the `js-sys` crate will stop compiling in future versions of Rust; please update to `js-sys` v0.3.40 or above
-   = note: this warning originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
   --> $DIR/actix-web/src/extract.rs:5:34
    |
 LL |         #[my_macro] struct Three($T);
    |                                  ^^
    |
-  ::: $DIR/group-compat-hack.rs:55:5
+  ::: $DIR/group-compat-hack.rs:54:5
    |
 LL |     tuple_from_req!(Foo);
    |     -------------------- in this macro invocation
@@ -61,15 +61,15 @@ LL |     tuple_from_req!(Foo);
    = 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
-   = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
   --> $DIR/actix-web-2.0.0/src/extract.rs:5:34
    |
 LL |         #[my_macro] struct Three($T);
    |                                  ^^
    |
-  ::: $DIR/group-compat-hack.rs:63:5
+  ::: $DIR/group-compat-hack.rs:62:5
    |
 LL |     tuple_from_req!(Foo);
    |     -------------------- in this macro invocation
@@ -77,36 +77,36 @@ LL |     tuple_from_req!(Foo);
    = 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
-   = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: 5 warnings emitted
+error: aborting due to 5 previous errors
 
 Future incompatibility report: Future breakage diagnostic:
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
   --> $DIR/time-macros-impl/src/lib.rs:5:32
    |
 LL |         #[my_macro] struct One($name);
    |                                ^^^^^
    |
-  ::: $DIR/group-compat-hack.rs:27:5
+  ::: $DIR/group-compat-hack.rs:26:5
    |
 LL |     impl_macros!(Foo);
    |     ----------------- in this macro invocation
    |
-   = note: `#[warn(proc_macro_back_compat)]` on by default
+   = note: `#[deny(proc_macro_back_compat)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
-   = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
   --> $DIR/time-macros-impl-0.1.0/src/lib.rs:5:32
    |
 LL |         #[my_macro] struct One($name);
    |                                ^^^^^
    |
-  ::: $DIR/group-compat-hack.rs:44:5
+  ::: $DIR/group-compat-hack.rs:43:5
    |
 LL |     impl_macros!(Foo);
    |     ----------------- in this macro invocation
@@ -114,16 +114,16 @@ LL |     impl_macros!(Foo);
    = 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
-   = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-warning: using an old version of `js-sys`
+error: using an old version of `js-sys`
   --> $DIR/js-sys-0.3.17/src/lib.rs:5:32
    |
 LL |         #[my_macro] struct Two($name);
    |                                ^^^^^
    |
-  ::: $DIR/group-compat-hack.rs:46:5
+  ::: $DIR/group-compat-hack.rs:45:5
    |
 LL |     arrays!(Foo);
    |     ------------ in this macro invocation
@@ -131,16 +131,16 @@ LL |     arrays!(Foo);
    = 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: older versions of the `js-sys` crate will stop compiling in future versions of Rust; please update to `js-sys` v0.3.40 or above
-   = note: this warning originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
   --> $DIR/actix-web/src/extract.rs:5:34
    |
 LL |         #[my_macro] struct Three($T);
    |                                  ^^
    |
-  ::: $DIR/group-compat-hack.rs:55:5
+  ::: $DIR/group-compat-hack.rs:54:5
    |
 LL |     tuple_from_req!(Foo);
    |     -------------------- in this macro invocation
@@ -148,16 +148,16 @@ LL |     tuple_from_req!(Foo);
    = 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
-   = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
   --> $DIR/actix-web-2.0.0/src/extract.rs:5:34
    |
 LL |         #[my_macro] struct Three($T);
    |                                  ^^
    |
-  ::: $DIR/group-compat-hack.rs:63:5
+  ::: $DIR/group-compat-hack.rs:62:5
    |
 LL |     tuple_from_req!(Foo);
    |     -------------------- in this macro invocation
@@ -165,5 +165,5 @@ LL |     tuple_from_req!(Foo);
    = 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
-   = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
 
index 82d6bc33bf95b95f960d75d2bd360dcb3d54373c..51312b10ad17616bb7e4d4c187ee469f39e49073 100644 (file)
@@ -1,11 +1,11 @@
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#6) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#6) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:27:18: 27:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#6) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#6) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#10) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#10) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:13: 29:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:32: 5:37 (#10) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#10) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#10) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:22:25: 22:31 (#14) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:22:32: 22:37 (#14) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:30:12: 30:15 (#0) }], span: $DIR/group-compat-hack.rs:22:38: 22:43 (#14) }], span: $DIR/group-compat-hack.rs:22:37: 22:44 (#14) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:22:44: 22:45 (#14) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:18: 44:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:46:13: 46:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:39:25: 39:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:39:32: 39:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:48:12: 48:15 (#0) }], span: $DIR/group-compat-hack.rs:39:38: 39:43 (#28) }], span: $DIR/group-compat-hack.rs:39:37: 39:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:39:44: 39:45 (#28) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:55:21: 55:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:63:21: 63:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:71:21: 71:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:33: 5:35 (#43) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:78:21: 78:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:33: 5:35 (#48) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.40/src/lib.rs:5:21: 5:27 (#53) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.40/src/lib.rs:5:28: 5:31 (#53) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:84:13: 84:16 (#0) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:32: 5:37 (#53) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:31: 5:38 (#53) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.40/src/lib.rs:5:38: 5:39 (#53) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#6) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#6) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:26:18: 26:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#6) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#6) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#10) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#10) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:28:13: 28:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:32: 5:37 (#10) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#10) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#10) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:21:25: 21:31 (#14) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:21:32: 21:37 (#14) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:21:38: 21:43 (#14) }], span: $DIR/group-compat-hack.rs:21:37: 21:44 (#14) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:21:44: 21:45 (#14) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:13: 45:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:47:12: 47:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#28) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#28) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:54:21: 54:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:62:21: 62:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:70:21: 70:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:33: 5:35 (#43) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:77:21: 77:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:33: 5:35 (#48) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.40/src/lib.rs:5:21: 5:27 (#53) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.40/src/lib.rs:5:28: 5:31 (#53) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:83:13: 83:16 (#0) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:32: 5:37 (#53) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:31: 5:38 (#53) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.40/src/lib.rs:5:38: 5:39 (#53) }]
index ceb6d789785cc1b39548266c2407c9f4d8cdd51d..45b014c4b69fa161d2e4e4bc645c0a917a3133ee 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `empty_helper` is ambiguous
   --> $DIR/helper-attr-blocked-by-import-ambig.rs:7:3
    |
 LL | #[empty_helper]
    |   ^^^^^^^^^^^^ ambiguous name
    |
+   = note: ambiguous because of a name conflict with a derive helper attribute
 note: `empty_helper` could refer to the derive helper attribute defined here
   --> $DIR/helper-attr-blocked-by-import-ambig.rs:10:10
    |
index 22ad4aa147b66132be92f110bca81294deacfe91..60cd36a9cceb92d3c4d3ff5617238a8e4eb197a9 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `identity_attr` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `identity_attr` is ambiguous
   --> $DIR/issue-41211.rs:11:4
    |
 LL | #![identity_attr]
    |    ^^^^^^^^^^^^^ ambiguous name
    |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
 note: `identity_attr` could refer to the attribute macro imported here
   --> $DIR/issue-41211.rs:14:5
    |
index abc3d2691a307bed549216a34b9dc70897022f48..113235051b2b92dfb46504782a0f526ac55df1c6 100644 (file)
@@ -1,11 +1,10 @@
-// check-pass
 // aux-build:test-macros.rs
 
 #[macro_use]
 extern crate test_macros;
 
 #[derive(Print)]
-enum ProceduralMasqueradeDummyType { //~ WARN using
+enum ProceduralMasqueradeDummyType { //~ ERROR using
 //~| WARN this was previously
     Input
 }
index 4d6edab08e2cf28b85f668ad55a2549780241bff..dff71c9eacd4d8d24f6527e670e63caa61386294 100644 (file)
@@ -1,24 +1,24 @@
-warning: using `procedural-masquerade` crate
-  --> $DIR/issue-73933-procedural-masquerade.rs:8:6
+error: using `procedural-masquerade` crate
+  --> $DIR/issue-73933-procedural-masquerade.rs:7:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(proc_macro_back_compat)]` on by default
+   = note: `#[deny(proc_macro_back_compat)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
 
-warning: 1 warning emitted
+error: aborting due to previous error
 
 Future incompatibility report: Future breakage diagnostic:
-warning: using `procedural-masquerade` crate
-  --> $DIR/issue-73933-procedural-masquerade.rs:8:6
+error: using `procedural-masquerade` crate
+  --> $DIR/issue-73933-procedural-masquerade.rs:7:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(proc_macro_back_compat)]` on by default
+   = note: `#[deny(proc_macro_back_compat)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
index 8edd68f8a3b849dc0605203bf52b68a9f4e038d0..8a8fbf0682470d90f59dc95beeb67b551cf5569a 100644 (file)
@@ -3,20 +3,20 @@ PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
-        span: #0 bytes(100..104),
+        span: #0 bytes(86..90),
     },
     Ident {
         ident: "ProceduralMasqueradeDummyType",
-        span: #0 bytes(105..134),
+        span: #0 bytes(91..120),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "Input",
-                span: #0 bytes(186..191),
+                span: #0 bytes(173..178),
             },
         ],
-        span: #0 bytes(135..193),
+        span: #0 bytes(121..180),
     },
 ]
index 7f7a1009c909a6a751d846e4c5ef5bed08d9c704..5d04fe1e3de5f5cd08f9ead0fb563fdfd8d05eca 100644 (file)
@@ -49,6 +49,8 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt:
 crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it")
 crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site")
 crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
 crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include")
 crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
 
index 078038638137327b44fa10c59ecf8ff5262c31af..709b2a2169e08d8f9033ba28e706f17f06756acc 100644 (file)
@@ -73,6 +73,8 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt:
 crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer")
 crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro(Bang, "inner")
 crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro(Bang, "print_bang")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
 crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include")
 crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
 
index 1ba04258df0d53c942a78c1e33d5d6f073897c8d..b66e4575e11af6720abf96cc9472e2a5895bbddf 100644 (file)
@@ -4,12 +4,13 @@ error: cannot find attribute `C` in this scope
 LL | #[C]
    |   ^ help: a derive helper attribute with a similar name exists: `B`
 
-error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `B` is ambiguous
   --> $DIR/proc-macro-attributes.rs:6:3
    |
 LL | #[B]
    |   ^ ambiguous name
    |
+   = note: ambiguous because of a name conflict with a derive helper attribute
 note: `B` could refer to the derive helper attribute defined here
   --> $DIR/proc-macro-attributes.rs:19:10
    |
@@ -21,12 +22,13 @@ note: `B` could also refer to the derive macro imported here
 LL | #[macro_use]
    | ^^^^^^^^^^^^
 
-error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `B` is ambiguous
   --> $DIR/proc-macro-attributes.rs:10:3
    |
 LL | #[B(D)]
    |   ^ ambiguous name
    |
+   = note: ambiguous because of a name conflict with a derive helper attribute
 note: `B` could refer to the derive helper attribute defined here
   --> $DIR/proc-macro-attributes.rs:19:10
    |
@@ -38,12 +40,13 @@ note: `B` could also refer to the derive macro imported here
 LL | #[macro_use]
    | ^^^^^^^^^^^^
 
-error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `B` is ambiguous
   --> $DIR/proc-macro-attributes.rs:13:3
    |
 LL | #[B(E = "foo")]
    |   ^ ambiguous name
    |
+   = note: ambiguous because of a name conflict with a derive helper attribute
 note: `B` could refer to the derive helper attribute defined here
   --> $DIR/proc-macro-attributes.rs:19:10
    |
@@ -55,12 +58,13 @@ note: `B` could also refer to the derive macro imported here
 LL | #[macro_use]
    | ^^^^^^^^^^^^
 
-error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `B` is ambiguous
   --> $DIR/proc-macro-attributes.rs:16:3
    |
 LL | #[B(arbitrary tokens)]
    |   ^ ambiguous name
    |
+   = note: ambiguous because of a name conflict with a derive helper attribute
 note: `B` could refer to the derive helper attribute defined here
   --> $DIR/proc-macro-attributes.rs:19:10
    |
diff --git a/src/test/ui/query-system/issue-83479.rs b/src/test/ui/query-system/issue-83479.rs
new file mode 100644 (file)
index 0000000..32676df
--- /dev/null
@@ -0,0 +1,16 @@
+#![feature(type_alias_impl_trait)]
+
+type PairCoupledTypes: Trait<
+    //~^ ERROR: bounds on `type`s in this context have no effect
+    //~| ERROR: cannot find trait `Trait` in this scope
+    [u32; {
+        static FOO: usize; //~ ERROR: free static item without body
+    }],
+> = impl Trait<
+    //~^ ERROR: cannot find trait `Trait` in this scope
+    [u32; {
+        static FOO: usize; //~ ERROR: free static item without body
+    }],
+>;
+
+fn main() {}
diff --git a/src/test/ui/query-system/issue-83479.stderr b/src/test/ui/query-system/issue-83479.stderr
new file mode 100644 (file)
index 0000000..7cb41f5
--- /dev/null
@@ -0,0 +1,44 @@
+error: bounds on `type`s in this context have no effect
+  --> $DIR/issue-83479.rs:3:24
+   |
+LL |   type PairCoupledTypes: Trait<
+   |  ________________________^
+LL | |
+LL | |
+LL | |     [u32; {
+LL | |         static FOO: usize;
+LL | |     }],
+LL | | > = impl Trait<
+   | |_^
+
+error: free static item without body
+  --> $DIR/issue-83479.rs:7:9
+   |
+LL |         static FOO: usize;
+   |         ^^^^^^^^^^^^^^^^^-
+   |                          |
+   |                          help: provide a definition for the static: `= <expr>;`
+
+error: free static item without body
+  --> $DIR/issue-83479.rs:12:9
+   |
+LL |         static FOO: usize;
+   |         ^^^^^^^^^^^^^^^^^-
+   |                          |
+   |                          help: provide a definition for the static: `= <expr>;`
+
+error[E0405]: cannot find trait `Trait` in this scope
+  --> $DIR/issue-83479.rs:3:24
+   |
+LL | type PairCoupledTypes: Trait<
+   |                        ^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `Trait` in this scope
+  --> $DIR/issue-83479.rs:9:10
+   |
+LL | > = impl Trait<
+   |          ^^^^^ not found in this scope
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0405`.
diff --git a/src/test/ui/resolve/issue-90113.rs b/src/test/ui/resolve/issue-90113.rs
new file mode 100644 (file)
index 0000000..f6658b4
--- /dev/null
@@ -0,0 +1,21 @@
+mod list {
+    pub use self::List::Cons;
+
+    pub enum List<T> {
+        Cons(T, Box<List<T>>),
+    }
+}
+
+mod alias {
+    use crate::list::List;
+
+    pub type Foo = List<String>;
+}
+
+fn foo(l: crate::alias::Foo) {
+    match l {
+        Cons(..) => {} //~ ERROR: cannot find tuple struct or tuple variant `Cons` in this scope
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/issue-90113.stderr b/src/test/ui/resolve/issue-90113.stderr
new file mode 100644 (file)
index 0000000..1b78720
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0531]: cannot find tuple struct or tuple variant `Cons` in this scope
+  --> $DIR/issue-90113.rs:17:9
+   |
+LL |         Cons(..) => {}
+   |         ^^^^ not found in this scope
+   |
+help: consider importing this tuple variant
+   |
+LL | use list::List::Cons;
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0531`.
index ff72b0b563ab176fc361e0b13a117f173fe00f8f..06c52befd52b2daa8694f9c2d12af234bae2e67f 100644 (file)
@@ -338,7 +338,7 @@ LL |         let _ = Z::Unit();
    |                 |
    |                 call expression requires function
    |
-help: `Z::Unit` is a unit variant, you need to write it without the parenthesis
+help: `Z::Unit` is a unit variant, you need to write it without the parentheses
    |
 LL |         let _ = Z::Unit;
    |                 ~~~~~~~
@@ -372,7 +372,7 @@ LL |     let _: E = m::E::Unit();
    |                |
    |                call expression requires function
    |
-help: `m::E::Unit` is a unit variant, you need to write it without the parenthesis
+help: `m::E::Unit` is a unit variant, you need to write it without the parentheses
    |
 LL |     let _: E = m::E::Unit;
    |                ~~~~~~~~~~
@@ -406,7 +406,7 @@ LL |     let _: E = E::Unit();
    |                |
    |                call expression requires function
    |
-help: `E::Unit` is a unit variant, you need to write it without the parenthesis
+help: `E::Unit` is a unit variant, you need to write it without the parentheses
    |
 LL |     let _: E = E::Unit;
    |                ~~~~~~~
index 5ec4352919ea015c2c78c9bf0f835e88dce2db2f..513b473c4de436f5b96e79b75a2f064d01c58acf 100644 (file)
@@ -16,7 +16,7 @@ LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -25,7 +25,7 @@ LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -34,7 +34,7 @@ LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -43,7 +43,7 @@ LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -52,7 +52,7 @@ LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -61,7 +61,7 @@ LL |     if true || let 0 = 0 {}
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -70,7 +70,7 @@ LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -79,7 +79,7 @@ LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -88,7 +88,7 @@ LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -97,7 +97,7 @@ LL |     if x = let 0 = 0 {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -106,7 +106,7 @@ LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -115,7 +115,7 @@ LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -124,7 +124,7 @@ LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -133,7 +133,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -142,7 +142,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -151,7 +151,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -160,7 +160,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -169,7 +169,7 @@ LL |     if let true = let true = true {}
    |                   ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -178,7 +178,7 @@ LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -187,7 +187,7 @@ LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -196,7 +196,7 @@ LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -205,7 +205,7 @@ LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -214,7 +214,7 @@ LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -223,7 +223,7 @@ LL |     while true || let 0 = 0 {}
    |                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -232,7 +232,7 @@ LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -241,7 +241,7 @@ LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -250,7 +250,7 @@ LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -259,7 +259,7 @@ LL |     while x = let 0 = 0 {}
    |               ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -268,7 +268,7 @@ LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -277,7 +277,7 @@ LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -286,7 +286,7 @@ LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -295,7 +295,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -304,7 +304,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -313,7 +313,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -322,7 +322,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -331,7 +331,7 @@ LL |     while let true = let true = true {}
    |                      ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -340,7 +340,7 @@ LL |     &let 0 = 0;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -349,7 +349,7 @@ LL |     !let 0 = 0;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -358,7 +358,7 @@ LL |     *let 0 = 0;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -367,7 +367,7 @@ LL |     -let 0 = 0;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -376,7 +376,7 @@ LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -385,7 +385,7 @@ LL |     true || let 0 = 0;
    |             ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -394,7 +394,7 @@ LL |     (true || let 0 = 0);
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -403,7 +403,7 @@ LL |     true && (true || let 0 = 0);
    |                      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -412,7 +412,7 @@ LL |     x = let 0 = 0;
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -421,7 +421,7 @@ LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -430,7 +430,7 @@ LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -439,7 +439,7 @@ LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -448,7 +448,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -457,7 +457,7 @@ LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -466,7 +466,7 @@ LL |     &let 0 = 0
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -475,7 +475,7 @@ LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -484,7 +484,7 @@ LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -493,7 +493,7 @@ LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
@@ -502,7 +502,7 @@ LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if`- and `while`-expressions
-   = note: as well as when nested within `&&` and parenthesis in those conditions
+   = 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
index 34cd1d2b1074d837610e08bca6d5e547da91debb..efe46d7e81d3de1ea8759a1acd7aead7f7c1948f 100644 (file)
@@ -51,9 +51,6 @@ LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
 error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied
   --> $DIR/const-drop-fail.rs:49:5
    |
-LL |         const _: () = check($exp);
-   |                       ----- required by a bound introduced by this call
-...
 LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop`
    |
index 34cd1d2b1074d837610e08bca6d5e547da91debb..efe46d7e81d3de1ea8759a1acd7aead7f7c1948f 100644 (file)
@@ -51,9 +51,6 @@ LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
 error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied
   --> $DIR/const-drop-fail.rs:49:5
    |
-LL |         const _: () = check($exp);
-   |                       ----- required by a bound introduced by this call
-...
 LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop`
    |
index 4a4544c16c941d53f53ad234e1b5d8374c72db5d..fffb91f98700bdf8f9c9210468645a851944d9ca 100644 (file)
@@ -20,11 +20,11 @@ error[E0277]: the trait bound `T: Bar` is not satisfied
 LL |     T::c::<T>();
    |     ^^^^^^^^^ the trait `Bar` is not implemented for `T`
    |
-note: required by a bound in `Foo::c`
-  --> $DIR/trait-where-clause.rs:9:10
+note: required by `Foo::c`
+  --> $DIR/trait-where-clause.rs:9:5
    |
 LL |     fn c<T: ~const Bar>();
-   |          ^ required by this bound in `Foo::c`
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 help: consider further restricting this bound
    |
 LL | const fn test1<T: ~const Foo + Bar + Bar>() {
@@ -52,11 +52,11 @@ error[E0277]: the trait bound `T: Bar` is not satisfied
 LL |     T::c::<T>();
    |     ^^^^^^^^^ the trait `Bar` is not implemented for `T`
    |
-note: required by a bound in `Foo::c`
-  --> $DIR/trait-where-clause.rs:9:10
+note: required by `Foo::c`
+  --> $DIR/trait-where-clause.rs:9:5
    |
 LL |     fn c<T: ~const Bar>();
-   |          ^ required by this bound in `Foo::c`
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 help: consider further restricting this bound
    |
 LL | fn test3<T: Foo + Bar>() {
index 1d3a2ff82845ef74b6769045d765fc5e02b1c5e1..dc193582c6a50bec8fe0184eb0a6a5bcc6fecc52 100644 (file)
@@ -25,6 +25,6 @@ fn main() {
     println!("{:#?}", output);
     let stderr = std::str::from_utf8(&output.stderr);
     assert!(stderr.map(|v| {
-        v.ends_with("drop of the panic payload panicked")
+        v.ends_with("fatal runtime error: drop of the panic payload panicked\n")
     }).unwrap_or(false));
 }
index 2545231a1712c2f75b59900fc8e64afaaf25d913..7e008d46574c644af2de80239f86cfb985d424cd 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
   --> $DIR/ambiguity-macros-nested.rs:8:13
    |
 LL |     pub use std::io;
    |             ^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
    = note: `std` could refer to a built-in crate
    = help: use `::std` to refer to this crate unambiguously
 note: `std` could also refer to the module defined here
index af45cd81a3b106a684e114c196cfe674f0449b55..771d2c10c1da2fbe3ddbb63193d22302bce54264 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
   --> $DIR/ambiguity-macros.rs:7:5
    |
 LL | use std::io;
    |     ^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
    = note: `std` could refer to a built-in crate
    = help: use `::std` to refer to this crate unambiguously
 note: `std` could also refer to the module defined here
index 4129930bdb0fdaa233475080f104b7a8d77e86ac..defb16f79703848400134bada7f2aa1d43f7efe4 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
   --> $DIR/ambiguity-nested.rs:8:13
    |
 LL |     pub use std::io;
    |             ^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
    = note: `std` could refer to a built-in crate
    = help: use `::std` to refer to this crate unambiguously
 note: `std` could also refer to the module defined here
index e123b323e7c574fad59b6a07c4cc34787be779fd..2d735c7e3fdfe25c0edf6c732d38e238c696aeb4 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
   --> $DIR/ambiguity.rs:5:5
    |
 LL | use std::io;
    |     ^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
    = note: `std` could refer to a built-in crate
    = help: use `::std` to refer to this crate unambiguously
 note: `std` could also refer to the module defined here
diff --git a/src/test/ui/rust-2018/uniform-paths/auxiliary/issue-55779-extern-trait.rs b/src/test/ui/rust-2018/uniform-paths/auxiliary/issue-55779-extern-trait.rs
new file mode 100644 (file)
index 0000000..1ce9841
--- /dev/null
@@ -0,0 +1 @@
+pub trait Trait { fn no_op(&self); }
diff --git a/src/test/ui/rust-2018/uniform-paths/auxiliary/issue-87932-a.rs b/src/test/ui/rust-2018/uniform-paths/auxiliary/issue-87932-a.rs
new file mode 100644 (file)
index 0000000..8fd2d77
--- /dev/null
@@ -0,0 +1,3 @@
+pub trait Deserialize {
+    fn deserialize();
+}
index db176876382d6fab84f2509cac68e79d6f1251cc..3d45a81402940a2d9a1d7bf76f4802e002e01569 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `sub` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `sub` is ambiguous
   --> $DIR/block-scoped-shadow-nested.rs:16:13
    |
 LL |         use sub::bar;
    |             ^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
 note: `sub` could refer to the module imported here
   --> $DIR/block-scoped-shadow-nested.rs:14:9
    |
index 2767d9ee77e4293fd6a99f814a3ab23a6c1af24a..b068312cedd6fc9871b2e3d0a7c7bdd500e072d0 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `Foo` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `Foo` is ambiguous
   --> $DIR/block-scoped-shadow.rs:11:9
    |
 LL |     use Foo::*;
    |         ^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
 note: `Foo` could refer to the enum defined here
   --> $DIR/block-scoped-shadow.rs:10:5
    |
@@ -16,12 +17,13 @@ LL | enum Foo {}
    | ^^^^^^^^^^^
    = help: use `crate::Foo` to refer to this enum unambiguously
 
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
   --> $DIR/block-scoped-shadow.rs:18:9
    |
 LL |     use std as foo;
    |         ^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
 note: `std` could refer to the enum defined here
   --> $DIR/block-scoped-shadow.rs:17:5
    |
@@ -34,12 +36,13 @@ LL | struct std;
    | ^^^^^^^^^^^
    = help: use `crate::std` to refer to this struct unambiguously
 
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
   --> $DIR/block-scoped-shadow.rs:18:9
    |
 LL |     use std as foo;
    |         ^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
 note: `std` could refer to the function defined here
   --> $DIR/block-scoped-shadow.rs:16:5
    |
diff --git a/src/test/ui/rust-2018/uniform-paths/issue-55779.rs b/src/test/ui/rust-2018/uniform-paths/issue-55779.rs
new file mode 100644 (file)
index 0000000..0af17a8
--- /dev/null
@@ -0,0 +1,29 @@
+// run-pass
+// edition:2018
+// aux-crate:issue_55779_extern_trait=issue-55779-extern-trait.rs
+
+use issue_55779_extern_trait::Trait;
+
+struct Local;
+struct Helper;
+
+impl Trait for Local {
+    fn no_op(&self)
+    {
+        // (Unused) extern crate declaration necessary to reproduce bug
+        extern crate issue_55779_extern_trait;
+
+        // This one works
+        // impl Trait for Helper { fn no_op(&self) { } }
+
+        // This one infinite-loops
+        const _IMPL_SERIALIZE_FOR_HELPER: () = {
+            // (extern crate can also appear here to reproduce bug,
+            // as in originating example from serde)
+            impl Trait for Helper { fn no_op(&self) { } }
+        };
+
+    }
+}
+
+fn main() { }
index e39840d34d9f70c7651e9bf470b54fdb2c0f308a..d2297385f33deb8f007027f16460f011a4e6fd8d 100644 (file)
@@ -1,9 +1,10 @@
-error[E0659]: `issue_56596` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `issue_56596` is ambiguous
   --> $DIR/issue-56596.rs:12:5
    |
 LL | use issue_56596;
    |     ^^^^^^^^^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
    = note: `issue_56596` could refer to a crate passed with `--extern`
    = help: use `::issue_56596` to refer to this crate unambiguously
 note: `issue_56596` could also refer to the module imported here
diff --git a/src/test/ui/rust-2018/uniform-paths/issue-87932.rs b/src/test/ui/rust-2018/uniform-paths/issue-87932.rs
new file mode 100644 (file)
index 0000000..70a641d
--- /dev/null
@@ -0,0 +1,15 @@
+// edition:2018
+// aux-crate:issue_87932_a=issue-87932-a.rs
+
+pub struct A {}
+
+impl issue_87932_a::Deserialize for A {
+    fn deserialize() {
+        extern crate issue_87932_a as _a;
+    }
+}
+
+fn main() {
+    A::deserialize();
+    //~^ ERROR no function or associated item named `deserialize` found for struct `A`
+}
diff --git a/src/test/ui/rust-2018/uniform-paths/issue-87932.stderr b/src/test/ui/rust-2018/uniform-paths/issue-87932.stderr
new file mode 100644 (file)
index 0000000..53272ab
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0599]: no function or associated item named `deserialize` found for struct `A` in the current scope
+  --> $DIR/issue-87932.rs:13:8
+   |
+LL | pub struct A {}
+   | ------------ function or associated item `deserialize` not found for this
+...
+LL |     A::deserialize();
+   |        ^^^^^^^^^^^ function or associated item not found in `A`
+   |
+   = help: items from traits can only be used if the trait is in scope
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+   |
+LL | use <crate::A as issue_87932_a::Deserialize>::deserialize::_a::Deserialize;
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
index f1b5e0c5efaac3a441f8e900d42530ec420fff9a..622595bfa0328cba4f449f5448db1373bcd6f130 100644 (file)
@@ -10,12 +10,13 @@ note: consider marking `legacy_macro` as `pub` in the imported module
 LL |     pub use legacy_macro as _;
    |             ^^^^^^^^^^^^^^^^^
 
-error[E0659]: `legacy_macro` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `legacy_macro` is ambiguous
   --> $DIR/macro-rules.rs:31:13
    |
 LL |         use legacy_macro as _;
    |             ^^^^^^^^^^^^ ambiguous name
    |
+   = note: ambiguous because of multiple potential import sources
 note: `legacy_macro` could refer to the macro defined here
   --> $DIR/macro-rules.rs:28:9
    |
index 2d306eb920cc157a60c29e3f996980447617d839..fd7fc7fbd41b774dfc6ba266d2edd8f1d3825284 100644 (file)
@@ -13,8 +13,8 @@ mod bar {
 }
 
 fn main() {
-    io::stdout();
-    self::std::io::stdout();
-    foo::my_std::io::stdout();
-    bar::std::io::stdout();
+    let _ = io::stdout();
+    let _ = self::std::io::stdout();
+    let _ = foo::my_std::io::stdout();
+    let _ = bar::std::io::stdout();
 }
index e4662b430dccc7bdd9131fc4996955c95b5fde11..d945b4c94ca2f128d6d628484b6d24bd519b11bc 100644 (file)
@@ -15,6 +15,7 @@ LL |     fn try_into(self) -> Result<T, Self::Error>;
    |        the method is available for `Rc<u8>` here
    |
    = help: items from traits can only be used if the trait is in scope
+   = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
 help: consider wrapping the receiver expression with the appropriate type
    |
 LL |         let _: u32 = Box::new(3u8).try_into().unwrap();
index 3a9fd69322869518567d41a2e18f556ac1cdbc88..a63b6fcf2627ab8294f0a0e050b63a466c3bdf16 100644 (file)
@@ -1,6 +1,5 @@
 // check-pass
 // edition:2021
-// compile-flags: -Zunstable-options
 
 fn main() {
     let _: u16 = 123i32.try_into().unwrap();
index e026f01e93fb038027d0b773c7a4ff53f709e42e..eed2f313abe6ec70ced488c3246db67e05f4dab7 100644 (file)
@@ -1,6 +1,6 @@
 // check-pass
 // run-rustfix
-// compile-flags: -Z unstable-options --edition 2018
+// edition:2018
 
 #![warn(rust_2021_prefixes_incompatible_syntax)]
 
index d24f29634806d9d70cee029979f0a6258a7b8869..0565db793df66accbff7d51319f204b0fb307197 100644 (file)
@@ -1,6 +1,6 @@
 // check-pass
 // run-rustfix
-// compile-flags: -Z unstable-options --edition 2018
+// edition:2018
 
 #![warn(rust_2021_prefixes_incompatible_syntax)]
 
index 8ceb24dd2afd28a85aa06e6dfeb1a439de1f282b..52e7dcf4499a8478d1c12f862e696894cc9ec08f 100644 (file)
@@ -1,9 +1,6 @@
 // run-pass
 // This test is just checking that we won't ICE if logging is turned
-// on; don't bother trying to compare that (copious) output. (Note
-// also that this test potentially silly, since we do not build+test
-// debug versions of rustc as part of our continuous integration
-// process...)
+// on; don't bother trying to compare that (copious) output.
 //
 // dont-check-compiler-stdout
 // dont-check-compiler-stderr
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.nll.stderr
deleted file mode 100644 (file)
index 5d0b2c2..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error: lifetime may not live long enough
-  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:37
-   |
-LL |     async fn f(self: Pin<&Self>) -> impl Clone { self }
-   |                          -          ^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
-   |                          |
-   |                          let's call the lifetime of this reference `'1`
-   |
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
-   |
-LL |     async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
-   |                                                ++++
-
-error: aborting due to previous error
-
index 43998ca8c5784478dfca0e18aea561c2aab3ef40..a1e7f4aa875eeb749821b7101543863b576081a9 100644 (file)
@@ -6,7 +6,7 @@
 
 impl Foo {
     async fn f(self: Pin<&Self>) -> impl Clone { self }
-    //~^ ERROR E0759
+    //~^ ERROR: captures lifetime that does not appear in bounds
 }
 
 fn main() {
index 04cd2b78da124610733a6d77b7c03e3310c04ee4..953d7cd6a07692630c827bdf67d6e05670579ddc 100644 (file)
@@ -1,17 +1,16 @@
-error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:37
    |
 LL |     async fn f(self: Pin<&Self>) -> impl Clone { self }
-   |                ^^^^  ----------     ---------- ...and is required to live as long as `'static` here
-   |                |     |
-   |                |     this data with an anonymous lifetime `'_`...
-   |                ...is captured here...
+   |                          -          ^^^^^^^^^^
+   |                          |
+   |                          hidden type `Pin<&Foo>` captures the lifetime `'_` as defined here
    |
-help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
    |
 LL |     async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
    |                                                ++++
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0759`.
+For more information about this error, try `rustc --explain E0700`.
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr
deleted file mode 100644 (file)
index 4301d8f..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error: lifetime may not live long enough
-  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:31
-   |
-LL |     fn f(self: Pin<&Self>) -> impl Clone { self }
-   |                    -          ^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
-   |                    |
-   |                    let's call the lifetime of this reference `'1`
-   |
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
-   |
-LL |     fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
-   |                                          ++++
-
-error: aborting due to previous error
-
index 04935fc52ab9e31253bb8dce181cacfafdd589ac..4db2fa7dcb81eef2cf602f6c17a0640bca33cfd0 100644 (file)
@@ -3,7 +3,8 @@
 struct Foo;
 
 impl Foo {
-    fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR E0759
+    fn f(self: Pin<&Self>) -> impl Clone { self }
+    //~^ ERROR: captures lifetime that does not appear in bounds
 }
 
 fn main() {
index 54e75aeec3e3662c8c6e9b436313196a1d781034..faa1233ffde634335590e0f5730a39c3bd668112 100644 (file)
@@ -1,21 +1,16 @@
-error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44
-   |
-LL |     fn f(self: Pin<&Self>) -> impl Clone { self }
-   |                ----------                  ^^^^ ...is captured here...
-   |                |
-   |                this data with an anonymous lifetime `'_`...
-   |
-note: ...and is required to live as long as `'static` here
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
   --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:31
    |
 LL |     fn f(self: Pin<&Self>) -> impl Clone { self }
-   |                               ^^^^^^^^^^
-help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |                    -----      ^^^^^^^^^^
+   |                    |
+   |                    hidden type `Pin<&Foo>` captures the anonymous lifetime defined here
+   |
+help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
    |
 LL |     fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
    |                                          ++++
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0759`.
+For more information about this error, try `rustc --explain E0700`.
index d484fb8cbe0d8f6aa5aa9675c104530415e1faa5..ce85d93b96ca8de5f288d1f54a2f0fdc583fd608 100644 (file)
@@ -6,10 +6,10 @@ LL |     let _x = NonZeroU32::new(5).unwrap();
    |
 help: consider importing one of these items
    |
-LL | use std::num::NonZeroU32;
-   |
 LL | use core::num::NonZeroU32;
    |
+LL | use std::num::NonZeroU32;
+   |
 
 error: aborting due to previous error
 
index 80d3c940eb7c618c784dd83f400c575eedb12eac..2dc300ac76f278d4de4b0dbf29e4fa434441f5a5 100644 (file)
@@ -1,17 +1,8 @@
-error[E0597]: `val` does not live long enough
+error[E0515]: cannot return reference to function parameter `val`
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:21:9
    |
-LL |     fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
-   |               -- lifetime `'a` defined here                  ------------------- opaque type requires that `val` is borrowed for `'a`
 LL |         val.use_self()
-   |         ^^^^^^^^^^^^^^ borrowed value does not live long enough
-LL |     }
-   |     - `val` dropped here while still borrowed
-   |
-help: you can add a bound to the opaque type to make it last less than `'static` and match `'a`
-   |
-LL |     fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a {
-   |                                                                                  ++++
+   |         ^^^^^^^^^^^^^^ returns a reference to data owned by the current function
 
 error[E0515]: cannot return reference to function parameter `val`
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9
@@ -27,5 +18,4 @@ LL |         val.use_self()
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0515, E0597.
-For more information about an error, try `rustc --explain E0515`.
+For more information about this error, try `rustc --explain E0515`.
index b2dc16a27e310006490f28118a9781421bc3b9d4..0045d3fcf1c7b5f02cf9f3296d05dce23968dde3 100644 (file)
@@ -18,7 +18,7 @@ fn use_self(&self) -> &() { panic!() }
     impl Bar for i32 {}
 
     fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
-        val.use_self() //~ ERROR E0597
+        val.use_self() //~ ERROR cannot return reference to function parameter
     }
 }
 
index e8c3a7908f5211dc3bb2c26190b7af105bdecd27..2961d8d7eacc99a9a0e59b6c3dc0d115dc2092d8 100644 (file)
@@ -1,17 +1,8 @@
-error[E0597]: `val` does not live long enough
+error[E0515]: cannot return reference to function parameter `val`
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:21:9
    |
-LL |     fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
-   |               -- lifetime `'a` defined here                  ------------------- opaque type requires that `val` is borrowed for `'a`
 LL |         val.use_self()
-   |         ^^^^^^^^^^^^^^ borrowed value does not live long enough
-LL |     }
-   |     - `val` dropped here while still borrowed
-   |
-help: you can add a bound to the opaque type to make it last less than `'static` and match `'a`
-   |
-LL |     fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a {
-   |                                                                                  ++++
+   |         ^^^^^^^^^^^^^^ returns a reference to data owned by the current function
 
 error[E0515]: cannot return reference to function parameter `val`
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9
@@ -47,5 +38,4 @@ LL |     impl MyTrait for Box<dyn ObjectTrait<Assoc = i32> + '_> {
 
 error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0515, E0597.
-For more information about an error, try `rustc --explain E0515`.
+For more information about this error, try `rustc --explain E0515`.
index 263d509075af8058f258103ee9ef2f0caeb7bea1..0d9ecc32e08cdd6c75b47cf425955da9ffed7ddc 100644 (file)
@@ -1,8 +1,10 @@
 error[E0277]: the trait bound `&str: From<String>` is not satisfied
-  --> $DIR/into-str.rs:4:5
+  --> $DIR/into-str.rs:4:9
    |
 LL |     foo(String::new());
-   |     ^^^ the trait `From<String>` is not implemented for `&str`
+   |     --- ^^^^^^^^^^^^^ the trait `From<String>` is not implemented for `&str`
+   |     |
+   |     required by a bound introduced by this call
    |
    = note: to coerce a `String` into a `&str`, use `&*` as a prefix
    = note: required because of the requirements on the impl of `Into<&str>` for `String`
index 58075ed7caebc5bde335a8a0df33d2dbb3fc0f2a..ae55c96702adaed6e9fd46b0482a968834e5d53c 100644 (file)
@@ -49,10 +49,10 @@ LL |     f_sized(*ref_cl);
    |
    = help: the trait `Sized` is not implemented for `dyn Fn()`
 note: required by a bound in `f_sized`
-  --> $DIR/issue-84973-blacklist.rs:9:15
+  --> $DIR/issue-84973-blacklist.rs:9:12
    |
 LL | fn f_sized<T: Sized>(t: T) {}
-   |               ^^^^^ required by this bound in `f_sized`
+   |            ^ required by this bound in `f_sized`
 
 error[E0277]: `Rc<{integer}>` cannot be sent between threads safely
   --> $DIR/issue-84973-blacklist.rs:27:12
diff --git a/src/test/ui/suggestions/issue-90213-expected-boxfuture-self-ice.rs b/src/test/ui/suggestions/issue-90213-expected-boxfuture-self-ice.rs
new file mode 100644 (file)
index 0000000..1e36b2f
--- /dev/null
@@ -0,0 +1,13 @@
+// Checks that we do not ICE when comparing `Self` to `Pin`
+// edition:2021
+
+struct S;
+
+impl S {
+    fn foo(_: Box<Option<S>>) {}
+    fn bar() {
+        Self::foo(None) //~ ERROR mismatched types
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-90213-expected-boxfuture-self-ice.stderr b/src/test/ui/suggestions/issue-90213-expected-boxfuture-self-ice.stderr
new file mode 100644 (file)
index 0000000..c15b772
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-90213-expected-boxfuture-self-ice.rs:9:19
+   |
+LL |         Self::foo(None)
+   |                   ^^^^ expected struct `Box`, found enum `Option`
+   |
+   = note: expected struct `Box<Option<S>>`
+                found enum `Option<_>`
+   = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
+help: store this in the heap by calling `Box::new`
+   |
+LL |         Self::foo(Box::new(None))
+   |                   +++++++++    +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index b579635ca7c08acf337f8c0c9979c9b1f7d566ea..3ed3827b97da3b0b38c2c78a45d214e95ce1fd46 100644 (file)
@@ -1,10 +1,13 @@
 error: lifetime may not live long enough
-  --> $DIR/trait-object-nested-in-impl-trait.rs:27:23
+  --> $DIR/trait-object-nested-in-impl-trait.rs:28:9
    |
-LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
-   |             -         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
-   |             |
-   |             let's call the lifetime of this reference `'1`
+LL |       fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |               - let's call the lifetime of this reference `'1`
+LL | /         Iter {
+LL | |             current: None,
+LL | |             remaining: self.0.iter(),
+LL | |         }
+   | |_________^ returning this value requires that `'1` must outlive `'static`
    |
 help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
    |
@@ -34,12 +37,15 @@ LL | |         }
    | |_________^ returning this value requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/trait-object-nested-in-impl-trait.rs:60:30
+  --> $DIR/trait-object-nested-in-impl-trait.rs:61:9
    |
-LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
-   |             --               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
-   |             |
-   |             lifetime `'a` defined here
+LL |       fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |               -- lifetime `'a` defined here
+LL | /         Iter {
+LL | |             current: None,
+LL | |             remaining: self.0.iter(),
+LL | |         }
+   | |_________^ returning this value requires that `'a` must outlive `'static`
    |
 help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
    |
index 9e0d4ced01153ff3922534683c91555f67573679..0275fd475d8c6a1f5363b5ba7a807884a90c6fa2 100644 (file)
@@ -1,4 +1,4 @@
-error[E0277]: `[i32]` is not an iterator
+error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
   --> $DIR/slice-issue-87994.rs:3:12
    |
 LL |   for _ in v[1..] {
@@ -18,7 +18,7 @@ LL |   for _ in &v[1..] {
 LL |   for _ in &mut v[1..] {
    |            ++++
 
-error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
+error[E0277]: `[i32]` is not an iterator
   --> $DIR/slice-issue-87994.rs:3:12
    |
 LL |   for _ in v[1..] {
@@ -38,7 +38,7 @@ LL |   for _ in &v[1..] {
 LL |   for _ in &mut v[1..] {
    |            ++++
 
-error[E0277]: `[K]` is not an iterator
+error[E0277]: the size for values of type `[K]` cannot be known at compilation time
   --> $DIR/slice-issue-87994.rs:11:13
    |
 LL |   for i2 in v2[1..] {
@@ -58,7 +58,7 @@ LL |   for i2 in &v2[1..] {
 LL |   for i2 in &mut v2[1..] {
    |             ++++
 
-error[E0277]: the size for values of type `[K]` cannot be known at compilation time
+error[E0277]: `[K]` is not an iterator
   --> $DIR/slice-issue-87994.rs:11:13
    |
 LL |   for i2 in v2[1..] {
index 0c91e2feed3ade40afa74bb159f13d3d30438d7a..81f2e498fe5de86e415669c1876aef889155322b 100644 (file)
@@ -6,7 +6,7 @@ LL |     let _ = ||{}();
    |               |
    |               call expression requires function
    |
-help: if you meant to create this closure and immediately call it, surround the closure with parenthesis
+help: if you meant to create this closure and immediately call it, surround the closure with parentheses
    |
 LL |     let _ = (||{})();
    |             +    +
diff --git a/src/test/ui/suggestions/suggest-tryinto-edition-change.rs b/src/test/ui/suggestions/suggest-tryinto-edition-change.rs
new file mode 100644 (file)
index 0000000..f03b42b
--- /dev/null
@@ -0,0 +1,31 @@
+// Make sure that trying to access `TryInto`, `TryFrom`, `FromIterator` in pre-2021 mentions
+// Edition 2021 change
+// edition:2018
+
+fn test() {
+    let _i: i16 = 0_i32.try_into().unwrap();
+    //~^ ERROR no method named `try_into` found for type `i32` in the current scope
+    //~| NOTE method not found in `i32`
+    //~| NOTE 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+
+    let _i: i16 = TryFrom::try_from(0_i32).unwrap();
+    //~^ ERROR failed to resolve: use of undeclared type
+    //~| NOTE not found in this scope
+    //~| NOTE 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
+    //~| NOTE 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
+
+    let _i: i16 = TryInto::try_into(0_i32).unwrap();
+    //~^ ERROR failed to resolve: use of undeclared type
+    //~| NOTE not found in this scope
+    //~| NOTE 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+    //~| NOTE 'core::convert::TryInto' is included in the prelude starting in Edition 2021
+
+    let _v: Vec<_> = FromIterator::from_iter(&[1]);
+    //~^ ERROR failed to resolve: use of undeclared type
+    //~| NOTE 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
+    //~| NOTE 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
+}
+
+fn main() {
+    test();
+}
diff --git a/src/test/ui/suggestions/suggest-tryinto-edition-change.stderr b/src/test/ui/suggestions/suggest-tryinto-edition-change.stderr
new file mode 100644 (file)
index 0000000..86f4871
--- /dev/null
@@ -0,0 +1,76 @@
+error[E0433]: failed to resolve: use of undeclared type `TryFrom`
+  --> $DIR/suggest-tryinto-edition-change.rs:11:19
+   |
+LL |     let _i: i16 = TryFrom::try_from(0_i32).unwrap();
+   |                   ^^^^^^^ not found in this scope
+   |
+   = note: 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
+   = note: 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
+help: consider importing one of these items
+   |
+LL | use core::convert::TryFrom;
+   |
+LL | use std::convert::TryFrom;
+   |
+
+error[E0433]: failed to resolve: use of undeclared type `TryInto`
+  --> $DIR/suggest-tryinto-edition-change.rs:17:19
+   |
+LL |     let _i: i16 = TryInto::try_into(0_i32).unwrap();
+   |                   ^^^^^^^ not found in this scope
+   |
+   = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+   = note: 'core::convert::TryInto' is included in the prelude starting in Edition 2021
+help: consider importing one of these items
+   |
+LL | use core::convert::TryInto;
+   |
+LL | use std::convert::TryInto;
+   |
+
+error[E0433]: failed to resolve: use of undeclared type `FromIterator`
+  --> $DIR/suggest-tryinto-edition-change.rs:23:22
+   |
+LL |     let _v: Vec<_> = FromIterator::from_iter(&[1]);
+   |                      ^^^^^^^^^^^^
+   |
+  ::: $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL | pub trait IntoIterator {
+   | ---------------------- similarly named trait `IntoIterator` defined here
+   |
+   = note: 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
+   = note: 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
+help: a trait with a similar name exists
+   |
+LL |     let _v: Vec<_> = IntoIterator::from_iter(&[1]);
+   |                      ~~~~~~~~~~~~
+help: consider importing one of these items
+   |
+LL | use core::iter::FromIterator;
+   |
+LL | use std::iter::FromIterator;
+   |
+
+error[E0599]: no method named `try_into` found for type `i32` in the current scope
+  --> $DIR/suggest-tryinto-edition-change.rs:6:25
+   |
+LL |     let _i: i16 = 0_i32.try_into().unwrap();
+   |                         ^^^^^^^^ method not found in `i32`
+   |
+  ::: $SRC_DIR/core/src/convert/mod.rs:LL:COL
+   |
+LL |     fn try_into(self) -> Result<T, Self::Error>;
+   |        -------- the method is available for `i32` here
+   |
+   = help: items from traits can only be used if the trait is in scope
+   = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+   |
+LL | use std::convert::TryInto;
+   |
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0433, E0599.
+For more information about an error, try `rustc --explain E0433`.
diff --git a/src/test/ui/suggestions/undeclared-module-alloc.rs b/src/test/ui/suggestions/undeclared-module-alloc.rs
new file mode 100644 (file)
index 0000000..1defa1c
--- /dev/null
@@ -0,0 +1,5 @@
+// edition:2018
+
+use alloc::rc::Rc; //~ ERROR failed to resolve: use of undeclared crate or module `alloc`
+
+fn main() {}
diff --git a/src/test/ui/suggestions/undeclared-module-alloc.stderr b/src/test/ui/suggestions/undeclared-module-alloc.stderr
new file mode 100644 (file)
index 0000000..39169df
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0433]: failed to resolve: use of undeclared crate or module `alloc`
+  --> $DIR/undeclared-module-alloc.rs:3:5
+   |
+LL | use alloc::rc::Rc;
+   |     ^^^^^ use of undeclared crate or module `alloc`
+   |
+   = help: add `extern crate alloc` to use the `alloc` crate
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/trait-bounds/issue-75961.rs b/src/test/ui/trait-bounds/issue-75961.rs
new file mode 100644 (file)
index 0000000..367eac7
--- /dev/null
@@ -0,0 +1,7 @@
+// check-pass
+
+pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
+    <&mut () as Clone>::clone(&s);
+}
+
+fn main() {}
index 4318e07d07a1819e54c9c2cceff064811734bb44..c36ac08579b7798a85b8a935bd1e48acc5ee3c48 100644 (file)
@@ -41,5 +41,5 @@ fn test<X: ?Sized + Send>() {}
 
 fn main() {
     test::<A>();
-    //~^ ERROR evaluate(Binder(TraitPredicate(<A as std::marker::Send>), [])) = Ok(EvaluatedToOk)
+    //~^ ERROR evaluate(Binder(TraitPredicate(<A as std::marker::Send>, polarity:Positive), [])) = Ok(EvaluatedToOk)
 }
index 5e662970bb94c481fa10542331195cd8a84ec6c4..082aa0f5cd93ef74d663f9537b343acc88994c3a 100644 (file)
@@ -1,4 +1,4 @@
-error: evaluate(Binder(TraitPredicate(<A as std::marker::Send>), [])) = Ok(EvaluatedToOk)
+error: evaluate(Binder(TraitPredicate(<A as std::marker::Send>, polarity:Positive), [])) = Ok(EvaluatedToOk)
   --> $DIR/cache-reached-depth-ice.rs:43:5
    |
 LL | fn test<X: ?Sized + Send>() {}
index 23b78d023b600dc8f3665e3a5b6a6ea97eca3599..d1e8affd065f9356e9179a7053bb1670fbb9dfcc 100644 (file)
@@ -5,7 +5,7 @@ LL | #[derive(Clone)]
    |          ----- in this derive macro expansion
 LL | struct FooHolster {
 LL |     the_foos: Vec<Foo>,
-   |     ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone`
+   |     ^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Foo`
    |
    = note: required because of the requirements on the impl of `Clone` for `Vec<Foo>`
 note: required by `clone`
index 03d4fe23cc5bcff87004cfeed8144971e3320d70..f5be6cf21c1cc3dd24a72f1374d7cbfc2900e1a8 100644 (file)
@@ -6,6 +6,7 @@ fn what() {
     let opt = String::new();
 
     opts.get(opt.as_ref()); //~ ERROR type annotations needed
+    //~^ ERROR type annotations needed
 }
 
 fn main() {
index 68347207bda45d10b0a6e046e513b6848c5fa979..e868756504f19f36c5cee4996f42dd1aa60cbf0b 100644 (file)
@@ -6,17 +6,50 @@ LL |     opts.get(opt.as_ref());
    |          |
    |          cannot infer type for type parameter `Q` declared on the associated function `get`
    |
-   = note: cannot satisfy `String: Borrow<_>`
+   = note: multiple `impl`s satisfying `String: Borrow<_>` found in the following crates: `alloc`, `core`:
+           - impl Borrow<str> for String;
+           - impl<T> Borrow<T> for T
+             where T: ?Sized;
 
 error[E0283]: type annotations needed
-  --> $DIR/issue-77982.rs:12:44
+  --> $DIR/issue-77982.rs:8:18
+   |
+LL |     opts.get(opt.as_ref());
+   |              ----^^^^^^--
+   |              |   |
+   |              |   cannot infer type for type parameter `T` declared on the trait `AsRef`
+   |              this method call resolves to `&T`
+   |
+   = note: multiple `impl`s satisfying `String: AsRef<_>` found in the following crates: `alloc`, `std`:
+           - impl AsRef<OsStr> for String;
+           - impl AsRef<Path> for String;
+           - impl AsRef<[u8]> for String;
+           - impl AsRef<str> for String;
+help: use the fully qualified path for the potential candidates
+   |
+LL |     opts.get(<String as AsRef<OsStr>>::as_ref(opt));
+   |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     opts.get(<String as AsRef<Path>>::as_ref(opt));
+   |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     opts.get(<String as AsRef<[u8]>>::as_ref(opt));
+   |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     opts.get(<String as AsRef<str>>::as_ref(opt));
+   |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0283]: type annotations needed
+  --> $DIR/issue-77982.rs:13:44
    |
 LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect();
    |                                            ^^^^^^^^^ ----------- this method call resolves to `T`
    |                                            |
    |                                            cannot infer type for type parameter `T` declared on the trait `From`
    |
-   = note: cannot satisfy `u32: From<_>`
+   = note: multiple `impl`s satisfying `u32: From<_>` found in the following crates: `core`, `std`:
+           - impl From<Ipv4Addr> for u32;
+           - impl From<NonZeroU32> for u32;
+           - impl From<bool> for u32;
+           - impl From<char> for u32;
+           and 3 more
 note: required by `from`
   --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
    |
@@ -24,25 +57,37 @@ LL |     fn from(_: T) -> Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0283]: type annotations needed for `Box<T>`
-  --> $DIR/issue-77982.rs:35:16
+  --> $DIR/issue-77982.rs:36:16
    |
 LL |     let _ = ().foo();
    |         -      ^^^ cannot infer type for type parameter `T` declared on the trait `Foo`
    |         |
    |         consider giving this pattern the explicit type `Box<T>`, where the type parameter `T` is specified
    |
-   = note: cannot satisfy `(): Foo<'_, _>`
+note: multiple `impl`s satisfying `(): Foo<'_, _>` found
+  --> $DIR/issue-77982.rs:29:1
+   |
+LL | impl Foo<'static, u32> for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<'a> Foo<'a, i16> for () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0283]: type annotations needed for `Box<T>`
-  --> $DIR/issue-77982.rs:39:19
+  --> $DIR/issue-77982.rs:40:19
    |
 LL |     let _ = (&()).bar();
    |         -         ^^^ cannot infer type for type parameter `T` declared on the trait `Bar`
    |         |
    |         consider giving this pattern the explicit type `Box<T>`, where the type parameter `T` is specified
    |
-   = note: cannot satisfy `&(): Bar<'_, _>`
+note: multiple `impl`s satisfying `&(): Bar<'_, _>` found
+  --> $DIR/issue-77982.rs:32:1
+   |
+LL | impl<'a> Bar<'static, u32> for &'a () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<'a> Bar<'a, i16> for &'a () {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0283`.
index 1be0b05fa2b8c25a753cff2b82e3abe610bcf7a7..3cd68ff6f060e9ef6cc64c8ad71f69c9a3b91a16 100644 (file)
@@ -57,10 +57,10 @@ fn main() {
     // Key is that Vec<First> is "ok" and Third<'_, Ty> is "ok modulo regions":
 
     forward();
-    //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
-    //~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+    //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+    //~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
 
     reverse();
-    //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
-    //~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+    //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+    //~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
 }
index 43acc66fd73cbb00a589f918c15cd1357b61eee0..7c4041144a4d24092de52942fea93da67ea48317 100644 (file)
@@ -1,4 +1,4 @@
-error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
+error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
   --> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5
    |
 LL |     Vec<First>: Unpin,
@@ -7,7 +7,7 @@ LL |     Vec<First>: Unpin,
 LL |     forward();
    |     ^^^^^^^
 
-error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
   --> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5
    |
 LL |     Third<'a, Ty>: Unpin,
@@ -16,7 +16,7 @@ LL |     Third<'a, Ty>: Unpin,
 LL |     forward();
    |     ^^^^^^^
 
-error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
   --> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5
    |
 LL |     Third<'a, Ty>: Unpin,
@@ -25,7 +25,7 @@ LL |     Third<'a, Ty>: Unpin,
 LL |     reverse();
    |     ^^^^^^^
 
-error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
+error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
   --> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5
    |
 LL |     Vec<First>: Unpin,
diff --git a/src/test/ui/traits/issue-90195-2.rs b/src/test/ui/traits/issue-90195-2.rs
new file mode 100644 (file)
index 0000000..b739dc4
--- /dev/null
@@ -0,0 +1,20 @@
+// check-pass
+pub trait Archive {
+    type Archived;
+}
+
+impl<T> Archive for Option<T> {
+    type Archived = ();
+}
+pub type Archived<T> = <T as Archive>::Archived;
+
+pub trait Deserialize<D> {}
+
+const ARRAY_SIZE: usize = 32;
+impl<__D> Deserialize<__D> for ()
+where
+    Option<[u8; ARRAY_SIZE]>: Archive,
+    Archived<Option<[u8; ARRAY_SIZE]>>: Deserialize<__D>,
+{
+}
+fn main() {}
diff --git a/src/test/ui/traits/issue-90195.rs b/src/test/ui/traits/issue-90195.rs
new file mode 100644 (file)
index 0000000..543c9f1
--- /dev/null
@@ -0,0 +1,21 @@
+// check-pass
+pub trait Archive {
+    type Archived;
+}
+
+impl<T> Archive for Option<T> {
+    type Archived = ();
+}
+pub type Archived<T> = <T as Archive>::Archived;
+
+pub trait Deserialize<D> {}
+
+const ARRAY_SIZE: usize = 32;
+impl<__D> Deserialize<__D> for ()
+where
+    Option<[u8; ARRAY_SIZE]>: Archive,
+    Option<[u8; ARRAY_SIZE]>: Archive,
+    Archived<Option<[u8; ARRAY_SIZE]>>: Deserialize<__D>,
+{
+}
+fn main() {}
index 58cb69a05b7048295d2832c849ac5658b8f07f22..aa74e11c36256d847e0393c64aa4f4ecf274e06d 100644 (file)
@@ -24,7 +24,8 @@ fn test<T,U>(_: T, _: U)
 
 fn a() {
     test(22, std::default::Default::default());
-    //~^ ERROR type annotations needed [E0282]
+    //~^ ERROR type annotations needed
+    //~| ERROR type annotations needed
 }
 
 fn main() {}
index 62f5f5aaa88e06b137405eac9056e8380eb44802..9fd81b56bf153c34ff62aa8ce02ec03769da88b2 100644 (file)
@@ -4,6 +4,33 @@ error[E0282]: type annotations needed
 LL |     test(22, std::default::Default::default());
    |     ^^^^ cannot infer type for type parameter `U` declared on the function `test`
 
-error: aborting due to previous error
+error[E0283]: type annotations needed
+  --> $DIR/multidispatch-convert-ambig-dest.rs:26:5
+   |
+LL |     test(22, std::default::Default::default());
+   |     ^^^^ cannot infer type for type parameter `U` declared on the function `test`
+   |
+note: multiple `impl`s satisfying `i32: Convert<_>` found
+  --> $DIR/multidispatch-convert-ambig-dest.rs:8:1
+   |
+LL | impl Convert<i8> for i32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Convert<i16> for i32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `test`
+  --> $DIR/multidispatch-convert-ambig-dest.rs:21:11
+   |
+LL | fn test<T,U>(_: T, _: U)
+   |    ---- required by a bound in this
+LL | where T : Convert<U>
+   |           ^^^^^^^^^^ required by this bound in `test`
+help: consider specifying the type arguments in the function call
+   |
+LL |     test::<T, U>(22, std::default::Default::default());
+   |         ++++++++
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0282`.
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
index 8059a8ca71e43b0697eda08692317a7f2c6564f2..1cf73fcdebd0b9985a05dd07f3dfab5bff602d5a 100644 (file)
@@ -49,7 +49,7 @@ LL |     is_send((8, TestType));
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Send` is not implemented for `dummy1c::TestType`
+   = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType`
    = note: required because it appears within the type `({integer}, dummy1c::TestType)`
 note: required by a bound in `is_send`
   --> $DIR/negated-auto-traits-error.rs:16:15
@@ -86,7 +86,7 @@ LL |     is_send(Box::new(Outer2(TestType)));
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Send` is not implemented for `dummy3::TestType`
+   = help: within `Outer2<dummy3::TestType>`, the trait `Send` is not implemented for `dummy3::TestType`
 note: required because it appears within the type `Outer2<dummy3::TestType>`
   --> $DIR/negated-auto-traits-error.rs:12:8
    |
index db72aaf18034f3a6ec177f7f1cd52c8ff85255a7..119ac05c33e4b4442ee9c47b0c2baedbd87af17d 100644 (file)
@@ -1,3 +1,5 @@
+// check-pass
+
 #![feature(negative_impls)]
 
 // aux-build: foreign_trait.rs
@@ -16,6 +18,6 @@
 
 trait LocalTrait { }
 impl<T: ForeignTrait> LocalTrait for T { }
-impl LocalTrait for String { } //~ ERROR conflicting implementations
+impl LocalTrait for String { }
 
 fn main() { }
diff --git a/src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.stderr b/src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.stderr
deleted file mode 100644 (file)
index b970ad7..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0119]: conflicting implementations of trait `LocalTrait` for type `std::string::String`
-  --> $DIR/rely-on-negative-impl-in-coherence.rs:19:1
-   |
-LL | impl<T: ForeignTrait> LocalTrait for T { }
-   | -------------------------------------- first implementation here
-LL | impl LocalTrait for String { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `std::string::String`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0119`.
index 763fb5186cc9a480f0dcda2b03e7ec037f87361a..118b2cf3ecd857a2a3f6d5a43c5cc182927345a6 100644 (file)
@@ -2,13 +2,13 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/param-without-lifetime-constraint.rs:14:5
    |
 LL |     fn get_relation(&self) -> To;
-   |     ----------------------------- expected `fn(&Article) -> &ProofReader`
+   |     ----------------------------- expected `fn(&'1 Article) -> &'2 ProofReader`
 ...
 LL |     fn get_relation(&self) -> &ProofReader {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Article) -> &'1 ProofReader`
    |
-   = note: expected `fn(&Article) -> &ProofReader`
-              found `fn(&Article) -> &ProofReader`
+   = note: expected `fn(&'1 Article) -> &'2 ProofReader`
+              found `fn(&'1 Article) -> &'1 ProofReader`
 help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
   --> $DIR/param-without-lifetime-constraint.rs:10:31
    |
index 73b5aec022c6013c4fa590edb7203195b12e0997..85fada3b87c38a6cb8a50d18d6659f97c32d12ed 100644 (file)
@@ -2,13 +2,13 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/self-without-lifetime-constraint.rs:45:5
    |
 LL |     fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
-   |     -------------------------------------------------------------------- expected `fn(ValueRef<'_>) -> Result<(&str, &&str), FromSqlError>`
+   |     -------------------------------------------------------------------- expected `fn(ValueRef<'1>) -> Result<(&'2 str, &'1 &'2 str), FromSqlError>`
 ...
 LL |     fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'_>) -> Result<(&str, &&str), FromSqlError>`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'1>) -> Result<(&'1 str, &'1 &'1 str), FromSqlError>`
    |
-   = note: expected `fn(ValueRef<'_>) -> Result<(&str, &&str), _>`
-              found `fn(ValueRef<'_>) -> Result<(&str, &&str), _>`
+   = note: expected `fn(ValueRef<'1>) -> Result<(&'2 str, &'1 &'2 str), FromSqlError>`
+              found `fn(ValueRef<'1>) -> Result<(&'1 str, &'1 &'1 str), FromSqlError>`
 help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
   --> $DIR/self-without-lifetime-constraint.rs:41:60
    |
index 342928e882a556e0e9a8958041284e945a14ee6a..d062de25ac8c1d0bb5d3485ba53c12b888640d91 100644 (file)
@@ -6,9 +6,9 @@ impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
 impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
 
 fn main() {
-    10.dup::<i32>();
+    10.dup::<i32>(); //~ ERROR type annotations needed
     //~^ ERROR this associated function takes 0 generic arguments but 1
-    10.blah::<i32, i32>();
+    10.blah::<i32, i32>(); //~ ERROR type annotations needed
     //~^ ERROR this associated function takes 1 generic argument but 2
     (Box::new(10) as Box<dyn bar>).dup();
     //~^ ERROR E0038
index 77ea4e4e974ebf06c36175f8cd48d50821840f0c..5eec012458450af92fef905ae1913d529728b537 100644 (file)
@@ -79,7 +79,35 @@ LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
    = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn bar>>` for `Box<{integer}>`
    = note: required by cast to type `Box<dyn bar>`
 
-error: aborting due to 5 previous errors
+error[E0283]: type annotations needed
+  --> $DIR/test-2.rs:9:8
+   |
+LL |     10.dup::<i32>();
+   |        ^^^ cannot infer type for type `{integer}`
+   |
+note: multiple `impl`s satisfying `{integer}: bar` found
+  --> $DIR/test-2.rs:5:1
+   |
+LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
+   | ^^^^^^^^^^^^^^^^
+LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
+   | ^^^^^^^^^^^^^^^^
+
+error[E0283]: type annotations needed
+  --> $DIR/test-2.rs:11:8
+   |
+LL |     10.blah::<i32, i32>();
+   |        ^^^^ cannot infer type for type `{integer}`
+   |
+note: multiple `impl`s satisfying `{integer}: bar` found
+  --> $DIR/test-2.rs:5:1
+   |
+LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
+   | ^^^^^^^^^^^^^^^^
+LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
+   | ^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0038, E0107.
+Some errors have detailed explanations: E0038, E0107, E0283.
 For more information about an error, try `rustc --explain E0038`.
index 2e12b768f706693e3251b42c0082ffaca13d9402..e918551020c313ea09702b8f6abd877311c9cdb0 100644 (file)
@@ -27,7 +27,7 @@ LL |     Alias::Unit();
    |     |
    |     call expression requires function
    |
-help: `Alias::Unit` is a unit variant, you need to write it without the parenthesis
+help: `Alias::Unit` is a unit variant, you need to write it without the parentheses
    |
 LL |     Alias::Unit;
    |     ~~~~~~~~~~~
index d60be4b1ccf9ca04289899c22b46222d5484dde4..4a49d6e4ab8fd7aaac23229cdcfea5e659138662 100644 (file)
@@ -1,11 +1,13 @@
 error[E0277]: `Rc<u32>` cannot be sent between threads safely
-  --> $DIR/auto-trait-leakage2.rs:17:5
+  --> $DIR/auto-trait-leakage2.rs:17:13
    |
 LL |     type Foo = impl std::fmt::Debug;
    |                -------------------- within this `impl Debug`
 ...
 LL |     is_send(m::foo());
-   |     ^^^^^^^ `Rc<u32>` cannot be sent between threads safely
+   |     ------- ^^^^^^^^ `Rc<u32>` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: within `impl Debug`, the trait `Send` is not implemented for `Rc<u32>`
    = note: required because it appears within the type `impl Debug`
index 4baf198b12fae9251139cd00db67c64a0fec14d5..747081933172b50aca38ca1e5efeaca93a347e5b 100644 (file)
@@ -5,7 +5,7 @@
 fn main() {}
 
 type Two<A, B> = impl Debug;
-//~^ ERROR the trait bound `A: Foo` is not satisfied
+//~^ ERROR the trait bound `A: Foo` is not satisfied in `(A, B, <A as Foo>::Bar)`
 //~| ERROR `A` doesn't implement `Debug`
 //~| ERROR `B` doesn't implement `Debug`
 
index f21e036edc2ca11a1d6479a7ce666f976c20976b..a8eb53a50e38bb33d99f2256d7c3d58739878055 100644 (file)
@@ -10,6 +10,18 @@ note: previous use here
 LL | fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0277]: the trait bound `A: Foo` is not satisfied in `(A, B, <A as Foo>::Bar)`
+  --> $DIR/generic_duplicate_param_use9.rs:7:18
+   |
+LL | type Two<A, B> = impl Debug;
+   |                  ^^^^^^^^^^ within `(A, B, <A as Foo>::Bar)`, the trait `Foo` is not implemented for `A`
+   |
+   = note: required because it appears within the type `(A, B, <A as Foo>::Bar)`
+help: consider restricting type parameter `A`
+   |
+LL | type Two<A: Foo, B> = impl Debug;
+   |           +++++
+
 error[E0277]: `A` doesn't implement `Debug`
   --> $DIR/generic_duplicate_param_use9.rs:7:18
    |
@@ -34,18 +46,6 @@ help: consider restricting type parameter `B`
 LL | type Two<A, B: std::fmt::Debug> = impl Debug;
    |              +++++++++++++++++
 
-error[E0277]: the trait bound `A: Foo` is not satisfied
-  --> $DIR/generic_duplicate_param_use9.rs:7:18
-   |
-LL | type Two<A, B> = impl Debug;
-   |                  ^^^^^^^^^^ the trait `Foo` is not implemented for `A`
-   |
-   = note: required because of the requirements on the impl of `Debug` for `(A, B, <A as Foo>::Bar)`
-help: consider restricting type parameter `A`
-   |
-LL | type Two<A: Foo, B> = impl Debug;
-   |           +++++
-
 error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-89686.rs b/src/test/ui/type-alias-impl-trait/issue-89686.rs
new file mode 100644 (file)
index 0000000..2b6ce49
--- /dev/null
@@ -0,0 +1,24 @@
+// edition:2018
+
+#![feature(type_alias_impl_trait)]
+
+use std::future::Future;
+
+type G<'a, T> = impl Future<Output = ()>;
+//~^ ERROR: type mismatch resolving `<impl Future as Future>::Output == ()`
+//~| ERROR: the trait bound `T: Trait` is not satisfied
+
+trait Trait {
+    type F: Future<Output = ()>;
+
+    fn f(&self) -> Self::F;
+
+    fn g<'a>(&'a self) -> G<'a, Self>
+    where
+        Self: Sized,
+    {
+        async move { self.f().await }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-89686.stderr b/src/test/ui/type-alias-impl-trait/issue-89686.stderr
new file mode 100644 (file)
index 0000000..accc84d
--- /dev/null
@@ -0,0 +1,34 @@
+error[E0271]: type mismatch resolving `<impl Future as Future>::Output == ()`
+  --> $DIR/issue-89686.rs:7:17
+   |
+LL | type G<'a, T> = impl Future<Output = ()>;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+...
+LL |         async move { self.f().await }
+   |                    ------------------ the found `async` block
+   |
+  ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
+   |
+LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
+   |                                           ------------------------------- the found opaque type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl Future as Future>::Output`
+   = help: consider constraining the associated type `<impl Future as Future>::Output` to `()`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0277]: the trait bound `T: Trait` is not satisfied
+  --> $DIR/issue-89686.rs:7:17
+   |
+LL | type G<'a, T> = impl Future<Output = ()>;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | type G<'a, T: Trait> = impl Future<Output = ()>;
+   |             +++++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/typeck/issue-89806.rs b/src/test/ui/typeck/issue-89806.rs
new file mode 100644 (file)
index 0000000..69cec08
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    0u8.as_ref(); //~ ERROR no method named `as_ref` found for type `u8` in the current scope
+}
diff --git a/src/test/ui/typeck/issue-89806.stderr b/src/test/ui/typeck/issue-89806.stderr
new file mode 100644 (file)
index 0000000..c36b496
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0599]: no method named `as_ref` found for type `u8` in the current scope
+  --> $DIR/issue-89806.rs:2:9
+   |
+LL |     0u8.as_ref();
+   |         ^^^^^^ method not found in `u8`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/typeck/issue-89935.rs b/src/test/ui/typeck/issue-89935.rs
new file mode 100644 (file)
index 0000000..03f8f09
--- /dev/null
@@ -0,0 +1,18 @@
+// check-pass
+
+trait Foo: Baz {}
+trait Bar {}
+trait Baz: Bar {
+    fn bar(&self);
+}
+
+impl<T: Foo> Bar for T {}
+impl<T: Foo> Baz for T {
+    fn bar(&self) {}
+}
+
+fn accept_foo(x: Box<dyn Foo>) {
+    x.bar();
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-90101.rs b/src/test/ui/typeck/issue-90101.rs
new file mode 100644 (file)
index 0000000..1954ee6
--- /dev/null
@@ -0,0 +1,8 @@
+use std::path::{Path, PathBuf};
+
+fn func(path: impl Into<PathBuf>, code: impl Into<String>) {}
+
+fn main() {
+    func(Path::new("hello").to_path_buf().to_string_lossy(), "world")
+    //~^ ERROR [E0277]
+}
diff --git a/src/test/ui/typeck/issue-90101.stderr b/src/test/ui/typeck/issue-90101.stderr
new file mode 100644 (file)
index 0000000..998b636
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0277]: the trait bound `PathBuf: From<Cow<'_, str>>` is not satisfied
+  --> $DIR/issue-90101.rs:6:10
+   |
+LL |     func(Path::new("hello").to_path_buf().to_string_lossy(), "world")
+   |     ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<Cow<'_, str>>` is not implemented for `PathBuf`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the following implementations were found:
+             <PathBuf as From<&T>>
+             <PathBuf as From<Box<Path>>>
+             <PathBuf as From<Cow<'a, Path>>>
+             <PathBuf as From<OsString>>
+             <PathBuf as From<String>>
+   = note: required because of the requirements on the impl of `Into<PathBuf>` for `Cow<'_, str>`
+note: required by a bound in `func`
+  --> $DIR/issue-90101.rs:3:20
+   |
+LL | fn func(path: impl Into<PathBuf>, code: impl Into<String>) {}
+   |                    ^^^^^^^^^^^^^ required by this bound in `func`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/typeck/issue-90164.rs b/src/test/ui/typeck/issue-90164.rs
new file mode 100644 (file)
index 0000000..6335043
--- /dev/null
@@ -0,0 +1,9 @@
+fn copy<R: Unpin, W>(_: R, _: W) {}
+
+fn f<T>(r: T) {
+    let w = ();
+    copy(r, w);
+    //~^ ERROR [E0277]
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-90164.stderr b/src/test/ui/typeck/issue-90164.stderr
new file mode 100644 (file)
index 0000000..1e2f1ba
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0277]: `T` cannot be unpinned
+  --> $DIR/issue-90164.rs:5:10
+   |
+LL |     copy(r, w);
+   |     ---- ^ the trait `Unpin` is not implemented for `T`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: consider using `Box::pin`
+note: required by a bound in `copy`
+  --> $DIR/issue-90164.rs:1:12
+   |
+LL | fn copy<R: Unpin, W>(_: R, _: W) {}
+   |            ^^^^^ required by this bound in `copy`
+help: consider restricting type parameter `T`
+   |
+LL | fn f<T: std::marker::Unpin>(r: T) {
+   |       ++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 4b5804253b23b7efa555e35ce0ff0601eab5bc97..154e504996bc4001d441b668cebd388fd3e03f48 100644 (file)
@@ -29,10 +29,12 @@ LL | fn test<T: Sync>(s: T) {}
    |            ^^^^ required by this bound in `test`
 
 error[E0277]: `UnsafeCell<NoSync>` cannot be shared between threads safely
-  --> $DIR/typeck-unsafe-always-share.rs:27:5
+  --> $DIR/typeck-unsafe-always-share.rs:27:10
    |
 LL |     test(ms);
-   |     ^^^^ `UnsafeCell<NoSync>` cannot be shared between threads safely
+   |     ---- ^^ `UnsafeCell<NoSync>` cannot be shared between threads safely
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: within `MySync<NoSync>`, the trait `Sync` is not implemented for `UnsafeCell<NoSync>`
 note: required because it appears within the type `MySync<NoSync>`
index 76c14ccc14b4522906c1821bb06a5ec6c26b9572..8976da01e739beba94204208bf2482f6543e3b42 100644 (file)
@@ -5,6 +5,12 @@ LL | fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); }
    |                    ------      ------           ^ ...but data from `y` flows into `x` here
    |                                |
    |                                these two types are declared with different lifetimes...
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+   |       ++++              ~~          ~~
 
 error: aborting due to previous error
 
index e4e8b32c70ee9a1d6907d9d45adfb223861375a4..dcf0eb646f3b0591a1df8b2cbb9dac1cfc46faa0 100644 (file)
@@ -44,10 +44,10 @@ pub fn std() {}
 
 fn main() {
     foo::Foo(());
-    foo::std_io::stdout();
+    let _ = foo::std_io::stdout();
     foo::local_io(());
-    io::stdout();
-    bar::io::stdout();
+    let _ = io::stdout();
+    let _ = bar::io::stdout();
     bar::std();
     bar::std!();
 
@@ -56,6 +56,6 @@ fn main() {
         // scope is allowed, when both resolve to the same definition.
         use std::io;
         use io::stdout;
-        stdout();
+        let _ = stdout();
     }
 }
index 4e2e2dedef67924c9bb265bbba87d59500b691f1..ce611a7cacf38b887614240e2cfea8e076f86c5a 100644 (file)
@@ -20,7 +20,7 @@ mod std {
 
 fn main() {
     Foo(());
-    std_io::stdout();
+    let _ = std_io::stdout();
     local_io(());
 
     {
@@ -28,6 +28,6 @@ fn main() {
         // scope is allowed, when both resolve to the same definition.
         use ::std::io as std_io;
         use std_io::stdout;
-        stdout();
+        let _ = stdout();
     }
 }
index a62a28bb94d12681bf90d7ff97bfd750b914cfa4..175ccd34e98d92116d433f23bc2e15ab2720b269 100644 (file)
@@ -46,8 +46,8 @@ mod bar {
 
 fn main() {
     foo::Foo(());
-    foo::std_io::stdout();
+    let _ = foo::std_io::stdout();
     foo::local_io(());
-    io::stdout();
-    bar::io::stdout();
+    let _ = io::stdout();
+    let _ = bar::io::stdout();
 }
index 31b809f0cfdc5f2a5ad39ad08a64ca302017e2b9..bf512b30560eb7ebd8cb1b2c1d99800d47a4325d 100644 (file)
@@ -31,6 +31,6 @@ mod std {
 
 fn main() {
     Foo(());
-    std_io::stdout();
+    let _ = std_io::stdout();
     local_io(());
 }
index 8626b726f47c45c390ced7879688fbe5aae538e5..5c40787febfb76498c19eff2762d28aa7f36af45 100644 (file)
@@ -19,10 +19,10 @@ LL | | >(Unique<T>, A);
    | |________________- doesn't satisfy `Box<dyn Foo>: Clone`
    |
    = note: the following trait bounds were not satisfied:
-           `dyn Foo: Clone`
-           which is required by `Box<dyn Foo>: Clone`
            `dyn Foo: Sized`
            which is required by `Box<dyn Foo>: Clone`
+           `dyn Foo: Clone`
+           which is required by `Box<dyn Foo>: Clone`
 
 error: aborting due to previous error
 
index 6686e55130fb453579d774d736238a9282612281..6960255d98797492815899c0bebc915e1feedd59 100644 (file)
@@ -16,7 +16,7 @@ LL |     udrop::<A<[u8]>>(A { 0: *foo() });
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Sized` is not implemented for `[u8]`
+   = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]`
 note: required because it appears within the type `A<[u8]>`
   --> $DIR/unsized-exprs.rs:3:8
    |
index 83199e8112e71d2ad12245d61793e49d91e142bc..93c7af68ac388e145714fe11c473d29eb0b5b16b 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(relaxed_struct_unsize)]
 // run-pass
 // Test that we allow unsizing even if there is an unchanged param in the
 // field getting unsized.
index 0dd439e14e3cd390b79961d164999b9361eaafa9..531e9b4c9c95533194bdb40bbbb245e58f2c400b 100644 (file)
@@ -7,10 +7,10 @@ LL | fn foo<T: ?Sized>() { bar::<T>() }
    |        this type parameter needs to be `std::marker::Sized`
    |
 note: required by a bound in `bar`
-  --> $DIR/unsized-bare-typaram.rs:1:11
+  --> $DIR/unsized-bare-typaram.rs:1:8
    |
 LL | fn bar<T: Sized>() { }
-   |           ^^^^^ required by this bound in `bar`
+   |        ^ required by this bound in `bar`
 help: consider removing the `?Sized` bound to make the type parameter `Sized`
    |
 LL - fn foo<T: ?Sized>() { bar::<T>() }
index 88ba7567402db12d046b225859d026f361d15eb3..1c70a840c77dc382553fb5be30e2f1e4f68b9ef7 100644 (file)
@@ -38,10 +38,10 @@ note: required because it appears within the type `Bar<T>`
 LL | struct Bar<T: ?Sized> { data: T }
    |        ^^^
 note: required by a bound in `is_sized`
-  --> $DIR/unsized-struct.rs:1:15
+  --> $DIR/unsized-struct.rs:1:13
    |
 LL | fn is_sized<T:Sized>() { }
-   |               ^^^^^ required by this bound in `is_sized`
+   |             ^ required by this bound in `is_sized`
 help: consider removing the `?Sized` bound to make the type parameter `Sized`
    |
 LL - fn bar2<T: ?Sized>() { is_sized::<Bar<T>>() }
index 9339a004d3b742bf138b79f0c3014e08737d72c5..6ac558974d0c5476e6a606ffe3006a0b050607ac 100644 (file)
@@ -1,7 +1,7 @@
 // --extern-location with a raw reference
 
 // aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar
+// compile-flags:--extern-location bar -Zunstable-options
 
 #![warn(unused_crate_dependencies)]
 
diff --git a/src/test/ui/variance/variance-associated-consts.rs b/src/test/ui/variance/variance-associated-consts.rs
new file mode 100644 (file)
index 0000000..da55bc9
--- /dev/null
@@ -0,0 +1,17 @@
+// Test that the variance computation considers types that
+// appear in const expressions to be invariant.
+
+#![feature(rustc_attrs)]
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+trait Trait {
+    const Const: usize;
+}
+
+#[rustc_variance]
+struct Foo<T: Trait> { //~ ERROR [o]
+    field: [u8; <T as Trait>::Const]
+}
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-associated-consts.stderr b/src/test/ui/variance/variance-associated-consts.stderr
new file mode 100644 (file)
index 0000000..d1bf347
--- /dev/null
@@ -0,0 +1,10 @@
+error[E0208]: [o]
+  --> $DIR/variance-associated-consts.rs:13:1
+   |
+LL | / struct Foo<T: Trait> {
+LL | |     field: [u8; <T as Trait>::Const]
+LL | | }
+   | |_^
+
+error: aborting due to previous error
+
index 96d3c873843318e3bff6d9d60ccd1a69c92c7166..d6364e28fef97f2394694d80e550419ea16f25b2 100644 (file)
@@ -196,7 +196,6 @@ struct ManifestPackage {
 
 #[derive(Debug, serde::Deserialize)]
 struct ManifestTargetPackage {
-    available: bool,
     url: Option<String>,
     hash: Option<String>,
     xz_url: Option<String>,
index c7957a74bdcf3b11e7154c1a9401735f23ebd484..94ca096afbf25f670e76e07dca754fcfe27134be 160000 (submodule)
@@ -1 +1 @@
-Subproject commit c7957a74bdcf3b11e7154c1a9401735f23ebd484
+Subproject commit 94ca096afbf25f670e76e07dca754fcfe27134be
diff --git a/src/tools/clippy/.cargo/config b/src/tools/clippy/.cargo/config
deleted file mode 100644 (file)
index 688473f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-[alias]
-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"
-
-[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"
diff --git a/src/tools/clippy/.cargo/config.toml b/src/tools/clippy/.cargo/config.toml
new file mode 100644 (file)
index 0000000..688473f
--- /dev/null
@@ -0,0 +1,10 @@
+[alias]
+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"
+
+[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"
index a3c57232f557c4b774cb53ecc7e10299db1bd8e6..34225a5402904084617e9f19adaaa762d0aa5336 100644 (file)
@@ -13,7 +13,8 @@ cp util/gh-pages/lints.json out/master
 if [[ -n $TAG_NAME ]]; then
   echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it"
   cp -Tr out/master "out/$TAG_NAME"
-  ln -sf "$TAG_NAME" out/stable
+  rm -f out/stable
+  ln -s "$TAG_NAME" out/stable
 fi
 
 if [[ $BETA = "true" ]]; then
index e700e5f0d736e7ca056dc0fdf0a355c429c07d38..85a6a6be8b7f2618d9b515afc201e54f27781e13 100644 (file)
@@ -6,11 +6,162 @@ document.
 
 ## Unreleased / In Rust Nightly
 
-[7bfc26e...master](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...master)
+[b7f3f7f...master](https://github.com/rust-lang/rust-clippy/compare/b7f3f7f...master)
+
+## Rust 1.57
+
+Current beta, release 2021-12-02
+
+[7bfc26e...b7f3f7f](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...b7f3f7f)
+
+### New Lints
+
+* [`negative_feature_names`]
+  [#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
+* [`redundant_feature_names`]
+  [#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
+* [`mod_module_files`]
+  [#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
+* [`self_named_module_files`]
+  [#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
+* [`manual_split_once`]
+  [#7565](https://github.com/rust-lang/rust-clippy/pull/7565)
+* [`derivable_impls`]
+  [#7570](https://github.com/rust-lang/rust-clippy/pull/7570)
+* [`needless_option_as_deref`]
+  [#7596](https://github.com/rust-lang/rust-clippy/pull/7596)
+* [`iter_not_returning_iterator`]
+  [#7610](https://github.com/rust-lang/rust-clippy/pull/7610)
+* [`same_name_method`]
+  [#7653](https://github.com/rust-lang/rust-clippy/pull/7653)
+* [`manual_assert`] [#7669](https://github.com/rust-lang/rust-clippy/pull/7669)
+* [`non_send_fields_in_send_ty`]
+  [#7709](https://github.com/rust-lang/rust-clippy/pull/7709)
+* [`equatable_if_let`]
+  [#7762](https://github.com/rust-lang/rust-clippy/pull/7762)
+
+### Moves and Deprecations
+
+* Move [`shadow_unrelated`] to `restriction`
+  [#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
+* Move [`option_if_let_else`] to `nursery`
+  [#7568](https://github.com/rust-lang/rust-clippy/pull/7568)
+* Move [`branches_sharing_code`] to `nursery`
+  [#7595](https://github.com/rust-lang/rust-clippy/pull/7595)
+* Rename `if_let_some_result` to [`match_result_ok`] which now also handles
+  `while let` cases [#7608](https://github.com/rust-lang/rust-clippy/pull/7608)
+* Move [`many_single_char_names`] to `pedantic`
+  [#7671](https://github.com/rust-lang/rust-clippy/pull/7671)
+* Move [`float_cmp`] to `pedantic`
+  [#7692](https://github.com/rust-lang/rust-clippy/pull/7692)
+* Rename `box_vec` to [`box_collection`] and lint on more general cases
+  [#7693](https://github.com/rust-lang/rust-clippy/pull/7693)
+* Uplift `invalid_atomic_ordering` to rustc
+  [rust-lang/rust#84039](https://github.com/rust-lang/rust/pull/84039)
+
+### Enhancements
+
+* Rewrite the `shadow*` lints, so that they find a lot more shadows and are not
+  limited to certain patterns
+  [#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
+* The `avoid-breaking-exported-api` configuration now also works for
+  [`box_collection`], [`redundant_allocation`], [`rc_buffer`], [`vec_box`],
+  [`option_option`], [`linkedlist`], [`rc_mutex`]
+  [#7560](https://github.com/rust-lang/rust-clippy/pull/7560)
+* [`unnecessary_unwrap`]: Now also checks for `expect`s
+  [#7584](https://github.com/rust-lang/rust-clippy/pull/7584)
+* [`disallowed_method`]: Allow adding a reason that will be displayed with the
+  lint message
+  [#7621](https://github.com/rust-lang/rust-clippy/pull/7621)
+* [`approx_constant`]: Now checks the MSRV for `LOG10_2` and `LOG2_10`
+  [#7629](https://github.com/rust-lang/rust-clippy/pull/7629)
+* [`approx_constant`]: Add `TAU`
+  [#7642](https://github.com/rust-lang/rust-clippy/pull/7642)
+* [`needless_borrow`]: Now also lints on needless mutable borrows
+  [#7657](https://github.com/rust-lang/rust-clippy/pull/7657)
+* [`missing_safety_doc`]: Now also lints on unsafe traits
+  [#7734](https://github.com/rust-lang/rust-clippy/pull/7734)
+
+### False Positive Fixes
+
+* [`manual_map`]: No longer lints when the option is borrowed in the match and
+  also consumed in the arm
+  [#7531](https://github.com/rust-lang/rust-clippy/pull/7531)
+* [`filter_next`]: No longer lints if `filter` method is not the
+  `Iterator::filter` method
+  [#7562](https://github.com/rust-lang/rust-clippy/pull/7562)
+* [`manual_flatten`]: No longer lints if expression is used after `if let`
+  [#7566](https://github.com/rust-lang/rust-clippy/pull/7566)
+* [`option_if_let_else`]: Multiple fixes
+  [#7573](https://github.com/rust-lang/rust-clippy/pull/7573)
+    * `break` and `continue` statements local to the would-be closure are
+      allowed
+    * Don't lint in const contexts
+    * Don't lint when yield expressions are used
+    * Don't lint when the captures made by the would-be closure conflict with
+      the other branch
+    * Don't lint when a field of a local is used when the type could be
+      potentially moved from
+    * In some cases, don't lint when scrutinee expression conflicts with the
+      captures of the would-be closure
+* [`redundant_allocation`]: No longer lints on `Box<Box<dyn T>>` which replaces
+  wide pointers with thin pointers
+  [#7592](https://github.com/rust-lang/rust-clippy/pull/7592)
+* [`bool_assert_comparison`]: No longer lints on types that do not implement the
+  `Not` trait with `Output = bool`
+  [#7605](https://github.com/rust-lang/rust-clippy/pull/7605)
+* [`mut_range_bound`]: No longer lints on range bound mutations, that are
+  immediately followed by a `break;`
+  [#7607](https://github.com/rust-lang/rust-clippy/pull/7607)
+* [`mutable_key_type`]: Improve accuracy and document remaining false positives
+  and false negatives
+  [#7640](https://github.com/rust-lang/rust-clippy/pull/7640)
+* [`redundant_closure`]: Rewrite the lint to fix various false positives and
+  false negatives [#7661](https://github.com/rust-lang/rust-clippy/pull/7661)
+* [`large_enum_variant`]: No longer wrongly identifies the second largest
+  variant [#7677](https://github.com/rust-lang/rust-clippy/pull/7677)
+* [`needless_return`]: No longer lints on let-else expressions
+  [#7685](https://github.com/rust-lang/rust-clippy/pull/7685)
+* [`suspicious_else_formatting`]: No longer lints in proc-macros
+  [#7707](https://github.com/rust-lang/rust-clippy/pull/7707)
+* [`excessive_precision`]: No longer lints when in some cases the float was
+  already written in the shortest form
+  [#7722](https://github.com/rust-lang/rust-clippy/pull/7722)
+* [`doc_markdown`]: No longer lints on intra-doc links
+  [#7772](https://github.com/rust-lang/rust-clippy/pull/7772)
+
+### Suggestion Fixes/Improvements
+
+* [`unnecessary_operation`]: Recommend using an `assert!` instead of using a
+  function call in an indexing operation
+  [#7453](https://github.com/rust-lang/rust-clippy/pull/7453)
+* [`manual_split_once`]: Produce semantically equivalent suggestion when
+  `rsplitn` is used [#7663](https://github.com/rust-lang/rust-clippy/pull/7663)
+* [`while_let_on_iterator`]: Produce correct suggestion when using `&mut`
+  [#7690](https://github.com/rust-lang/rust-clippy/pull/7690)
+* [`manual_assert`]: No better handles complex conditions
+  [#7741](https://github.com/rust-lang/rust-clippy/pull/7741)
+* Correctly handle signs in exponents in numeric literals lints
+  [#7747](https://github.com/rust-lang/rust-clippy/pull/7747)
+* [`suspicious_map`]: Now also suggests to use `inspect` as an alternative
+  [#7770](https://github.com/rust-lang/rust-clippy/pull/7770)
+* Drop exponent from suggestion if it is 0 in numeric literals lints
+  [#7774](https://github.com/rust-lang/rust-clippy/pull/7774)
+
+### ICE Fixes
+
+* [`implicit_hasher`]
+  [#7761](https://github.com/rust-lang/rust-clippy/pull/7761)
+
+### Others
+
+* Clippy now uses the 2021
+  [Edition!](https://www.youtube.com/watch?v=q0aNduqb2Ro)
+  [#7664](https://github.com/rust-lang/rust-clippy/pull/7664)
 
 ## Rust 1.56
 
-Current beta, release 2021-10-21
+Current stable, released 2021-10-21
 
 [74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e)
 
@@ -74,13 +225,9 @@ Current beta, release 2021-10-21
 * [`unnested_or_patterns`]: Removed `or_patterns` feature gate in the code
   example [#7507](https://github.com/rust-lang/rust-clippy/pull/7507)
 
-### New Lints
-
-* Renamed Lint: `if_let_some_result` is now called [`match_result_ok`]. Now also handles `while let` case.
-
 ## Rust 1.55
 
-Current stable, released 2021-09-09
+Released 2021-09-09
 
 [3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561)
 
@@ -2730,11 +2877,13 @@ Released 2018-09-13
 [`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons
 [`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools
 [`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
+[`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any
 [`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
 [`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map
 [`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
 [`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
 [`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
+[`format_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_in_format_args
 [`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
 [`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
 [`from_str_radix_10`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_str_radix_10
@@ -2746,7 +2895,6 @@ Released 2018-09-13
 [`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
 [`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
 [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
-[`if_then_panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_panic
 [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
 [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
 [`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
@@ -2804,6 +2952,7 @@ Released 2018-09-13
 [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
 [`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
 [`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_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
@@ -2836,6 +2985,7 @@ Released 2018-09-13
 [`match_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_result_ok
 [`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms
 [`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding
+[`match_str_case_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_str_case_mismatch
 [`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
 [`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
 [`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
@@ -2896,6 +3046,7 @@ Released 2018-09-13
 [`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self
 [`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
 [`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
+[`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
 [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
 [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
 [`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
@@ -2972,6 +3123,7 @@ Released 2018-09-13
 [`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors
 [`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files
 [`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
+[`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix
 [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
 [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
 [`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same
@@ -2996,6 +3148,7 @@ Released 2018-09-13
 [`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
 [`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
 [`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
+[`string_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_slice
 [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
 [`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
 [`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
@@ -3012,16 +3165,19 @@ Released 2018-09-13
 [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
 [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
 [`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
+[`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args
 [`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
 [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
 [`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
 [`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg
+[`trailing_empty_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#trailing_empty_array
 [`trait_duplication_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#trait_duplication_in_bounds
 [`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str
 [`transmute_float_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_float_to_int
 [`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
 [`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
 [`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
+[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
 [`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
 [`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
 [`transmutes_expressible_as_ptr_casts`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmutes_expressible_as_ptr_casts
@@ -3031,12 +3187,15 @@ Released 2018-09-13
 [`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err
 [`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
 [`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
+[`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks
 [`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
 [`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
 [`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
 [`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
+[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec
 [`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg
 [`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
+[`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash
 [`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
 [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
 [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
index 4273fda4e640d5d9356a5d63f166db26224fc603..97ff31b4bc5a3181727c5d8230ea463a6c1c170a 100644 (file)
@@ -262,7 +262,9 @@ to be run inside the `rust` directory):
 2. Checkout the commit from the latest available nightly. You can get it using `rustup check`.
 3. Sync the changes to the rust-copy of Clippy to your Clippy fork:
     ```bash
-    # Make sure to change `your-github-name` to your github name in the following command
+    # Make sure to change `your-github-name` to your github name in the following command. Also be
+    # sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand
+    # because changes cannot be fast forwarded
     git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust
     ```
 
index ba3ed3053ac743466be07b2fdf04c97911dcc0f1..602877bb9d6831dfd824f6d0e8a4fdf143e96b59 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.57"
+version = "0.1.58"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -22,13 +22,13 @@ path = "src/driver.rs"
 
 [dependencies]
 clippy_lints = { version = "0.1", path = "clippy_lints" }
-semver = "0.11"
+semver = "1.0"
 rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
 tempfile = { version = "3.2", optional = true }
 
 [dev-dependencies]
-cargo_metadata = "0.12"
-compiletest_rs = { version = "0.7", features = ["tmp"] }
+cargo_metadata = "0.14"
+compiletest_rs = { version = "0.7.1", features = ["tmp"] }
 tester = "0.9"
 regex = "1.5"
 # This is used by the `collect-metadata` alias.
index 4a13a4524097601ffda40ce63349ca71fef9563e..affb283017c8ce50252ae6d9750e553591e21497 100644 (file)
@@ -6,6 +6,7 @@ edition = "2021"
 [dependencies]
 bytecount = "0.6"
 clap = "2.33"
+indoc = "1.0"
 itertools = "0.10"
 opener = "0.5"
 regex = "1.5"
index 8fdeba9842af3e6f80070aa055e2a28dd70ff000..b5c04efce3bc95bca885102df44ed2c612c6e8f1 100644 (file)
@@ -28,6 +28,7 @@ fn main() {
                 matches.value_of("pass"),
                 matches.value_of("name"),
                 matches.value_of("category"),
+                matches.is_present("msrv"),
             ) {
                 Ok(_) => update_lints::run(update_lints::UpdateMode::Change),
                 Err(e) => eprintln!("Unable to create lint: {}", e),
@@ -147,6 +148,11 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
                             "internal_warn",
                         ])
                         .takes_value(true),
+                )
+                .arg(
+                    Arg::with_name("msrv")
+                        .long("msrv")
+                        .help("Add MSRV config code to the lint"),
                 ),
         )
         .subcommand(
index 3a81aaba6de04054148e741ee8c551102b869b2c..43a478ee77db826975fcbda09202af1381a2981b 100644 (file)
@@ -1,4 +1,5 @@
 use crate::clippy_project_root;
+use indoc::indoc;
 use std::fs::{self, OpenOptions};
 use std::io::prelude::*;
 use std::io::{self, ErrorKind};
@@ -32,7 +33,7 @@ fn context<C: AsRef<str>>(self, text: C) -> Self {
 /// # Errors
 ///
 /// This function errors out if the files couldn't be created or written to.
-pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> io::Result<()> {
+pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>, msrv: bool) -> io::Result<()> {
     let lint = LintData {
         pass: pass.expect("`pass` argument is validated by clap"),
         name: lint_name.expect("`name` argument is validated by clap"),
@@ -40,29 +41,13 @@ pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str
         project_root: clippy_project_root(),
     };
 
-    create_lint(&lint).context("Unable to create lint implementation")?;
-    create_test(&lint).context("Unable to create a test for the new lint")
+    create_lint(&lint, msrv).context("Unable to create lint implementation")?;
+    create_test(&lint).context("Unable to create a test for the new lint")?;
+    add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")
 }
 
-fn create_lint(lint: &LintData<'_>) -> io::Result<()> {
-    let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass {
-        "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"),
-        "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"),
-        _ => {
-            unreachable!("`pass_type` should only ever be `early` or `late`!");
-        },
-    };
-
-    let camel_case_name = to_camel_case(lint.name);
-    let lint_contents = get_lint_file_contents(
-        pass_type,
-        pass_lifetimes,
-        lint.name,
-        &camel_case_name,
-        lint.category,
-        pass_import,
-        context_import,
-    );
+fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
+    let lint_contents = get_lint_file_contents(lint, enable_msrv);
 
     let lint_path = format!("clippy_lints/src/{}.rs", lint.name);
     write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())
@@ -96,6 +81,33 @@ fn create_project_layout<P: Into<PathBuf>>(lint_name: &str, location: P, case: &
     }
 }
 
+fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
+    let path = "clippy_lints/src/lib.rs";
+    let mut lib_rs = fs::read_to_string(path).context("reading")?;
+
+    let comment_start = lib_rs.find("// add lints here,").expect("Couldn't find comment");
+
+    let new_lint = if enable_msrv {
+        format!(
+            "store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n    ",
+            lint_pass = lint.pass,
+            module_name = lint.name,
+            camel_name = to_camel_case(lint.name),
+        )
+    } else {
+        format!(
+            "store.register_{lint_pass}_pass(|| Box::new({module_name}::{camel_name}));\n    ",
+            lint_pass = lint.pass,
+            module_name = lint.name,
+            camel_name = to_camel_case(lint.name),
+        )
+    };
+
+    lib_rs.insert_str(comment_start, &new_lint);
+
+    fs::write(path, lib_rs).context("writing")
+}
+
 fn write_file<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
     fn inner(path: &Path, contents: &[u8]) -> io::Result<()> {
         OpenOptions::new()
@@ -122,12 +134,13 @@ fn to_camel_case(name: &str) -> String {
 
 fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String {
     let mut contents = format!(
-        "#![warn(clippy::{})]
+        indoc! {"
+            #![warn(clippy::{})]
 
-fn main() {{
-    // test code goes here
-}}
-",
+            fn main() {{
+                // test code goes here
+            }}
+        "},
         lint_name
     );
 
@@ -140,64 +153,133 @@ fn main() {{
 
 fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
     format!(
-        r#"
-# {}
+        indoc! {r#"
+            # {}
 
-[package]
-name = "{}"
-version = "0.1.0"
-publish = false
+            [package]
+            name = "{}"
+            version = "0.1.0"
+            publish = false
 
-[workspace]
-"#,
+            [workspace]
+        "#},
         hint, lint_name
     )
 }
 
-fn get_lint_file_contents(
-    pass_type: &str,
-    pass_lifetimes: &str,
-    lint_name: &str,
-    camel_case_name: &str,
-    category: &str,
-    pass_import: &str,
-    context_import: &str,
-) -> String {
-    format!(
-        "use rustc_lint::{{{type}, {context_import}}};
-use rustc_session::{{declare_lint_pass, declare_tool_lint}};
-{pass_import}
-
-declare_clippy_lint! {{
-    /// ### What it does
-    ///
-    /// ### Why is this bad?
-    ///
-    /// ### Example
-    /// ```rust
-    /// // example code where clippy issues a warning
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// // example code which does not raise clippy warning
-    /// ```
-    pub {name_upper},
-    {category},
-    \"default lint description\"
-}}
-
-declare_lint_pass!({name_camel} => [{name_upper}]);
-
-impl {type}{lifetimes} for {name_camel} {{}}
-",
-        type=pass_type,
-        lifetimes=pass_lifetimes,
-        name_upper=lint_name.to_uppercase(),
-        name_camel=camel_case_name,
-        category=category,
-        pass_import=pass_import,
-        context_import=context_import
-    )
+fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
+    let mut result = String::new();
+
+    let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass {
+        "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"),
+        "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"),
+        _ => {
+            unreachable!("`pass_type` should only ever be `early` or `late`!");
+        },
+    };
+
+    let lint_name = lint.name;
+    let category = lint.category;
+    let name_camel = to_camel_case(lint.name);
+    let name_upper = lint_name.to_uppercase();
+
+    result.push_str(&if enable_msrv {
+        format!(
+            indoc! {"
+                use clippy_utils::msrvs;
+                {pass_import}
+                use rustc_lint::{{{context_import}, {pass_type}, LintContext}};
+                use rustc_semver::RustcVersion;
+                use rustc_session::{{declare_tool_lint, impl_lint_pass}};
+
+            "},
+            pass_type = pass_type,
+            pass_import = pass_import,
+            context_import = context_import,
+        )
+    } else {
+        format!(
+            indoc! {"
+                {pass_import}
+                use rustc_lint::{{{context_import}, {pass_type}}};
+                use rustc_session::{{declare_lint_pass, declare_tool_lint}};
+
+            "},
+            pass_import = pass_import,
+            pass_type = pass_type,
+            context_import = context_import
+        )
+    });
+
+    result.push_str(&format!(
+        indoc! {"
+            declare_clippy_lint! {{
+                /// ### What it does
+                ///
+                /// ### Why is this bad?
+                ///
+                /// ### Example
+                /// ```rust
+                /// // example code where clippy issues a warning
+                /// ```
+                /// Use instead:
+                /// ```rust
+                /// // example code which does not raise clippy warning
+                /// ```
+                pub {name_upper},
+                {category},
+                \"default lint description\"
+            }}
+        "},
+        name_upper = name_upper,
+        category = category,
+    ));
+
+    result.push_str(&if enable_msrv {
+        format!(
+            indoc! {"
+                pub struct {name_camel} {{
+                    msrv: Option<RustcVersion>,
+                }}
+
+                impl {name_camel} {{
+                    #[must_use]
+                    pub fn new(msrv: Option<RustcVersion>) -> Self {{
+                        Self {{ msrv }}
+                    }}
+                }}
+
+                impl_lint_pass!({name_camel} => [{name_upper}]);
+
+                impl {pass_type}{pass_lifetimes} for {name_camel} {{
+                    extract_msrv_attr!({context_import});
+                }}
+
+                // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed.
+                // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`.
+                // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
+            "},
+            pass_type = pass_type,
+            pass_lifetimes = pass_lifetimes,
+            name_upper = name_upper,
+            name_camel = name_camel,
+            context_import = context_import,
+        )
+    } else {
+        format!(
+            indoc! {"
+                declare_lint_pass!({name_camel} => [{name_upper}]);
+
+                impl {pass_type}{pass_lifetimes} for {name_camel} {{}}
+            "},
+            pass_type = pass_type,
+            pass_lifetimes = pass_lifetimes,
+            name_upper = name_upper,
+            name_camel = name_camel,
+        )
+    });
+
+    result
 }
 
 #[test]
index 10d859988f6f2d55d52ac3cf035397be337aba0d..23f58bc4915f919eed14c71f50684c77ff2b52c9 100644 (file)
@@ -619,8 +619,8 @@ fn test_gen_changelog_lint_list() {
             Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
         ];
         let expected = vec![
-            format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK.to_string()),
-            format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK.to_string()),
+            format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK),
+            format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK),
         ];
         assert_eq!(expected, gen_changelog_lint_list(lints.iter()));
     }
index 7900dc6d0414136a0ef27a74f787c7d97cd6fc05..281480b8d94914c2d1835a1fb7d2d1fb62620b18 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.57"
+version = "0.1.58"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -9,7 +9,7 @@ keywords = ["clippy", "lint", "plugin"]
 edition = "2021"
 
 [dependencies]
-cargo_metadata = "0.12"
+cargo_metadata = "0.14"
 clippy_utils = { path = "../clippy_utils" }
 if_chain = "1.0"
 itertools = "0.10"
@@ -21,7 +21,7 @@ serde_json = { version = "1.0", optional = true }
 toml = "0.5"
 unicode-normalization = "0.1"
 unicode-script = { version = "0.5", default-features = false }
-semver = "0.11"
+semver = "1.0"
 rustc-semver = "1.1"
 # NOTE: cargo requires serde feat in its url dep
 # see <https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864>
index 833ad122e0d4e20c46ae07f32c94157a4120f218..4af412ccaf35d7d0946429c5b997f9ae7081792e 100644 (file)
@@ -1,15 +1,88 @@
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::expr_or_init;
 use clippy_utils::ty::is_isize_or_usize;
-use rustc_hir::Expr;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, FloatTy, Ty};
 
 use super::{utils, CAST_POSSIBLE_TRUNCATION};
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
+    if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) {
+        Some(c)
+    } else {
+        None
+    }
+}
+
+fn get_constant_bits(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u64> {
+    constant_int(cx, expr).map(|c| u64::from(128 - c.leading_zeros()))
+}
+
+fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: bool) -> u64 {
+    match expr_or_init(cx, expr).kind {
+        ExprKind::Cast(inner, _) => apply_reductions(cx, nbits, inner, signed),
+        ExprKind::Block(block, _) => block.expr.map_or(nbits, |e| apply_reductions(cx, nbits, e, signed)),
+        ExprKind::Binary(op, left, right) => match op.node {
+            BinOpKind::Div => {
+                apply_reductions(cx, nbits, left, signed)
+                    - (if signed {
+                        0 // let's be conservative here
+                    } else {
+                        // by dividing by 1, we remove 0 bits, etc.
+                        get_constant_bits(cx, right).map_or(0, |b| b.saturating_sub(1))
+                    })
+            },
+            BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right)
+                .unwrap_or(u64::max_value())
+                .min(apply_reductions(cx, nbits, left, signed)),
+            BinOpKind::Shr => {
+                apply_reductions(cx, nbits, left, signed)
+                    - constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))
+            },
+            _ => nbits,
+        },
+        ExprKind::MethodCall(method, _, [left, right], _) => {
+            if signed {
+                return nbits;
+            }
+            let max_bits = if method.ident.as_str() == "min" {
+                get_constant_bits(cx, right)
+            } else {
+                None
+            };
+            apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
+        },
+        ExprKind::MethodCall(method, _, [_, lo, hi], _) => {
+            if method.ident.as_str() == "clamp" {
+                //FIXME: make this a diagnostic item
+                if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) {
+                    return lo_bits.max(hi_bits);
+                }
+            }
+            nbits
+        },
+        ExprKind::MethodCall(method, _, [_value], _) => {
+            if method.ident.name.as_str() == "signum" {
+                0 // do not lint if cast comes from a `signum` function
+            } else {
+                nbits
+            }
+        },
+        _ => nbits,
+    }
+}
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
     let msg = match (cast_from.is_integral(), cast_to.is_integral()) {
         (true, true) => {
-            let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
+            let from_nbits = apply_reductions(
+                cx,
+                utils::int_ty_to_nbits(cast_from, cx.tcx),
+                cast_expr,
+                cast_from.is_signed(),
+            );
             let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
 
             let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) {
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
new file mode 100644 (file)
index 0000000..0362188
--- /dev/null
@@ -0,0 +1,34 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty};
+
+use super::FN_TO_NUMERIC_CAST_ANY;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+    // We allow casts from any function type to any function type.
+    match cast_to.kind() {
+        ty::FnDef(..) | ty::FnPtr(..) => return,
+        _ => { /* continue to checks */ },
+    }
+
+    match cast_from.kind() {
+        ty::FnDef(..) | ty::FnPtr(_) => {
+            let mut applicability = Applicability::MaybeIncorrect;
+            let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability);
+
+            span_lint_and_sugg(
+                cx,
+                FN_TO_NUMERIC_CAST_ANY,
+                expr.span,
+                &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to),
+                "did you mean to invoke the function?",
+                format!("{}() as {}", from_snippet, cast_to),
+                applicability,
+            );
+        },
+        _ => {},
+    }
+}
index 27e1bea799353da4bd3cbb3076ef4d788934264c..233abd178943e9bc20b2685c68fd55f03d46a9c3 100644 (file)
@@ -7,6 +7,7 @@
 mod cast_sign_loss;
 mod char_lit_as_u8;
 mod fn_to_numeric_cast;
+mod fn_to_numeric_cast_any;
 mod fn_to_numeric_cast_with_truncation;
 mod ptr_as_ptr;
 mod unnecessary_cast;
     "casting a function pointer to a numeric type not wide enough to store the address"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for casts of a function pointer to any integer type.
+    ///
+    /// ### Why is this bad?
+    /// Casting a function pointer to an integer can have surprising results and can occur
+    /// accidentally if parantheses are omitted from a function call. If you aren't doing anything
+    /// low-level with function pointers then you can opt-out of casting functions to integers in
+    /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
+    /// pointer casts in your code.
+    ///
+    /// ### Example
+    /// ```rust
+    /// // Bad: fn1 is cast as `usize`
+    /// fn fn1() -> u16 {
+    ///     1
+    /// };
+    /// let _ = fn1 as usize;
+    ///
+    /// // Good: maybe you intended to call the function?
+    /// fn fn2() -> u16 {
+    ///     1
+    /// };
+    /// let _ = fn2() as usize;
+    ///
+    /// // Good: maybe you intended to cast it to a function type?
+    /// fn fn3() -> u16 {
+    ///     1
+    /// }
+    /// let _ = fn3 as fn() -> u16;
+    /// ```
+    pub FN_TO_NUMERIC_CAST_ANY,
+    restriction,
+    "casting a function pointer to any integer type"
+}
+
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for casts of `&T` to `&mut T` anywhere in the code.
@@ -360,6 +397,7 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
     CAST_REF_TO_MUT,
     CAST_PTR_ALIGNMENT,
     UNNECESSARY_CAST,
+    FN_TO_NUMERIC_CAST_ANY,
     FN_TO_NUMERIC_CAST,
     FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
     CHAR_LIT_AS_U8,
@@ -385,10 +423,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 return;
             }
 
+            fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
             fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
             fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
             if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
-                cast_possible_truncation::check(cx, expr, cast_from, cast_to);
+                cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
                 cast_possible_wrap::check(cx, expr, cast_from, cast_to);
                 cast_precision_loss::check(cx, expr, cast_from, cast_to);
                 cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to);
index b7385dcfbca19a38a4165a1f676d1f8c52c577bf..8abf10c0d1c2d174b1380b5a3c01d5ef5b17d3ee 100644 (file)
@@ -459,12 +459,10 @@ fn emit_branches_sharing_code_lint(
         } else {
             sm.stmt_span(block.stmts[block.stmts.len() - end_stmts].span, block.span)
         };
-        let moved_end = block
-            .expr
-            .map_or_else(
-                || sm.stmt_span(block.stmts[block.stmts.len() - 1].span, block.span),
-                |expr| expr.span.source_callsite(),
-            );
+        let moved_end = block.expr.map_or_else(
+            || sm.stmt_span(block.stmts[block.stmts.len() - 1].span, block.span),
+            |expr| expr.span.source_callsite(),
+        );
 
         let moved_span = moved_start.to(moved_end);
         let moved_snipped = reindent_multiline(snippet(cx, moved_span, "_"), true, None);
index db8f2171348f7046ffa96bae0a3a2519471a1e4d..cde27d3ad2a0ce3def12b28ab0e5ebfddb640489 100644 (file)
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
 use clippy_utils::source::snippet_with_macro_callsite;
+use clippy_utils::ty::{has_drop, is_copy};
 use clippy_utils::{any_parent_is_automatically_derived, contains_name, in_macro, match_def_path, paths};
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashSet;
@@ -139,6 +140,13 @@ fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
                     .fields
                     .iter()
                     .all(|field| field.vis.is_accessible_from(module_did, cx.tcx));
+                let all_fields_are_copy = variant
+                    .fields
+                    .iter()
+                    .all(|field| {
+                        is_copy(cx, cx.tcx.type_of(field.did))
+                    });
+                if !has_drop(cx, binding_type) || all_fields_are_copy;
                 then {
                     (local, variant, ident.name, binding_type, expr.span)
                 } else {
index c604516742ce5a1a510862792bc48cb7fdb1b01e..9d8524ec91cc6e08f7c2ea056aabb58f3103e02e 100644 (file)
@@ -1,3 +1,6 @@
+// NOTE: if you add a deprecated lint in this file, please add a corresponding test in
+// tests/ui/deprecated.rs
+
 /// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This
 /// enables the simple extraction of the metadata without changing the current deprecation
 /// declaration.
index 7825e5f6ed52e45f9f715c0cb2b93fd55a4fc9ca..ce59311c4aa96acac5154ce00f02e3d0a746fa99 100644 (file)
@@ -126,7 +126,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                                 target_mut,
                             },
                         ));
-                    }
+                    },
                     _ => (),
                 }
             },
index 87124f093a86dbf7c327581296397e5d0e58a55d..48f781516f4228c2aecdb5f738d76c47942772ff 100644 (file)
@@ -1,12 +1,14 @@
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::span_lint_and_then;
 
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{
     def::Res, def_id::DefId, Item, ItemKind, PolyTraitRef, PrimTy, TraitBoundModifier, Ty, TyKind, UseKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
+
+use crate::utils::conf;
 
 declare_clippy_lint! {
     /// ### What it does
     /// An example clippy.toml configuration:
     /// ```toml
     /// # clippy.toml
-    /// disallowed-types = ["std::collections::BTreeMap"]
+    /// disallowed-types = [
+    ///     # Can use a string as the path of the disallowed type.
+    ///     "std::collections::BTreeMap",
+    ///     # Can also use an inline table with a `path` key.
+    ///     { path = "std::net::TcpListener" },
+    ///     # When using an inline table, can add a `reason` for why the type
+    ///     # is disallowed.
+    ///     { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
+    /// ]
     /// ```
     ///
     /// ```rust,ignore
 }
 #[derive(Clone, Debug)]
 pub struct DisallowedType {
-    disallowed: FxHashSet<Vec<Symbol>>,
-    def_ids: FxHashSet<DefId>,
-    prim_tys: FxHashSet<PrimTy>,
+    conf_disallowed: Vec<conf::DisallowedType>,
+    def_ids: FxHashMap<DefId, Option<String>>,
+    prim_tys: FxHashMap<PrimTy, Option<String>>,
 }
 
 impl DisallowedType {
-    pub fn new(disallowed: &FxHashSet<String>) -> Self {
+    pub fn new(conf_disallowed: Vec<conf::DisallowedType>) -> Self {
         Self {
-            disallowed: disallowed
-                .iter()
-                .map(|s| s.split("::").map(Symbol::intern).collect::<Vec<_>>())
-                .collect(),
-            def_ids: FxHashSet::default(),
-            prim_tys: FxHashSet::default(),
+            conf_disallowed,
+            def_ids: FxHashMap::default(),
+            prim_tys: FxHashMap::default(),
         }
     }
 
     fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
         match res {
             Res::Def(_, did) => {
-                if self.def_ids.contains(did) {
-                    emit(cx, &cx.tcx.def_path_str(*did), span);
+                if let Some(reason) = self.def_ids.get(did) {
+                    emit(cx, &cx.tcx.def_path_str(*did), span, reason.as_deref());
                 }
             },
             Res::PrimTy(prim) => {
-                if self.prim_tys.contains(prim) {
-                    emit(cx, prim.name_str(), span);
+                if let Some(reason) = self.prim_tys.get(prim) {
+                    emit(cx, prim.name_str(), span, reason.as_deref());
                 }
             },
             _ => {},
@@ -76,14 +83,21 @@ fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
 
 impl<'tcx> LateLintPass<'tcx> for DisallowedType {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
-        for path in &self.disallowed {
-            let segs = path.iter().map(ToString::to_string).collect::<Vec<_>>();
-            match clippy_utils::path_to_res(cx, &segs.iter().map(String::as_str).collect::<Vec<_>>()) {
+        for conf in &self.conf_disallowed {
+            let (path, reason) = match conf {
+                conf::DisallowedType::Simple(path) => (path, None),
+                conf::DisallowedType::WithReason { path, reason } => (
+                    path,
+                    reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)),
+                ),
+            };
+            let segs: Vec<_> = path.split("::").collect();
+            match clippy_utils::path_to_res(cx, &segs) {
                 Res::Def(_, id) => {
-                    self.def_ids.insert(id);
+                    self.def_ids.insert(id, reason);
                 },
                 Res::PrimTy(ty) => {
-                    self.prim_tys.insert(ty);
+                    self.prim_tys.insert(ty, reason);
                 },
                 _ => {},
             }
@@ -107,11 +121,16 @@ fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTrait
     }
 }
 
-fn emit(cx: &LateContext<'_>, name: &str, span: Span) {
-    span_lint(
+fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) {
+    span_lint_and_then(
         cx,
         DISALLOWED_TYPE,
         span,
         &format!("`{}` is not allowed according to config", name),
+        |diag| {
+            if let Some(reason) = reason {
+                diag.note(reason);
+            }
+        },
     );
 }
index 9840affbf6fd81b978a00e2e17a0d1a0a564690c..87ad5178ff0887d8971b220844b528659a251b8f 100644 (file)
@@ -1,5 +1,6 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note};
-use clippy_utils::source::first_line_of_span;
+use clippy_utils::attrs::is_doc_hidden;
+use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg};
+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 if_chain::if_chain;
@@ -9,7 +10,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::Handler;
+use rustc_errors::{Applicability, Handler};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{AnonConst, Expr, ExprKind, QPath};
@@ -47,7 +48,7 @@
     /// content are not linted.
     ///
     /// In addition, when writing documentation comments, including `[]` brackets
-    /// inside a link text would trip the parser. Therfore, documenting link with
+    /// inside a link text would trip the parser. Therefore, documenting link with
     /// `[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec
     /// would fail.
     ///
@@ -297,6 +298,17 @@ fn lint_for_missing_headers<'tcx>(
     if !cx.access_levels.is_exported(def_id) {
         return; // Private functions do not require doc comments
     }
+
+    // do not lint if any parent has `#[doc(hidden)]` attribute (#7347)
+    if cx
+        .tcx
+        .hir()
+        .parent_iter(cx.tcx.hir().local_def_id_to_hir_id(def_id))
+        .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id)))
+    {
+        return;
+    }
+
     if !headers.safety && sig.header.unsafety == hir::Unsafety::Unsafe {
         span_lint(
             cx,
@@ -566,9 +578,12 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     // text "http://example.com" by pulldown-cmark
                     continue;
                 }
-                headers.safety |= in_heading && text.trim() == "Safety";
-                headers.errors |= in_heading && text.trim() == "Errors";
-                headers.panics |= in_heading && text.trim() == "Panics";
+                let trimmed_text = text.trim();
+                headers.safety |= in_heading && trimmed_text == "Safety";
+                headers.safety |= in_heading && trimmed_text == "Implementation safety";
+                headers.safety |= in_heading && trimmed_text == "Implementation Safety";
+                headers.errors |= in_heading && trimmed_text == "Errors";
+                headers.panics |= in_heading && trimmed_text == "Panics";
                 if in_code {
                     if is_rust {
                         let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition());
@@ -674,10 +689,18 @@ fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str
     for word in text.split(|c: char| c.is_whitespace() || c == '\'') {
         // Trim punctuation as in `some comment (see foo::bar).`
         //                                                   ^^
-        // Or even as in `_foo bar_` which is emphasized.
-        let word = word.trim_matches(|c: char| !c.is_alphanumeric());
+        // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix.
+        let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':');
 
-        if valid_idents.contains(word) {
+        // Remove leading or trailing single `:` which may be part of a sentence.
+        if word.starts_with(':') && !word.starts_with("::") {
+            word = word.trim_start_matches(':');
+        }
+        if word.ends_with(':') && !word.ends_with("::") {
+            word = word.trim_end_matches(':');
+        }
+
+        if valid_idents.contains(word) || word.chars().all(|c| c == ':') {
             continue;
         }
 
@@ -732,17 +755,22 @@ fn has_hyphen(s: &str) -> bool {
         }
     }
 
-    // We assume that mixed-case words are not meant to be put inside bacticks. (Issue #2343)
+    // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343)
     if has_underscore(word) && has_hyphen(word) {
         return;
     }
 
     if has_underscore(word) || word.contains("::") || is_camel_case(word) {
-        span_lint(
+        let mut applicability = Applicability::MachineApplicable;
+
+        span_lint_and_sugg(
             cx,
             DOC_MARKDOWN,
             span,
-            &format!("you should put `{}` between ticks in the documentation", word),
+            "item in documentation is missing backticks",
+            "try",
+            format!("`{}`", snippet_with_applicability(cx, span, "..", &mut applicability)),
+            applicability,
         );
     }
 }
@@ -781,9 +809,9 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 
         // check for `unwrap`
         if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-            let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
-            if is_type_diagnostic_item(self.cx, reciever_ty, sym::Option)
-                || is_type_diagnostic_item(self.cx, reciever_ty, sym::Result)
+            let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+            if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
+                || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
             {
                 self.panic_span = Some(expr.span);
             }
index ac6824672f66cbf90c13b7f7d9e6dfab2d009d4d..57fd24bd4f04d81ca9263a905b84b258a100ae59 100644 (file)
@@ -245,11 +245,14 @@ fn try_parse_contains(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(Map
         ExprKind::MethodCall(
             _,
             _,
-            [map, Expr {
-                kind: ExprKind::AddrOf(_, _, key),
-                span: key_span,
-                ..
-            }],
+            [
+                map,
+                Expr {
+                    kind: ExprKind::AddrOf(_, _, key),
+                    span: key_span,
+                    ..
+                },
+            ],
             _,
         ) if key_span.ctxt() == expr.span.ctxt() => {
             let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
index 174260fabd228688c47943efa52d9cae07f84481..404b67c8f29f2817a9e6f58c3fc55d3b588075e4 100644 (file)
@@ -1,8 +1,8 @@
 //! lint on enum variants that are prefixed or suffixed by the same characters
 
-use clippy_utils::camel_case;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::source::is_present_in_source;
+use clippy_utils::str_utils::{self, count_match_end, count_match_start};
 use rustc_hir::{EnumDef, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -117,26 +117,6 @@ pub fn new(threshold: u64, avoid_breaking_exported_api: bool) -> Self {
     MODULE_INCEPTION
 ]);
 
-/// Returns the number of chars that match from the start
-#[must_use]
-fn partial_match(pre: &str, name: &str) -> usize {
-    let mut name_iter = name.chars();
-    let _ = name_iter.next_back(); // make sure the name is never fully matched
-    pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count()
-}
-
-/// Returns the number of chars that match from the end
-#[must_use]
-fn partial_rmatch(post: &str, name: &str) -> usize {
-    let mut name_iter = name.chars();
-    let _ = name_iter.next(); // make sure the name is never fully matched
-    post.chars()
-        .rev()
-        .zip(name_iter.rev())
-        .take_while(|&(l, r)| l == r)
-        .count()
-}
-
 fn check_variant(
     cx: &LateContext<'_>,
     threshold: u64,
@@ -150,7 +130,7 @@ fn check_variant(
     }
     for var in def.variants {
         let name = var.ident.name.as_str();
-        if partial_match(item_name, &name) == item_name_chars
+        if count_match_start(item_name, &name).char_count == item_name_chars
             && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
             && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
         {
@@ -161,7 +141,7 @@ fn check_variant(
                 "variant name starts with the enum's name",
             );
         }
-        if partial_rmatch(item_name, &name) == item_name_chars {
+        if count_match_end(item_name, &name).char_count == item_name_chars {
             span_lint(
                 cx,
                 ENUM_VARIANT_NAMES,
@@ -171,14 +151,14 @@ fn check_variant(
         }
     }
     let first = &def.variants[0].ident.name.as_str();
-    let mut pre = &first[..camel_case::until(&*first)];
-    let mut post = &first[camel_case::from(&*first)..];
+    let mut pre = &first[..str_utils::camel_case_until(&*first).byte_index];
+    let mut post = &first[str_utils::camel_case_start(&*first).byte_index..];
     for var in def.variants {
         let name = var.ident.name.as_str();
 
-        let pre_match = partial_match(pre, &name);
+        let pre_match = count_match_start(pre, &name).byte_count;
         pre = &pre[..pre_match];
-        let pre_camel = camel_case::until(pre);
+        let pre_camel = str_utils::camel_case_until(pre).byte_index;
         pre = &pre[..pre_camel];
         while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
             if next.is_numeric() {
@@ -186,18 +166,18 @@ fn check_variant(
             }
             if next.is_lowercase() {
                 let last = pre.len() - last.len_utf8();
-                let last_camel = camel_case::until(&pre[..last]);
-                pre = &pre[..last_camel];
+                let last_camel = str_utils::camel_case_until(&pre[..last]);
+                pre = &pre[..last_camel.byte_index];
             } else {
                 break;
             }
         }
 
-        let post_match = partial_rmatch(post, &name);
-        let post_end = post.len() - post_match;
+        let post_match = count_match_end(post, &name);
+        let post_end = post.len() - post_match.byte_count;
         post = &post[post_end..];
-        let post_camel = camel_case::from(post);
-        post = &post[post_camel..];
+        let post_camel = str_utils::camel_case_start(post);
+        post = &post[post_camel.byte_index..];
     }
     let (what, value) = match (pre.is_empty(), post.is_empty()) {
         (true, true) => return,
@@ -266,14 +246,16 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
                             );
                         }
                     }
-                    if item.vis.node.is_pub() {
-                        let matching = partial_match(mod_camel, &item_camel);
-                        let rmatching = partial_rmatch(mod_camel, &item_camel);
+                    // The `module_name_repetitions` lint should only trigger if the item has the module in its
+                    // name. Having the same name is accepted.
+                    if item.vis.node.is_pub() && item_camel.len() > mod_camel.len() {
+                        let matching = count_match_start(mod_camel, &item_camel);
+                        let rmatching = count_match_end(mod_camel, &item_camel);
                         let nchars = mod_camel.chars().count();
 
                         let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();
 
-                        if matching == nchars {
+                        if matching.char_count == nchars {
                             match item_camel.chars().nth(nchars) {
                                 Some(c) if is_word_beginning(c) => span_lint(
                                     cx,
@@ -284,7 +266,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
                                 _ => (),
                             }
                         }
-                        if rmatching == nchars {
+                        if rmatching.char_count == nchars {
                             span_lint(
                                 cx,
                                 MODULE_NAME_REPETITIONS,
index 51d5094e8c9987491d39bb3b29c3b91cc050b789..655560afd4250045d8675529fc41bb5abf6f8677 100644 (file)
@@ -1,7 +1,9 @@
 use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then};
 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, in_macro, is_expn_of};
+use clippy_utils::{
+    ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of, is_in_test_function,
+};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind};
@@ -81,7 +83,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                         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,
@@ -108,7 +110,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             if macro_with_not_op(&left.kind) || macro_with_not_op(&right.kind) {
                 return;
             }
-            if is_useless_with_eq_exprs(op.node.into()) && eq_expr_value(cx, left, right) {
+            if is_useless_with_eq_exprs(op.node.into())
+                && eq_expr_value(cx, left, right)
+                && !is_in_test_function(cx.tcx, e.hir_id)
+            {
                 span_lint(
                     cx,
                     EQ_OP,
index 0c6ba91c9430b9db1024c62276d96dab17b4a3d9..e8b1d6f6edaaaeb27b1a41daf89a9cd1e0580248 100644 (file)
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::implements_trait;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -77,9 +77,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                 let pat_str = match pat.kind {
                     PatKind::Struct(..) => format!(
                         "({})",
-                        snippet_with_applicability(cx, pat.span, "..", &mut applicability),
+                        snippet_with_context(cx, pat.span, expr.span.ctxt(), "..", &mut applicability).0,
                     ),
-                    _ => snippet_with_applicability(cx, pat.span, "..", &mut applicability).to_string(),
+                    _ => snippet_with_context(cx, pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(),
                 };
                 span_lint_and_sugg(
                     cx,
@@ -89,7 +89,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                     "try",
                     format!(
                         "{} == {}",
-                        snippet_with_applicability(cx, exp.span, "..", &mut applicability),
+                        snippet_with_context(cx, exp.span, expr.span.ctxt(), "..", &mut applicability).0,
                         pat_str,
                     ),
                     applicability,
index 765a6c7585a20a6ee3b5f4d09bd6f5b0319396ab..9247343b52a5322f8c7ee09eec77de8b655ffcff 100644 (file)
@@ -169,13 +169,16 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_
         }
         match *cx.typeck_results().expr_adjustments(arg) {
             [] => true,
-            [Adjustment {
-                kind: Adjust::Deref(None),
-                ..
-            }, Adjustment {
-                kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
-                ..
-            }] => {
+            [
+                Adjustment {
+                    kind: Adjust::Deref(None),
+                    ..
+                },
+                Adjustment {
+                    kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
+                    ..
+                },
+            ] => {
                 // re-borrow with the same mutability is allowed
                 let ty = cx.typeck_results().expr_ty(arg);
                 matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into())
index 37d9ea3bdc117cae4b4e917425751ec27e155213..7169ac9ad6c5a50ce98062c8d1dcdaa465adea46 100644 (file)
@@ -1,11 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::higher::FormatExpn;
-use clippy_utils::last_path_segment;
 use clippy_utils::source::{snippet_opt, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, QPath};
+use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -50,15 +49,19 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 
         let mut applicability = Applicability::MachineApplicable;
         if format_args.value_args.is_empty() {
-            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 {
-                    // 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);
+            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 {
+                        // 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 {
@@ -69,8 +72,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     ty::Str => true,
                     _ => false,
                 };
-                if format_args.args.iter().all(is_display_arg);
-                if format_args.fmt_expr.map_or(true, check_unformatted);
+                if let Some(args) = format_args.args();
+                if args.iter().all(|arg| arg.is_display() && !arg.has_string_formatting());
                 then {
                     let is_new_string = match value.kind {
                         ExprKind::Binary(..) => true,
@@ -90,58 +93,26 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     }
 }
 
-fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) {
+fn span_useless_format_empty(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) {
     span_lint_and_sugg(
         cx,
         USELESS_FORMAT,
         span,
         "useless use of `format!`",
-        "consider using `.to_string()`",
+        "consider using `String::new()`",
         sugg,
         applicability,
     );
 }
 
-fn is_display_arg(expr: &Expr<'_>) -> bool {
-    if_chain! {
-        if let ExprKind::Call(_, [_, fmt]) = expr.kind;
-        if let ExprKind::Path(QPath::Resolved(_, path)) = fmt.kind;
-        if let [.., t, _] = path.segments;
-        if t.ident.name == sym::Display;
-        then { true } else { false }
-    }
-}
-
-/// Checks if the expression matches
-/// ```rust,ignore
-/// &[_ {
-///    format: _ {
-///         width: _::Implied,
-///         precision: _::Implied,
-///         ...
-///    },
-///    ...,
-/// }]
-/// ```
-fn check_unformatted(expr: &Expr<'_>) -> bool {
-    if_chain! {
-        if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind;
-        if let ExprKind::Array([expr]) = expr.kind;
-        // struct `core::fmt::rt::v1::Argument`
-        if let ExprKind::Struct(_, fields, _) = expr.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(_, fields, _) = format_field.expr.kind;
-        if let Some(precision_field) = fields.iter().find(|f| f.ident.name == sym::precision);
-        if let ExprKind::Path(ref precision_path) = precision_field.expr.kind;
-        if last_path_segment(precision_path).ident.name == sym::Implied;
-        if let Some(width_field) = fields.iter().find(|f| f.ident.name == sym::width);
-        if let ExprKind::Path(ref width_qpath) = width_field.expr.kind;
-        if last_path_segment(width_qpath).ident.name == sym::Implied;
-        then {
-            return true;
-        }
-    }
-
-    false
+fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) {
+    span_lint_and_sugg(
+        cx,
+        USELESS_FORMAT,
+        span,
+        "useless use of `format!`",
+        "consider using `.to_string()`",
+        sugg,
+        applicability,
+    );
 }
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
new file mode 100644 (file)
index 0000000..8b27442
--- /dev/null
@@ -0,0 +1,223 @@
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::higher::{FormatArgsArg, FormatArgsExpn, FormatExpn};
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{is_diag_trait_item, match_def_path, paths};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment};
+use rustc_middle::ty::Ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, BytePos, ExpnData, ExpnKind, Span, Symbol};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects `format!` within the arguments of another macro that does
+    /// formatting such as `format!` itself, `write!` or `println!`. Suggests
+    /// inlining the `format!` call.
+    ///
+    /// ### Why is this bad?
+    /// The recommended code is both shorter and avoids a temporary allocation.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use std::panic::Location;
+    /// println!("error: {}", format!("something failed at {}", Location::caller()));
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use std::panic::Location;
+    /// println!("error: something failed at {}", Location::caller());
+    /// ```
+    pub FORMAT_IN_FORMAT_ARGS,
+    perf,
+    "`format!` used in a macro that does formatting"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for [`ToString::to_string`](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string)
+    /// applied to a type that implements [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html)
+    /// in a macro that does formatting.
+    ///
+    /// ### Why is this bad?
+    /// Since the type implements `Display`, the use of `to_string` is
+    /// unnecessary.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use std::panic::Location;
+    /// println!("error: something failed at {}", Location::caller().to_string());
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use std::panic::Location;
+    /// println!("error: something failed at {}", Location::caller());
+    /// ```
+    pub TO_STRING_IN_FORMAT_ARGS,
+    perf,
+    "`to_string` applied to a type that implements `Display` in format args"
+}
+
+declare_lint_pass!(FormatArgs => [FORMAT_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS]);
+
+const FORMAT_MACRO_PATHS: &[&[&str]] = &[
+    &paths::FORMAT_ARGS_MACRO,
+    &paths::ASSERT_EQ_MACRO,
+    &paths::ASSERT_MACRO,
+    &paths::ASSERT_NE_MACRO,
+    &paths::EPRINT_MACRO,
+    &paths::EPRINTLN_MACRO,
+    &paths::PRINT_MACRO,
+    &paths::PRINTLN_MACRO,
+    &paths::WRITE_MACRO,
+    &paths::WRITELN_MACRO,
+];
+
+const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[sym::format_macro, sym::std_panic_macro];
+
+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);
+            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;
+            if FORMAT_MACRO_PATHS
+                .iter()
+                .any(|path| match_def_path(cx, macro_def_id, path))
+                || FORMAT_MACRO_DIAG_ITEMS
+                    .iter()
+                    .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, macro_def_id));
+            if let ExpnKind::Macro(_, name) = outermost_expn_data.kind;
+            if let Some(args) = format_args.args();
+            then {
+                for (i, arg) in args.iter().enumerate() {
+                    if !arg.is_display() {
+                        continue;
+                    }
+                    if arg.has_string_formatting() {
+                        continue;
+                    }
+                    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);
+                }
+            }
+        }
+    }
+}
+
+fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
+    if expn_data.call_site.from_expansion() {
+        outermost_expn_data(expn_data.call_site.ctxt().outer_expn_data())
+    } else {
+        expn_data
+    }
+}
+
+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,
+                trim_semicolon(cx, 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;
+    if_chain! {
+        if !value.span.from_expansion();
+        if let ExprKind::MethodCall(_, _, [receiver], _) = value.kind;
+        if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id);
+        if is_diag_trait_item(cx, method_def_id, sym::ToString);
+        let receiver_ty = cx.typeck_results().expr_ty(receiver);
+        if let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display);
+        if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
+        then {
+            let (n_needed_derefs, target) = count_needed_derefs(
+                receiver_ty,
+                cx.typeck_results().expr_adjustments(receiver).iter(),
+            );
+            if implements_trait(cx, target, display_trait_id, &[]) {
+                if n_needed_derefs == 0 {
+                    span_lint_and_sugg(
+                        cx,
+                        TO_STRING_IN_FORMAT_ARGS,
+                        value.span.with_lo(receiver.span.hi()),
+                        &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name),
+                        "remove this",
+                        String::new(),
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    span_lint_and_sugg(
+                        cx,
+                        TO_STRING_IN_FORMAT_ARGS,
+                        value.span,
+                        &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name),
+                        "use this",
+                        format!("{:*>width$}{}", "", receiver_snippet, width = n_needed_derefs),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+        }
+    }
+}
+
+// Returns true if `args[i]` "refers to" or "is referred to by" another argument.
+fn is_aliased(args: &[FormatArgsArg<'_>], i: usize) -> bool {
+    let value = args[i].value;
+    args.iter()
+        .enumerate()
+        .any(|(j, arg)| i != j && std::ptr::eq(value, arg.value))
+}
+
+fn trim_semicolon(cx: &LateContext<'_>, span: Span) -> Span {
+    snippet_opt(cx, span).map_or(span, |snippet| {
+        let snippet = snippet.trim_end_matches(';');
+        span.with_hi(span.lo() + BytePos(u32::try_from(snippet.len()).unwrap()))
+    })
+}
+
+fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
+where
+    I: Iterator<Item = &'tcx Adjustment<'tcx>>,
+{
+    let mut n_total = 0;
+    let mut n_needed = 0;
+    loop {
+        if let Some(Adjustment {
+            kind: Adjust::Deref(overloaded_deref),
+            target,
+        }) = iter.next()
+        {
+            n_total += 1;
+            if overloaded_deref.is_some() {
+                n_needed = n_total;
+            }
+            ty = target;
+        } else {
+            return (n_needed, ty);
+        }
+    }
+}
index 04fc5887e8e8b21123d92d9bde53ed6179151560..d7c5ec9ba355bdf4bcc4118bc518554718afd4cf 100644 (file)
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for a [`#[must_use]`] attribute on
+    /// Checks for a `#[must_use]` attribute on
     /// unit-returning functions and methods.
     ///
-    /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
-    ///
     /// ### Why is this bad?
     /// Unit values are useless. The attribute is likely
     /// a remnant of a refactoring that removed the return type.
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for a [`#[must_use]`] attribute without
+    /// Checks for a `#[must_use]` attribute without
     /// further information on functions and methods that return a type already
     /// marked as `#[must_use]`.
     ///
-    /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
-    ///
     /// ### Why is this bad?
     /// The attribute isn't needed. Not using the result
     /// will already be reported. Alternatively, one can add some text to the
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for public functions that have no
-    /// [`#[must_use]`] attribute, but return something not already marked
+    /// `#[must_use]` attribute, but return something not already marked
     /// must-use, have no mutable arg and mutate no statics.
     ///
-    /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
-    ///
     /// ### Why is this bad?
     /// Not bad at all, this lint just shows places where
     /// you could add the attribute.
index 73bdd67ff5d25a864b88c23055d7e8cec1b63c18..414f465c49414088113b36ee2eb09f45c72b9964 100644 (file)
@@ -66,7 +66,6 @@ fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_
         && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1))
 }
 
-#[allow(clippy::cast_possible_wrap)]
 fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) {
     if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e) {
         let check = match *cx.typeck_results().expr_ty(e).kind() {
index 3ce91d421baca8bc9efe4b9ae760c522c7f288ca..ac938156237bf8f090feb281558f6301b685e6b0 100644 (file)
@@ -2,9 +2,9 @@
 //! on the condition
 
 use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp};
-use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_middle::lint::in_external_macro;
+use clippy_utils::is_else_clause;
+use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
 
 declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
 
-impl EarlyLintPass for IfNotElse {
-    fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
-        if in_external_macro(cx.sess, item.span) {
+impl LateLintPass<'_> for IfNotElse {
+    fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
+        // While loops will be desugared to ExprKind::If. This will cause the lint to fire.
+        // To fix this, return early if this span comes from a macro or desugaring.
+        if item.span.from_expansion() {
             return;
         }
-        if let ExprKind::If(ref cond, _, Some(ref els)) = item.kind {
+        if let ExprKind::If(cond, _, Some(els)) = item.kind {
             if let ExprKind::Block(..) = els.kind {
-                match cond.kind {
+                // Disable firing the lint in "else if" expressions.
+                if is_else_clause(cx.tcx, item) {
+                    return;
+                }
+
+                match cond.peel_drop_temps().kind {
                     ExprKind::Unary(UnOp::Not, _) => {
                         span_lint_and_help(
                             cx,
diff --git a/src/tools/clippy/clippy_lints/src/if_then_panic.rs b/src/tools/clippy/clippy_lints/src/if_then_panic.rs
deleted file mode 100644 (file)
index 10bca59..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher::PanicExpn;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_expn_of, sugg};
-use rustc_errors::Applicability;
-use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Detects `if`-then-`panic!` that can be replaced with `assert!`.
-    ///
-    /// ### Why is this bad?
-    /// `assert!` is simpler than `if`-then-`panic!`.
-    ///
-    /// ### Example
-    /// ```rust
-    /// let sad_people: Vec<&str> = vec![];
-    /// if !sad_people.is_empty() {
-    ///     panic!("there are sad people: {:?}", sad_people);
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// let sad_people: Vec<&str> = vec![];
-    /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
-    /// ```
-    pub IF_THEN_PANIC,
-    style,
-    "`panic!` and only a `panic!` in `if`-then statement"
-}
-
-declare_lint_pass!(IfThenPanic => [IF_THEN_PANIC]);
-
-impl LateLintPass<'_> for IfThenPanic {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        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 !matches!(cond.kind, ExprKind::Let(_, _, _));
-            if let StmtKind::Semi(semi) = stmt.kind;
-            if !cx.tcx.sess.source_map().is_multiline(cond.span);
-
-            then {
-                let span = if let Some(panic_expn) = PanicExpn::parse(semi) {
-                    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_chain! {
-                        if let ExprKind::Block(block, _) = semi.kind;
-                        if let Some(init) = block.expr;
-                        if let ExprKind::Call(_, [format_args]) = init.kind;
-
-                        then {
-                            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().to_string())
-                    }
-                } else {
-                   format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par().to_string())
-                };
-
-                span_lint_and_sugg(
-                    cx,
-                    IF_THEN_PANIC,
-                    expr.span,
-                    "only a `panic!` in `if`-then statement",
-                    "try",
-                    format!("assert!({}, {});", cond_sugg, sugg),
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-    }
-}
index 79d4d7ddcbcedfe8e0ad85116a98a76068dc6c46..a4f60ded3a6e0ebcaadab8e2b92ab712211d5159 100644 (file)
@@ -43,7 +43,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             return;
         }
         if_chain! {
-            if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
+            if let Some(higher::If { cond, then, r#else: None }) = higher::If::hir(expr);
 
             // Check if the conditional expression is a binary operation
             if let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind;
index 3c40ca50a0981aa04c42d6357362fc4aef139311..61dd0eb4af7ed37d7239f2b334bbed4712a7edf8 100644 (file)
@@ -138,10 +138,10 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) {
             item.span,
             &format!(
                 "type `{}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`",
-                self_type.to_string()
+                self_type
             ),
             None,
-            &format!("remove the inherent method from type `{}`", self_type.to_string()),
+            &format!("remove the inherent method from type `{}`", self_type),
         );
     } else {
         span_lint_and_help(
@@ -150,10 +150,10 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) {
             item.span,
             &format!(
                 "implementation of inherent method `to_string(&self) -> String` for type `{}`",
-                self_type.to_string()
+                self_type
             ),
             None,
-            &format!("implement trait `Display` for type `{}` instead", self_type.to_string()),
+            &format!("implement trait `Display` for type `{}` instead", self_type),
         );
     }
 }
index 49b69dd072a21352da51d21d4eb1a4c0bee2778f..6850e0c34767cb0864a002b5ce498c3cc157c5a8 100644 (file)
@@ -89,7 +89,7 @@ fn check_binop(cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs: &Expr)
                     },
                     _ => None,
                 }
-            }
+            },
             // case where `x + 1 <= ...` or `1 + x <= ...`
             (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _)
                 if lhskind.node == BinOpKind::Add =>
@@ -104,7 +104,7 @@ fn check_binop(cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs: &Expr)
                     },
                     _ => None,
                 }
-            }
+            },
             // case where `... >= y - 1` or `... >= -1 + y`
             (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
                 match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {
index b1f70b30c12cf1c1605b09ac48cf9fc9891fad3e..82438d85c7a3a353128134b0736e587c4dc9d5f1 100644 (file)
@@ -1,5 +1,3 @@
-use std::cmp::Ordering;
-
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
@@ -7,11 +5,11 @@
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 
+use clippy_utils::comparisons;
 use clippy_utils::comparisons::Rel;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{constant_full_int, FullInt};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::source::snippet;
-use clippy_utils::{comparisons, sext};
 
 declare_clippy_lint! {
     /// ### What it does
 
 declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
 
-#[derive(Copy, Clone, Debug, Eq)]
-enum FullInt {
-    S(i128),
-    U(u128),
-}
-
-impl FullInt {
-    #[allow(clippy::cast_sign_loss)]
-    #[must_use]
-    fn cmp_s_u(s: i128, u: u128) -> Ordering {
-        if s < 0 {
-            Ordering::Less
-        } else if u > (i128::MAX as u128) {
-            Ordering::Greater
-        } else {
-            (s as u128).cmp(&u)
-        }
-    }
-}
-
-impl PartialEq for FullInt {
-    #[must_use]
-    fn eq(&self, other: &Self) -> bool {
-        self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal
-    }
-}
-
-impl PartialOrd for FullInt {
-    #[must_use]
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        Some(match (self, other) {
-            (&Self::S(s), &Self::S(o)) => s.cmp(&o),
-            (&Self::U(s), &Self::U(o)) => s.cmp(&o),
-            (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o),
-            (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(),
-        })
-    }
-}
-
-impl Ord for FullInt {
-    #[must_use]
-    fn cmp(&self, other: &Self) -> Ordering {
-        self.partial_cmp(other)
-            .expect("`partial_cmp` for FullInt can never return `None`")
-    }
-}
-
 fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
     if let ExprKind::Cast(cast_exp, _) = expr.kind {
         let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
@@ -118,19 +69,6 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) ->
     }
 }
 
-fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
-    let val = constant(cx, cx.typeck_results(), expr)?.0;
-    if let Constant::Int(const_int) = val {
-        match *cx.typeck_results().expr_ty(expr).kind() {
-            ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
-            ty::Uint(_) => Some(FullInt::U(const_int)),
-            _ => None,
-        }
-    } else {
-        None
-    }
-}
-
 fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
     if let ExprKind::Cast(cast_val, _) = expr.kind {
         span_lint(
@@ -156,7 +94,7 @@ fn upcast_comparison_bounds_err<'tcx>(
     invert: bool,
 ) {
     if let Some((lb, ub)) = lhs_bounds {
-        if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
+        if let Some(norm_rhs_val) = constant_full_int(cx, cx.typeck_results(), rhs) {
             if rel == Rel::Eq || rel == Rel::Ne {
                 if norm_rhs_val < lb || norm_rhs_val > ub {
                     err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
index 89146b4dd2c9bd5f58b61a89a2cab4b61f7b6d76..9efd7aba7e83bccf09af6aea4f86da86285eeeda 100644 (file)
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `let _ = <expr>`
-    /// where expr is #[must_use]
+    /// Checks for `let _ = <expr>` where expr is `#[must_use]`
     ///
     /// ### Why is this bad?
-    /// It's better to explicitly
-    /// handle the value of a #[must_use] expr
+    /// It's better to explicitly handle the value of a `#[must_use]`
+    /// expr
     ///
     /// ### Example
     /// ```rust
index 6a3ee35b41a4ba361018295205059784a15e9a64..15edb79d36c24d613653e870f38dc66ff94ca3e3 100644 (file)
@@ -60,6 +60,8 @@
     LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
     LintId::of(float_literal::EXCESSIVE_PRECISION),
     LintId::of(format::USELESS_FORMAT),
+    LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
+    LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
     LintId::of(formatting::POSSIBLE_MISSING_COMMA),
     LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
     LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
@@ -74,7 +76,6 @@
     LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
     LintId::of(identity_op::IDENTITY_OP),
     LintId::of(if_let_mutex::IF_LET_MUTEX),
-    LintId::of(if_then_panic::IF_THEN_PANIC),
     LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
     LintId::of(infinite_iter::INFINITE_ITER),
     LintId::of(inherent_to_string::INHERENT_TO_STRING),
     LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
     LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
     LintId::of(match_result_ok::MATCH_RESULT_OK),
+    LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH),
     LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
     LintId::of(matches::MATCH_AS_REF),
     LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
     LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
     LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
     LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
+    LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
     LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
     LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
     LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
     LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
     LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
     LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
+    LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
     LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
     LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
     LintId::of(transmute::WRONG_TRANSMUTE),
     LintId::of(types::VEC_BOX),
     LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
     LintId::of(unicode::INVISIBLE_CHARACTERS),
+    LintId::of(uninit_vec::UNINIT_VEC),
+    LintId::of(unit_hash::UNIT_HASH),
     LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
     LintId::of(unit_types::UNIT_ARG),
     LintId::of(unit_types::UNIT_CMP),
index 64b82fc0faac8593504e6de0b0653504c5eb442d..c51341bdf0c233bbcd11a18a7759994acc83d8bc 100644 (file)
@@ -82,6 +82,7 @@
     LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
     LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
     LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
+    LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
     LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
     LintId::of(types::BORROWED_BOX),
     LintId::of(types::TYPE_COMPLEXITY),
index bbe47a0e772f7b6e5318b6af7b99f926ff3d6d70..4217fd3a3ea72c04af802f688f39d34f1f501c7a 100644 (file)
@@ -36,6 +36,7 @@
     LintId::of(loops::ITER_NEXT_LOOP),
     LintId::of(loops::NEVER_LOOP),
     LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
+    LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH),
     LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
     LintId::of(methods::CLONE_DOUBLE_REF),
     LintId::of(methods::ITERATOR_STEP_BY_ZERO),
@@ -62,6 +63,8 @@
     LintId::of(transmuting_null::TRANSMUTING_NULL),
     LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
     LintId::of(unicode::INVISIBLE_CHARACTERS),
+    LintId::of(uninit_vec::UNINIT_VEC),
+    LintId::of(unit_hash::UNIT_HASH),
     LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
     LintId::of(unit_types::UNIT_CMP),
     LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
index b0be3b653664cd8f51ad4ea09b2bc6d77d7188ae..2cb86418e3cb5df2cc946ba79a8095fe48de7be0 100644 (file)
@@ -67,6 +67,7 @@
     casts::CAST_SIGN_LOSS,
     casts::CHAR_LIT_AS_U8,
     casts::FN_TO_NUMERIC_CAST,
+    casts::FN_TO_NUMERIC_CAST_ANY,
     casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
     casts::PTR_AS_PTR,
     casts::UNNECESSARY_CAST,
     floating_point_arithmetic::IMPRECISE_FLOPS,
     floating_point_arithmetic::SUBOPTIMAL_FLOPS,
     format::USELESS_FORMAT,
+    format_args::FORMAT_IN_FORMAT_ARGS,
+    format_args::TO_STRING_IN_FORMAT_ARGS,
     formatting::POSSIBLE_MISSING_COMMA,
     formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
     formatting::SUSPICIOUS_ELSE_FORMATTING,
     identity_op::IDENTITY_OP,
     if_let_mutex::IF_LET_MUTEX,
     if_not_else::IF_NOT_ELSE,
-    if_then_panic::IF_THEN_PANIC,
     if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
     implicit_hasher::IMPLICIT_HASHER,
     implicit_return::IMPLICIT_RETURN,
     loops::WHILE_LET_ON_ITERATOR,
     macro_use::MACRO_USE_IMPORTS,
     main_recursion::MAIN_RECURSION,
+    manual_assert::MANUAL_ASSERT,
     manual_async_fn::MANUAL_ASYNC_FN,
     manual_map::MANUAL_MAP,
     manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
     map_unit_fn::RESULT_MAP_UNIT_FN,
     match_on_vec_items::MATCH_ON_VEC_ITEMS,
     match_result_ok::MATCH_RESULT_OK,
+    match_str_case_mismatch::MATCH_STR_CASE_MISMATCH,
     matches::INFALLIBLE_DESTRUCTURING_MATCH,
     matches::MATCH_AS_REF,
     matches::MATCH_BOOL,
     misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
     misc_early::MIXED_CASE_HEX_LITERALS,
     misc_early::REDUNDANT_PATTERN,
+    misc_early::SEPARATED_LITERAL_SUFFIX,
     misc_early::UNNEEDED_FIELD_PATTERN,
     misc_early::UNNEEDED_WILDCARD_PATTERN,
     misc_early::UNSEPARATED_LITERAL_SUFFIX,
     neg_multiply::NEG_MULTIPLY,
     new_without_default::NEW_WITHOUT_DEFAULT,
     no_effect::NO_EFFECT,
+    no_effect::NO_EFFECT_UNDERSCORE_BINDING,
     no_effect::UNNECESSARY_OPERATION,
     non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
     non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
     strings::STRING_ADD_ASSIGN,
     strings::STRING_FROM_UTF8_AS_BYTES,
     strings::STRING_LIT_AS_BYTES,
+    strings::STRING_SLICE,
     strings::STRING_TO_STRING,
     strings::STR_TO_STRING,
     strlen_on_c_strings::STRLEN_ON_C_STRINGS,
     temporary_assignment::TEMPORARY_ASSIGNMENT,
     to_digit_is_some::TO_DIGIT_IS_SOME,
     to_string_in_display::TO_STRING_IN_DISPLAY,
+    trailing_empty_array::TRAILING_EMPTY_ARRAY,
     trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
     trait_bounds::TYPE_REPETITION_IN_BOUNDS,
     transmute::CROSSPOINTER_TRANSMUTE,
     transmute::TRANSMUTE_INT_TO_BOOL,
     transmute::TRANSMUTE_INT_TO_CHAR,
     transmute::TRANSMUTE_INT_TO_FLOAT,
+    transmute::TRANSMUTE_NUM_TO_BYTES,
     transmute::TRANSMUTE_PTR_TO_PTR,
     transmute::TRANSMUTE_PTR_TO_REF,
     transmute::UNSOUND_COLLECTION_TRANSMUTE,
     types::REDUNDANT_ALLOCATION,
     types::TYPE_COMPLEXITY,
     types::VEC_BOX,
+    undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS,
     undropped_manually_drops::UNDROPPED_MANUALLY_DROPS,
     unicode::INVISIBLE_CHARACTERS,
     unicode::NON_ASCII_LITERAL,
     unicode::UNICODE_NOT_NFC,
+    uninit_vec::UNINIT_VEC,
+    unit_hash::UNIT_HASH,
     unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
     unit_types::LET_UNIT_VALUE,
     unit_types::UNIT_ARG,
index 96e0b421094d622f4495a3a9be49085127a5841a..44c75a11eec08111c17db1d2ca03862a17e3a6a3 100644 (file)
@@ -17,7 +17,6 @@
     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_INTEGER),
-    LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
     LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
     LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
     LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
@@ -25,6 +24,7 @@
     LintId::of(regex::TRIVIAL_REGEX),
     LintId::of(strings::STRING_LIT_AS_BYTES),
     LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
+    LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY),
     LintId::of(transmute::USELESS_TRANSMUTE),
     LintId::of(use_self::USE_SELF),
 ])
index 6533b94e82bd5ce10c539392ca6a3c627480dbd1..404ca20b5abc62bf05adf9b474a19c0990048e00 100644 (file)
@@ -48,6 +48,7 @@
     LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
     LintId::of(loops::EXPLICIT_ITER_LOOP),
     LintId::of(macro_use::MACRO_USE_IMPORTS),
+    LintId::of(manual_assert::MANUAL_ASSERT),
     LintId::of(manual_ok_or::MANUAL_OK_OR),
     LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
     LintId::of(matches::MATCH_BOOL),
     LintId::of(methods::MAP_UNWRAP_OR),
     LintId::of(misc::FLOAT_CMP),
     LintId::of(misc::USED_UNDERSCORE_BINDING),
-    LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
     LintId::of(mut_mut::MUT_MUT),
     LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
     LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE),
     LintId::of(needless_continue::NEEDLESS_CONTINUE),
     LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
     LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
+    LintId::of(no_effect::NO_EFFECT_UNDERSCORE_BINDING),
     LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
     LintId::of(non_expressive_names::SIMILAR_NAMES),
     LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
@@ -87,7 +88,6 @@
     LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
     LintId::of(types::LINKEDLIST),
     LintId::of(types::OPTION_OPTION),
-    LintId::of(unicode::NON_ASCII_LITERAL),
     LintId::of(unicode::UNICODE_NOT_NFC),
     LintId::of(unit_types::LET_UNIT_VALUE),
     LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
index 5432345760bc3242126b9f0978e8d90d44d62e70..a0d5cf9418e0b32f7244fbd48759acb925e9997f 100644 (file)
@@ -5,6 +5,8 @@
 store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
     LintId::of(entry::MAP_ENTRY),
     LintId::of(escape::BOXED_LOCAL),
+    LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
+    LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
     LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
     LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
     LintId::of(loops::MANUAL_MEMCPY),
index 4463dea5fcb8436a12f82721865750869fc16cf1..eab389a9bd892089b94a10c749b2837d3916b25c 100644 (file)
@@ -8,6 +8,7 @@
     LintId::of(as_conversions::AS_CONVERSIONS),
     LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
     LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
+    LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
     LintId::of(create_dir::CREATE_DIR),
     LintId::of(dbg_macro::DBG_MACRO),
     LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
@@ -34,7 +35,9 @@
     LintId::of(methods::GET_UNWRAP),
     LintId::of(methods::UNWRAP_USED),
     LintId::of(misc::FLOAT_CMP_CONST),
+    LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX),
     LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
+    LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
     LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
     LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
     LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
     LintId::of(shadow::SHADOW_SAME),
     LintId::of(shadow::SHADOW_UNRELATED),
     LintId::of(strings::STRING_ADD),
+    LintId::of(strings::STRING_SLICE),
     LintId::of(strings::STRING_TO_STRING),
     LintId::of(strings::STR_TO_STRING),
     LintId::of(types::RC_BUFFER),
     LintId::of(types::RC_MUTEX),
+    LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS),
+    LintId::of(unicode::NON_ASCII_LITERAL),
     LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
     LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
     LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
index a39c111c5742340d1a0d59723da29d722c8271c6..744880bda3e69c2a83763dc5d9b1a38ade7b6ec5 100644 (file)
@@ -27,7 +27,6 @@
     LintId::of(functions::DOUBLE_MUST_USE),
     LintId::of(functions::MUST_USE_UNIT),
     LintId::of(functions::RESULT_UNIT_ERR),
-    LintId::of(if_then_panic::IF_THEN_PANIC),
     LintId::of(inherent_to_string::INHERENT_TO_STRING),
     LintId::of(len_zero::COMPARISON_TO_EMPTY),
     LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
index 8859787fbc830c97e7b34a0ee21e053d586bcdcf..a3f964d1580428f92230f26f169586fd86e25504 100644 (file)
@@ -15,6 +15,7 @@
     LintId::of(loops::MUT_RANGE_BOUND),
     LintId::of(methods::SUSPICIOUS_MAP),
     LintId::of(mut_key::MUTABLE_KEY_TYPE),
+    LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
     LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
     LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
 ])
index 5534f9c94f367fe6a2de3d1aab5fa91846534c17..7174d0a082e0f7627f062180d10f5ef47c170a4b 100644 (file)
@@ -218,6 +218,7 @@ macro_rules! declare_clippy_lint {
 mod float_literal;
 mod floating_point_arithmetic;
 mod format;
+mod format_args;
 mod formatting;
 mod from_over_into;
 mod from_str_radix_10;
@@ -227,7 +228,6 @@ macro_rules! declare_clippy_lint {
 mod identity_op;
 mod if_let_mutex;
 mod if_not_else;
-mod if_then_panic;
 mod if_then_some_else_none;
 mod implicit_hasher;
 mod implicit_return;
@@ -254,6 +254,7 @@ macro_rules! declare_clippy_lint {
 mod loops;
 mod macro_use;
 mod main_recursion;
+mod manual_assert;
 mod manual_async_fn;
 mod manual_map;
 mod manual_non_exhaustive;
@@ -265,6 +266,7 @@ macro_rules! declare_clippy_lint {
 mod map_unit_fn;
 mod match_on_vec_items;
 mod match_result_ok;
+mod match_str_case_mismatch;
 mod matches;
 mod mem_forget;
 mod mem_replace;
@@ -352,13 +354,17 @@ macro_rules! declare_clippy_lint {
 mod temporary_assignment;
 mod to_digit_is_some;
 mod to_string_in_display;
+mod trailing_empty_array;
 mod trait_bounds;
 mod transmute;
 mod transmuting_null;
 mod try_err;
 mod types;
+mod undocumented_unsafe_blocks;
 mod undropped_manually_drops;
 mod unicode;
+mod uninit_vec;
+mod unit_hash;
 mod unit_return_expecting_ord;
 mod unit_types;
 mod unnamed_address;
@@ -516,6 +522,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
     store.register_late_pass(|| Box::new(collapsible_match::CollapsibleMatch));
     store.register_late_pass(|| Box::new(unicode::Unicode));
+    store.register_late_pass(|| Box::new(uninit_vec::UninitVec));
+    store.register_late_pass(|| Box::new(unit_hash::UnitHash));
     store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
     store.register_late_pass(|| Box::new(strings::StringAdd));
     store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn));
@@ -660,7 +668,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| Box::new(double_parens::DoubleParens));
     store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::new()));
     store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
-    store.register_early_pass(|| Box::new(if_not_else::IfNotElse));
     store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
     store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
     store.register_early_pass(|| Box::new(formatting::Formatting));
@@ -714,6 +721,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse));
     store.register_late_pass(|| Box::new(future_not_send::FutureNotSend));
     store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex));
+    store.register_late_pass(|| Box::new(if_not_else::IfNotElse));
     store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality));
     store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock));
     store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems));
@@ -754,8 +762,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison));
     store.register_early_pass(move || Box::new(module_style::ModStyle));
     store.register_late_pass(|| Box::new(unused_async::UnusedAsync));
-    let disallowed_types = conf.disallowed_types.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || Box::new(disallowed_type::DisallowedType::new(&disallowed_types)));
+    let disallowed_types = conf.disallowed_types.clone();
+    store.register_late_pass(move || Box::new(disallowed_type::DisallowedType::new(disallowed_types.clone())));
     let import_renames = conf.enforced_import_renames.clone();
     store.register_late_pass(move || Box::new(missing_enforced_import_rename::ImportRename::new(import_renames.clone())));
     let scripts = conf.allowed_scripts.clone();
@@ -764,9 +772,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors));
     store.register_late_pass(move || Box::new(feature_name::FeatureName));
     store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
-    store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic));
+    store.register_late_pass(move || Box::new(manual_assert::ManualAssert));
     let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
     store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send)));
+    store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default()));
+    store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch));
+    store.register_late_pass(move || Box::new(format_args::FormatArgs));
+    store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
+    // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
 #[rustfmt::skip]
@@ -817,6 +830,7 @@ fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
 ///
 /// Used in `./src/driver.rs`.
 pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
+    // NOTE: when renaming a lint, add a corresponding test to tests/ui/rename.rs
     ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions");
     ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default");
     ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");
index e5e6f8d25cc11143878512361a1a9d9f5672cb99..cb0b96e0652e53b1115b238a63713907c8a7fa04 100644 (file)
@@ -378,11 +378,15 @@ fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>, tbm: Tra
 
     fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
         match ty.kind {
-            TyKind::OpaqueDef(item, _) => {
+            TyKind::OpaqueDef(item, bounds) => {
                 let map = self.cx.tcx.hir();
                 let item = map.item(item);
                 walk_item(self, item);
                 walk_ty(self, ty);
+                self.lts.extend(bounds.iter().filter_map(|bound| match bound {
+                    GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)),
+                    _ => None,
+                }));
             },
             TyKind::BareFn(&BareFnTy { decl, .. }) => {
                 let mut sub_visitor = RefVisitor::new(self.cx);
index 2f7360210ba4de7918204c49434a6cf0a5ecd8f3..f9f515cc40a0fbdd120af9de1358d4e92ba66ce7 100644 (file)
@@ -338,7 +338,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
                     sugg::Sugg::hir_with_applicability(cx, arg_inner, "_", applic_ref).maybe_par(),
                     meth_name,
                 )
-            }
+            },
             _ => format!(
                 "{}.into_iter()",
                 sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par()
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
new file mode 100644 (file)
index 0000000..e55aa3f
--- /dev/null
@@ -0,0 +1,100 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::higher::PanicExpn;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{is_expn_of, sugg};
+use rustc_errors::Applicability;
+use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects `if`-then-`panic!` that can be replaced with `assert!`.
+    ///
+    /// ### Why is this bad?
+    /// `assert!` is simpler than `if`-then-`panic!`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let sad_people: Vec<&str> = vec![];
+    /// if !sad_people.is_empty() {
+    ///     panic!("there are sad people: {:?}", sad_people);
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let sad_people: Vec<&str> = vec![];
+    /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
+    /// ```
+    pub MANUAL_ASSERT,
+    pedantic,
+    "`panic!` and only a `panic!` in `if`-then statement"
+}
+
+declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]);
+
+impl LateLintPass<'_> for ManualAssert {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        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 !matches!(cond.kind, ExprKind::Let(_, _, _));
+            if let StmtKind::Semi(semi) = stmt.kind;
+            if !cx.tcx.sess.source_map().is_multiline(cond.span);
+
+            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())
+                };
+
+                span_lint_and_sugg(
+                    cx,
+                    MANUAL_ASSERT,
+                    expr.span,
+                    "only a `panic!` in `if`-then statement",
+                    "try",
+                    format!("assert!({}, {});", cond_sugg, sugg),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
index 2ae9cb4f9c132b16d4189c1f5b7821de51d56c5a..42478e3416ece7a2549529503c03943b25fbaadf 100644 (file)
@@ -98,7 +98,7 @@ fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'
                 reindent_multiline(or_body_snippet.into(), true, Some(indent));
 
             let suggestion = if scrutinee.span.from_expansion() {
-                    // we don't want parenthesis around macro, e.g. `(some_macro!()).unwrap_or(0)`
+                    // we don't want parentheses around macro, e.g. `(some_macro!()).unwrap_or(0)`
                     sugg::Sugg::hir_with_macro_callsite(cx, scrutinee, "..")
                 }
                 else {
index 3db1f0421ea70efb35940ed2c9ab96fbcbc935ad..ecf6ad316a46124a121e0be7de6264ace3ed1098 100644 (file)
@@ -35,7 +35,7 @@
     /// }
     ///
     /// if let Ok(value) = iter.next() {
-    ///        vec.push_value)
+    ///        vec.push(value)
     /// }
     /// ```
     pub MATCH_RESULT_OK,
diff --git a/src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs
new file mode 100644 (file)
index 0000000..f501593
--- /dev/null
@@ -0,0 +1,171 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+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::{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};
+use rustc_span::symbol::SymbolStr;
+use rustc_span::{sym, Span};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `match` expressions modifying the case of a string with non-compliant arms
+    ///
+    /// ### Why is this bad?
+    /// The arm is unreachable, which is likely a mistake
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let text = "Foo";
+    ///
+    /// match &*text.to_ascii_lowercase() {
+    ///     "foo" => {},
+    ///     "Bar" => {},
+    ///     _ => {},
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # let text = "Foo";
+    ///
+    /// match &*text.to_ascii_lowercase() {
+    ///     "foo" => {},
+    ///     "bar" => {},
+    ///     _ => {},
+    /// }
+    /// ```
+    pub MATCH_STR_CASE_MISMATCH,
+    correctness,
+    "creation of a case altering match expression with non-compliant arms"
+}
+
+declare_lint_pass!(MatchStrCaseMismatch => [MATCH_STR_CASE_MISMATCH]);
+
+#[derive(Debug)]
+enum CaseMethod {
+    LowerCase,
+    AsciiLowerCase,
+    UpperCase,
+    AsciiUppercase,
+}
+
+impl LateLintPass<'_> for MatchStrCaseMismatch {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if_chain! {
+            if !in_external_macro(cx.tcx.sess, expr.span);
+            if let ExprKind::Match(match_expr, arms, MatchSource::Normal) = expr.kind;
+            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(match_expr).kind();
+            if let ty::Str = ty.kind();
+            then {
+                let mut visitor = MatchExprVisitor {
+                    cx,
+                    case_method: None,
+                };
+
+                visitor.visit_expr(match_expr);
+
+                if let Some(case_method) = visitor.case_method {
+                    if let Some((bad_case_span, bad_case_str)) = verify_case(&case_method, arms) {
+                        lint(cx, &case_method, bad_case_span, &bad_case_str);
+                    }
+                }
+            }
+        }
+    }
+}
+
+struct MatchExprVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    case_method: Option<CaseMethod>,
+}
+
+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) => {},
+            _ => walk_expr(self, ex),
+        }
+    }
+}
+
+impl<'a, 'tcx> MatchExprVisitor<'a, 'tcx> {
+    fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> bool {
+        if let Some(case_method) = get_case_method(segment_ident) {
+            let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
+
+            if is_type_diagnostic_item(self.cx, ty, sym::String) || ty.kind() == &ty::Str {
+                self.case_method = Some(case_method);
+                return true;
+            }
+        }
+
+        false
+    }
+}
+
+fn get_case_method(segment_ident_str: &str) -> Option<CaseMethod> {
+    match segment_ident_str {
+        "to_lowercase" => Some(CaseMethod::LowerCase),
+        "to_ascii_lowercase" => Some(CaseMethod::AsciiLowerCase),
+        "to_uppercase" => Some(CaseMethod::UpperCase),
+        "to_ascii_uppercase" => Some(CaseMethod::AsciiUppercase),
+        _ => None,
+    }
+}
+
+fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(Span, SymbolStr)> {
+    let case_check = match case_method {
+        CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(|c| c.to_lowercase().next() == Some(c)) },
+        CaseMethod::AsciiLowerCase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_uppercase()) },
+        CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(|c| c.to_uppercase().next() == Some(c)) },
+        CaseMethod::AsciiUppercase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_lowercase()) },
+    };
+
+    for arm in arms {
+        if_chain! {
+            if let PatKind::Lit(Expr {
+                                kind: ExprKind::Lit(lit),
+                                ..
+                            }) = arm.pat.kind;
+            if let LitKind::Str(symbol, _) = lit.node;
+            let input = symbol.as_str();
+            if !case_check(&input);
+            then {
+                return Some((lit.span, input));
+            }
+        }
+    }
+
+    None
+}
+
+fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad_case_str: &str) {
+    let (method_str, suggestion) = match case_method {
+        CaseMethod::LowerCase => ("to_lowercase", bad_case_str.to_lowercase()),
+        CaseMethod::AsciiLowerCase => ("to_ascii_lowercase", bad_case_str.to_ascii_lowercase()),
+        CaseMethod::UpperCase => ("to_uppercase", bad_case_str.to_uppercase()),
+        CaseMethod::AsciiUppercase => ("to_ascii_uppercase", bad_case_str.to_ascii_uppercase()),
+    };
+
+    span_lint_and_sugg(
+        cx,
+        MATCH_STR_CASE_MISMATCH,
+        bad_case_span,
+        "this `match` arm has a differing case than its expression",
+        &*format!("consider changing the case of this arm to respect `{}`", method_str),
+        format!("\"{}\"", suggestion),
+        Applicability::MachineApplicable,
+    );
+}
index 56d4163a6b3435cf9d6d88052c6eb1bbecd3e5ad..eb311983b29276ebf0b21b35ed9e0dcc46750af3 100644 (file)
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, miri_to_const, Constant};
+use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt};
 use clippy_utils::diagnostics::{
     multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
 };
@@ -930,9 +930,8 @@ fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
 fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
     if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() {
         let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex));
-        let type_ranges = type_ranges(&ranges);
-        if !type_ranges.is_empty() {
-            if let Some((start, end)) = overlapping(&type_ranges) {
+        if !ranges.is_empty() {
+            if let Some((start, end)) = overlapping(&ranges) {
                 span_lint_and_note(
                     cx,
                     MATCH_OVERLAPPING_ARM,
@@ -968,8 +967,7 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm
                     }
                     if_chain! {
                         if matching_wild;
-                        if let ExprKind::Block(block, _) = arm.body.kind;
-                        if is_panic_block(block);
+                        if is_panic_call(arm.body);
                         then {
                             // `Err(_)` or `Err(_e)` arm with `panic!` found
                             span_lint_and_note(cx,
@@ -1172,14 +1170,19 @@ 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_block(block: &Block<'_>) -> bool {
-    match (&block.expr, block.stmts.len(), block.stmts.first()) {
-        (&Some(exp), 0, _) => is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none(),
-        (&None, 1, Some(stmt)) => {
-            is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none()
-        },
-        _ => false,
-    }
+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<'_>)
@@ -1187,7 +1190,7 @@ fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I,
     'b: 'a,
     I: Clone + Iterator<Item = &'a Pat<'b>>,
 {
-    if !has_only_ref_pats(pats.clone()) {
+    if !has_multiple_ref_pats(pats.clone()) {
         return;
     }
 
@@ -1601,7 +1604,7 @@ fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'
 }
 
 /// Gets all arms that are unbounded `PatRange`s.
-fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<Constant>> {
+fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<FullInt>> {
     arms.iter()
         .filter_map(|arm| {
             if let Arm { pat, guard: None, .. } = *arm {
@@ -1614,21 +1617,25 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
                         Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
                         None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
                     };
-                    let rhs = match range_end {
-                        RangeEnd::Included => Bound::Included(rhs),
-                        RangeEnd::Excluded => Bound::Excluded(rhs),
+
+                    let lhs_val = lhs.int_value(cx, ty)?;
+                    let rhs_val = rhs.int_value(cx, ty)?;
+
+                    let rhs_bound = match range_end {
+                        RangeEnd::Included => Bound::Included(rhs_val),
+                        RangeEnd::Excluded => Bound::Excluded(rhs_val),
                     };
                     return Some(SpannedRange {
                         span: pat.span,
-                        node: (lhs, rhs),
+                        node: (lhs_val, rhs_bound),
                     });
                 }
 
                 if let PatKind::Lit(value) = pat.kind {
-                    let value = constant(cx, cx.typeck_results(), value)?.0;
+                    let value = constant_full_int(cx, cx.typeck_results(), value)?;
                     return Some(SpannedRange {
                         span: pat.span,
-                        node: (value.clone(), Bound::Included(value)),
+                        node: (value, Bound::Included(value)),
                     });
                 }
             }
@@ -1643,32 +1650,6 @@ pub struct SpannedRange<T> {
     pub node: (T, Bound<T>),
 }
 
-type TypedRanges = Vec<SpannedRange<u128>>;
-
-/// Gets all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway
-/// and other types than
-/// `Uint` and `Int` probably don't make sense.
-fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
-    ranges
-        .iter()
-        .filter_map(|range| match range.node {
-            (Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange {
-                span: range.span,
-                node: (start, Bound::Included(end)),
-            }),
-            (Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange {
-                span: range.span,
-                node: (start, Bound::Excluded(end)),
-            }),
-            (Constant::Int(start), Bound::Unbounded) => Some(SpannedRange {
-                span: range.span,
-                node: (start, Bound::Unbounded),
-            }),
-            _ => None,
-        })
-        .collect()
-}
-
 // Checks if arm has the form `None => None`
 fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
     matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
@@ -1693,12 +1674,12 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotat
     None
 }
 
-fn has_only_ref_pats<'a, 'b, I>(pats: I) -> bool
+fn has_multiple_ref_pats<'a, 'b, I>(pats: I) -> bool
 where
     'b: 'a,
     I: Iterator<Item = &'a Pat<'b>>,
 {
-    let mut at_least_one_is_true = false;
+    let mut ref_count = 0;
     for opt in pats.map(|pat| match pat.kind {
         PatKind::Ref(..) => Some(true), // &-patterns
         PatKind::Wild => Some(false),   // an "anything" wildcard is also fine
@@ -1706,13 +1687,13 @@ fn has_only_ref_pats<'a, 'b, I>(pats: I) -> bool
     }) {
         if let Some(inner) = opt {
             if inner {
-                at_least_one_is_true = true;
+                ref_count += 1;
             }
         } else {
             return false;
         }
     }
-    at_least_one_is_true
+    ref_count > 1
 }
 
 pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)>
index 1a32af5dc7a386fdd5e03c3832e8c105d6fc47f8..b4dacb2580c313fbc366aae7b251facfbdda215e 100644 (file)
@@ -85,7 +85,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
                     if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) =>
                 {
                     return;
-                }
+                },
                 ExprKind::MethodCall(_, _, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
                 ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
                 | ExprKind::Field(..)
@@ -100,7 +100,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
                 ) =>
             {
                 return;
-            }
+            },
             _ => false,
         };
 
index b26d11c0d6b0d8620a77e985e0dc023e16c2bffc..26c29fbb289cb7f8d11e1aa41ce5d22d46a07cb0 100644 (file)
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for usages of `str::splitn(2, _)`
-    ///
-    /// **Why is this bad?** `split_once` is both clearer in intent and slightly more efficient.
-    ///
-    /// **Known problems:** None.
+    /// ### What it does
+    /// Checks for usages of `str::splitn(2, _)`
     ///
-    /// **Example:**
+    /// ### Why is this bad?
+    /// `split_once` is both clearer in intent and slightly more efficient.
     ///
+    /// ### Example
     /// ```rust,ignore
     /// // Bad
     ///  let (key, value) = _.splitn(2, '=').next_tuple()?;
index b5bbbb09092af4f12d27c6fc60cc363444796019..fe9ffde0d337c1f15506e73bdca1e0f373c88da5 100644 (file)
@@ -186,7 +186,7 @@ fn check_general_case<'tcx>(
                         check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
                     }
                 }
-            }
+            },
             _ => (),
         }
     }
index 1a5894e48d14c5ac1c935dae2231e086f248c78c..ce89189bce9779e12305ca5c269ef9c4e359e30d 100644 (file)
@@ -1,9 +1,8 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_expr_path_def_path, match_def_path, paths};
+use clippy_utils::{is_expr_path_def_path, paths, ty::is_uninit_value_valid_for_ty};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
 
 use super::UNINIT_ASSUMED_INIT;
 
@@ -13,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         if let hir::ExprKind::Call(callee, args) = recv.kind;
         if args.is_empty();
         if is_expr_path_def_path(cx, callee, &paths::MEM_MAYBEUNINIT_UNINIT);
-        if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr));
+        if !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr));
         then {
             span_lint(
                 cx,
@@ -24,12 +23,3 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         }
     }
 }
-
-fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    match ty.kind() {
-        ty::Array(component, _) => is_maybe_uninit_ty_valid(cx, component),
-        ty::Tuple(types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)),
-        ty::Adt(adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT),
-        _ => false,
-    }
-}
index 6f65778e1193cfc08d011e0eec606f08e683bf6a..06ba968fa4ed31da1700c3df599ff67badc51359 100644 (file)
@@ -1,4 +1,3 @@
-use super::MiscEarlyLints;
 use clippy_utils::diagnostics::span_lint;
 use rustc_ast::ast::{Expr, ExprKind, UnOp};
 use rustc_lint::EarlyContext;
@@ -6,18 +5,14 @@
 use super::DOUBLE_NEG;
 
 pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) {
-    match expr.kind {
-        ExprKind::Unary(UnOp::Neg, ref inner) => {
-            if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
-                span_lint(
-                    cx,
-                    DOUBLE_NEG,
-                    expr.span,
-                    "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
-                );
-            }
-        },
-        ExprKind::Lit(ref lit) => MiscEarlyLints::check_lit(cx, lit),
-        _ => (),
+    if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind {
+        if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
+            span_lint(
+                cx,
+                DOUBLE_NEG,
+                expr.span,
+                "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
+            );
+        }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
new file mode 100644 (file)
index 0000000..1165c19
--- /dev/null
@@ -0,0 +1,38 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::ast::Lit;
+use rustc_errors::Applicability;
+use rustc_lint::EarlyContext;
+
+use super::{SEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX};
+
+pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
+    let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
+        val
+    } else {
+        return; // It's useless so shouldn't lint.
+    };
+    // Do not lint when literal is unsuffixed.
+    if !suffix.is_empty() {
+        if lit_snip.as_bytes()[maybe_last_sep_idx] == b'_' {
+            span_lint_and_sugg(
+                cx,
+                SEPARATED_LITERAL_SUFFIX,
+                lit.span,
+                &format!("{} type suffix should not be separated by an underscore", sugg_type),
+                "remove the underscore",
+                format!("{}{}", &lit_snip[..maybe_last_sep_idx], suffix),
+                Applicability::MachineApplicable,
+            );
+        } else {
+            span_lint_and_sugg(
+                cx,
+                UNSEPARATED_LITERAL_SUFFIX,
+                lit.span,
+                &format!("{} type suffix should be separated by an underscore", sugg_type),
+                "add an underscore",
+                format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
index b32feab4ee3e7e5506b23875170ca01d6d4920b6..7c3f5f22ade0f9ba447d1dc583791b092f1abf80 100644 (file)
@@ -1,15 +1,15 @@
 mod builtin_type_shadow;
 mod double_neg;
+mod literal_suffix;
 mod mixed_case_hex_literals;
 mod redundant_pattern;
 mod unneeded_field_pattern;
 mod unneeded_wildcard_pattern;
-mod unseparated_literal_suffix;
 mod zero_prefixed_literal;
 
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::source::snippet_opt;
-use rustc_ast::ast::{Expr, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
+use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
 use rustc_ast::visit::FnKind;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_lint::{EarlyContext, EarlyLintPass};
     /// ### What it does
     /// Warns if literal suffixes are not separated by an
     /// underscore.
+    /// To enforce unseparated literal suffix style,
+    /// see the `separated_literal_suffix` lint.
     ///
     /// ### Why is this bad?
-    /// It is much less readable.
+    /// Suffix style should be consistent.
     ///
     /// ### Example
     /// ```rust
     /// let y = 123832_i32;
     /// ```
     pub UNSEPARATED_LITERAL_SUFFIX,
-    pedantic,
+    restriction,
     "literals whose suffix is not separated by an underscore"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Warns if literal suffixes are separated by an underscore.
+    /// To enforce separated literal suffix style,
+    /// see the `unseparated_literal_suffix` lint.
+    ///
+    /// ### Why is this bad?
+    /// Suffix style should be consistent.
+    ///
+    /// ### Example
+    /// ```rust
+    /// // Bad
+    /// let y = 123832_i32;
+    ///
+    /// // Good
+    /// let y = 123832i32;
+    /// ```
+    pub SEPARATED_LITERAL_SUFFIX,
+    restriction,
+    "literals whose suffix is separated by an underscore"
+}
+
 declare_clippy_lint! {
     /// ### What it does
     /// Warns if an integral constant literal starts with `0`.
     DOUBLE_NEG,
     MIXED_CASE_HEX_LITERALS,
     UNSEPARATED_LITERAL_SUFFIX,
+    SEPARATED_LITERAL_SUFFIX,
     ZERO_PREFIXED_LITERAL,
     BUILTIN_TYPE_SHADOW,
     REDUNDANT_PATTERN,
@@ -310,6 +335,10 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if in_external_macro(cx.sess, expr.span) {
             return;
         }
+
+        if let ExprKind::Lit(ref lit) = expr.kind {
+            MiscEarlyLints::check_lit(cx, lit);
+        }
         double_neg::check(cx, expr);
     }
 }
@@ -332,7 +361,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
                 LitIntType::Unsigned(ty) => ty.name_str(),
                 LitIntType::Unsuffixed => "",
             };
-            unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
+            literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
             if lit_snip.starts_with("0x") {
                 mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
             } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
@@ -342,7 +371,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
             }
         } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
             let suffix = float_ty.name_str();
-            unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
+            literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unseparated_literal_suffix.rs b/src/tools/clippy/clippy_lints/src/misc_early/unseparated_literal_suffix.rs
deleted file mode 100644 (file)
index 2018aa6..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use rustc_ast::ast::Lit;
-use rustc_errors::Applicability;
-use rustc_lint::EarlyContext;
-
-use super::UNSEPARATED_LITERAL_SUFFIX;
-
-pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
-    let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
-        val
-    } else {
-        return; // It's useless so shouldn't lint.
-    };
-    // Do not lint when literal is unsuffixed.
-    if !suffix.is_empty() && lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
-        span_lint_and_sugg(
-            cx,
-            UNSEPARATED_LITERAL_SUFFIX,
-            lit.span,
-            &format!("{} type suffix should be separated by an underscore", sugg_type),
-            "add an underscore",
-            format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
-            Applicability::MachineApplicable,
-        );
-    }
-}
index 667cdd8302528caec005ef878d7a8f2087d50e70..b593c747498e397b76ba9819b3d7388a87f41bd0 100644 (file)
@@ -8,7 +8,7 @@
 
 declare_clippy_lint! {
     /// ### What it does
-    /// it lints if an exported function, method, trait method with default impl,
+    /// It lints if an exported function, method, trait method with default impl,
     /// or trait method impl is not `#[inline]`.
     ///
     /// ### Why is this bad?
index f351d0098b7509cf6abdddfef53c21a29cc7a663..d41b54745649958de717e61f6d395bfbce0e62e5 100644 (file)
@@ -106,7 +106,7 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
                     }
                     process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders);
                     check_self_named_mod_exists(cx, path, file);
-                }
+                },
                 _ => {},
             }
         }
index 610152a217f1e3dac93028b9b41a945f37b92468..7c4cac29ba8e8c699b7a5cfdeea61678f0a477ba 100644 (file)
@@ -82,6 +82,10 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
+        if in_external_macro(self.cx.sess(), ty.span) {
+            return;
+        }
+
         if let hir::TyKind::Rptr(
             _,
             hir::MutTy {
index 1b2495d764d2a0c650f9f866a153252fa5288b5a..f1be90c44f98b998901e0f4b2462722466c99d69 100644 (file)
@@ -107,14 +107,18 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if let ExprKind::AddrOf(BorrowKind::Ref, mutability, inner) = e.kind {
             if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() {
                 for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
-                    if let [Adjustment {
-                        kind: Adjust::Deref(_), ..
-                    }, Adjustment {
-                        kind: Adjust::Deref(_), ..
-                    }, Adjustment {
-                        kind: Adjust::Borrow(_),
-                        ..
-                    }] = *adj3
+                    if let [
+                        Adjustment {
+                            kind: Adjust::Deref(_), ..
+                        },
+                        Adjustment {
+                            kind: Adjust::Deref(_), ..
+                        },
+                        Adjustment {
+                            kind: Adjust::Borrow(_),
+                            ..
+                        },
+                    ] = *adj3
                     {
                         let help_msg_ty = if matches!(mutability, Mutability::Not) {
                             format!("&{}", ty)
index c5a5cde4b110fccbb874801a53cd72dcc9b2e747..6dae8f320436fc49609aa428cc808a218f84edd7 100644 (file)
@@ -1,9 +1,10 @@
 use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
+use clippy_utils::is_lint_allowed;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::has_drop;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource};
+use rustc_hir::{is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, PatKind, Stmt, StmtKind, UnsafeSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use std::ops::Deref;
@@ -13,7 +14,7 @@
     /// Checks for statements which have no effect.
     ///
     /// ### Why is this bad?
-    /// Similar to dead code, these statements are actually
+    /// Unlike dead code, these statements are actually
     /// executed. However, as they have no effect, all they do is make the code less
     /// readable.
     ///
     "statements with no effect"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for binding to underscore prefixed variable without side-effects.
+    ///
+    /// ### Why is this bad?
+    /// Unlike dead code, these bindings are actually
+    /// executed. However, as they have no effect and shouldn't be used further on, all they
+    /// do is make the code less readable.
+    ///
+    /// ### Known problems
+    /// Further usage of this variable is not checked, which can lead to false positives if it is
+    /// used later in the code.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// let _i_serve_no_purpose = 1;
+    /// ```
+    pub NO_EFFECT_UNDERSCORE_BINDING,
+    pedantic,
+    "binding to `_` prefixed variable with no side-effect"
+}
+
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for expression statements that can be reduced to a
     "outer expressions with no effect"
 }
 
+declare_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION, NO_EFFECT_UNDERSCORE_BINDING]);
+
+impl<'tcx> LateLintPass<'tcx> for NoEffect {
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+        if check_no_effect(cx, stmt) {
+            return;
+        }
+        check_unnecessary_operation(cx, stmt);
+    }
+}
+
+fn check_no_effect(cx: &LateContext<'tcx>, stmt: &'tcx 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");
+            return true;
+        }
+    } else if let StmtKind::Local(local) = stmt.kind {
+        if_chain! {
+            if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id);
+            if let Some(init) = local.init;
+            if !local.pat.span.from_expansion();
+            if has_no_effect(cx, init);
+            if let PatKind::Binding(_, _, ident, _) = local.pat.kind;
+            if ident.name.to_ident_string().starts_with('_');
+            then {
+                span_lint_hir(
+                    cx,
+                    NO_EFFECT_UNDERSCORE_BINDING,
+                    init.hir_id,
+                    stmt.span,
+                    "binding to `_` prefixed variable with no side-effect"
+                );
+                return true;
+            }
+        }
+    }
+    false
+}
+
 fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     if expr.span.from_expansion() {
         return false;
@@ -88,71 +151,59 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     }
 }
 
-declare_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION]);
-
-impl<'tcx> LateLintPass<'tcx> for NoEffect {
-    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
-        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");
-            } else if let Some(reduced) = reduce_expression(cx, expr) {
-                for e in &reduced {
-                    if e.span.from_expansion() {
-                        return;
-                    }
-                }
-                if let ExprKind::Index(..) = &expr.kind {
-                    let snippet;
-                    if_chain! {
-                        if let Some(arr) = snippet_opt(cx, reduced[0].span);
-                        if let Some(func) = snippet_opt(cx, reduced[1].span);
-                        then {
-                            snippet = format!("assert!({}.len() > {});", &arr, &func);
-                        } else {
-                            return;
-                        }
-                    }
-                    span_lint_hir_and_then(
-                        cx,
-                        UNNECESSARY_OPERATION,
-                        expr.hir_id,
-                        stmt.span,
-                        "unnecessary operation",
-                        |diag| {
-                            diag.span_suggestion(
-                                stmt.span,
-                                "statement can be written as",
-                                snippet,
-                                Applicability::MaybeIncorrect,
-                            );
-                        },
-                    );
+fn check_unnecessary_operation(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+    if_chain! {
+        if let StmtKind::Semi(expr) = stmt.kind;
+        if let Some(reduced) = reduce_expression(cx, expr);
+        if !&reduced.iter().any(|e| e.span.from_expansion());
+        then {
+            if let ExprKind::Index(..) = &expr.kind {
+                let snippet;
+                if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) {
+                    snippet = format!("assert!({}.len() > {});", &arr, &func);
                 } else {
-                    let mut snippet = String::new();
-                    for e in reduced {
-                        if let Some(snip) = snippet_opt(cx, e.span) {
-                            snippet.push_str(&snip);
-                            snippet.push(';');
-                        } else {
-                            return;
-                        }
+                    return;
+                }
+                span_lint_hir_and_then(
+                    cx,
+                    UNNECESSARY_OPERATION,
+                    expr.hir_id,
+                    stmt.span,
+                    "unnecessary operation",
+                    |diag| {
+                        diag.span_suggestion(
+                            stmt.span,
+                            "statement can be written as",
+                            snippet,
+                            Applicability::MaybeIncorrect,
+                        );
+                    },
+                );
+            } else {
+                let mut snippet = String::new();
+                for e in reduced {
+                    if let Some(snip) = snippet_opt(cx, e.span) {
+                        snippet.push_str(&snip);
+                        snippet.push(';');
+                    } else {
+                        return;
                     }
-                    span_lint_hir_and_then(
-                        cx,
-                        UNNECESSARY_OPERATION,
-                        expr.hir_id,
-                        stmt.span,
-                        "unnecessary operation",
-                        |diag| {
-                            diag.span_suggestion(
-                                stmt.span,
-                                "statement can be reduced to",
-                                snippet,
-                                Applicability::MachineApplicable,
-                            );
-                        },
-                    );
                 }
+                span_lint_hir_and_then(
+                    cx,
+                    UNNECESSARY_OPERATION,
+                    expr.hir_id,
+                    stmt.span,
+                    "unnecessary operation",
+                    |diag| {
+                        diag.span_suggestion(
+                            stmt.span,
+                            "statement can be reduced to",
+                            snippet,
+                            Applicability::MachineApplicable,
+                        );
+                    },
+                );
             }
         }
     }
index 374b7bd59649e87db0f8ffbbdb22f1ae0b015309..7ebf84d400f569c3f891bc7d417afeeb2d741167 100644 (file)
@@ -44,7 +44,7 @@
     /// Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html)
     /// or specify correct bounds on generic type parameters (`T: Send`).
     pub NON_SEND_FIELDS_IN_SEND_TY,
-    nursery,
+    suspicious,
     "there is field that does not implement `Send` in a `Send` struct"
 }
 
index a62eb0699891bf583fc94e13a6e38629b533f877..cbe1c5d44d513044d745718518c69876f69a10f3 100644 (file)
@@ -22,7 +22,7 @@
     /// expression).
     ///
     /// ### Why is this bad?
-    /// Using the dedicated functions of the Option type is clearer and
+    /// Using the dedicated functions of the `Option` type is clearer and
     /// more concise than an `if let` expression.
     ///
     /// ### Known problems
index d180d6f922710ddc01f1e822184a4630c0e08048..8a36e20fc973d678297d14718039e8913af8acc7 100644 (file)
@@ -3,16 +3,16 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::ptr::get_spans;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty};
+use clippy_utils::ty::walk_ptrs_hir_ty;
 use clippy_utils::{expr_path_res, is_lint_allowed, match_any_diagnostic_items, paths};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
+use rustc_hir::def::Res;
 use rustc_hir::{
-    BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, Impl, ImplItem, ImplItemKind, Item,
-    ItemKind, Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
+    BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, Impl, ImplItem, ImplItemKind, Item, ItemKind,
+    Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
     /// unsafe { std::slice::from_raw_parts(ptr::null(), 0); }
     /// ```
     ///
+    /// ```ignore
     /// // Good
     /// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); }
     /// ```
 impl<'tcx> LateLintPass<'tcx> for Ptr {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Fn(ref sig, _, body_id) = item.kind {
-            check_fn(cx, sig.decl, item.hir_id(), Some(body_id));
+            check_fn(cx, sig.decl, Some(body_id));
         }
     }
 
@@ -164,7 +165,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>)
                     return; // ignore trait impls
                 }
             }
-            check_fn(cx, sig.decl, item.hir_id(), Some(body_id));
+            check_fn(cx, sig.decl, Some(body_id));
         }
     }
 
@@ -175,7 +176,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
             } else {
                 None
             };
-            check_fn(cx, sig.decl, item.hir_id(), body_id);
+            check_fn(cx, sig.decl, body_id);
         }
     }
 
@@ -243,13 +244,10 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 }
 
 #[allow(clippy::too_many_lines)]
-fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: Option<BodyId>) {
-    let fn_def_id = cx.tcx.hir().local_def_id(fn_id);
-    let sig = cx.tcx.fn_sig(fn_def_id);
-    let fn_ty = sig.skip_binder();
+fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option<BodyId>) {
     let body = opt_body_id.map(|id| cx.tcx.hir().body(id));
 
-    for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() {
+    for (idx, arg) in decl.inputs.iter().enumerate() {
         // Honor the allow attribute on parameters. See issue 5644.
         if let Some(body) = &body {
             if is_lint_allowed(cx, PTR_ARG, body.params[idx].hir_id) {
@@ -257,8 +255,20 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
             }
         }
 
-        if let ty::Ref(_, ty, Mutability::Not) = ty.kind() {
-            if is_type_diagnostic_item(cx, ty, sym::Vec) {
+        let (item_name, path) = if_chain! {
+            if let TyKind::Rptr(_, MutTy { ty, mutbl: Mutability::Not }) = arg.kind;
+            if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
+            if let Res::Def(_, did) = path.res;
+            if let Some(item_name) = cx.tcx.get_diagnostic_name(did);
+            then {
+                (item_name, path)
+            } else {
+                continue
+            }
+        };
+
+        match item_name {
+            sym::Vec => {
                 if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
                     span_lint_and_then(
                         cx,
@@ -288,7 +298,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
                         },
                     );
                 }
-            } else if is_type_diagnostic_item(cx, ty, sym::String) {
+            },
+            sym::String => {
                 if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
                     span_lint_and_then(
                         cx,
@@ -310,7 +321,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
                         },
                     );
                 }
-            } else if is_type_diagnostic_item(cx, ty, sym::PathBuf) {
+            },
+            sym::PathBuf => {
                 if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) {
                     span_lint_and_then(
                         cx,
@@ -337,11 +349,10 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
                         },
                     );
                 }
-            } else if match_type(cx, ty, &paths::COW) {
+            },
+            sym::Cow => {
                 if_chain! {
-                    if let TyKind::Rptr(_, MutTy { ty, ..} ) = arg.kind;
-                    if let TyKind::Path(QPath::Resolved(None, pp)) = ty.kind;
-                    if let [ref bx] = *pp.segments;
+                    if let [ref bx] = *path.segments;
                     if let Some(params) = bx.args;
                     if !params.parenthesized;
                     if let Some(inner) = params.args.iter().find_map(|arg| match arg {
@@ -362,7 +373,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
                         );
                     }
                 }
-            }
+            },
+            _ => {},
         }
     }
 
index aa6d254e7a54476acc0c109a431ae6b33d01f388..f63ef163bcbd0f1b76ddfd92fcac4d38b50a48bc 100644 (file)
@@ -4,10 +4,10 @@
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{eq_expr_value, path_to_local_id};
+use clippy_utils::{eq_expr_value, path_to_local, path_to_local_id};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::LangItem::{OptionNone, OptionSome};
+use rustc_hir::LangItem::{OptionNone, OptionSome, ResultOk};
 use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, PatKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -48,16 +48,20 @@ impl QuestionMark {
     /// }
     /// ```
     ///
+    /// ```ignore
+    /// if result.is_err() {
+    ///     return result;
+    /// }
+    /// ```
+    ///
     /// If it matches, it will suggest to use the question mark operator instead
-    fn check_is_none_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    fn check_is_none_or_err_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>) {
         if_chain! {
             if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
             if let ExprKind::MethodCall(segment, _, args, _) = &cond.kind;
-            if segment.ident.name == sym!(is_none);
-            if Self::expression_returns_none(cx, then);
             if let Some(subject) = args.get(0);
-            if Self::is_option(cx, subject);
-
+            if (Self::option_check_and_early_return(cx, subject, then) && segment.ident.name == sym!(is_none)) ||
+                (Self::result_check_and_early_return(cx, subject, then) && segment.ident.name == sym!(is_err));
             then {
                 let mut applicability = Applicability::MachineApplicable;
                 let receiver_str = &Sugg::hir_with_applicability(cx, subject, "..", &mut applicability);
@@ -95,31 +99,24 @@ fn check_is_none_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) {
         }
     }
 
-    fn check_if_let_some_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    fn check_if_let_some_or_err_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>) {
         if_chain! {
             if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) })
                 = higher::IfLet::hir(cx, expr);
-            if Self::is_option(cx, let_expr);
-
             if let PatKind::TupleStruct(ref path1, fields, None) = let_pat.kind;
-            if is_lang_ctor(cx, path1, OptionSome);
+            if (Self::option_check_and_early_return(cx, let_expr, if_else) && is_lang_ctor(cx, path1, OptionSome)) ||
+                (Self::result_check_and_early_return(cx, let_expr, if_else) && is_lang_ctor(cx, path1, ResultOk));
+
             if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind;
             let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
-
             if let ExprKind::Block(block, None) = if_then.kind;
             if block.stmts.is_empty();
             if let Some(trailing_expr) = &block.expr;
             if path_to_local_id(trailing_expr, bind_id);
-
-            if Self::expression_returns_none(cx, if_else);
             then {
                 let mut applicability = Applicability::MachineApplicable;
                 let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
-                let replacement = format!(
-                    "{}{}?",
-                    receiver_str,
-                    if by_ref { ".as_ref()" } else { "" },
-                );
+                let replacement = format!("{}{}?", receiver_str, if by_ref { ".as_ref()" } else { "" },);
 
                 span_lint_and_sugg(
                     cx,
@@ -134,6 +131,14 @@ fn check_if_let_some_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>
         }
     }
 
+    fn result_check_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>, nested_expr: &Expr<'_>) -> bool {
+        Self::is_result(cx, expr) && Self::expression_returns_unmodified_err(cx, nested_expr, expr)
+    }
+
+    fn option_check_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>, nested_expr: &Expr<'_>) -> bool {
+        Self::is_option(cx, expr) && Self::expression_returns_none(cx, nested_expr)
+    }
+
     fn moves_by_default(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
         let expr_ty = cx.typeck_results().expr_ty(expression);
 
@@ -146,6 +151,12 @@ fn is_option(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
         is_type_diagnostic_item(cx, expr_ty, sym::Option)
     }
 
+    fn is_result(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
+        let expr_ty = cx.typeck_results().expr_ty(expression);
+
+        is_type_diagnostic_item(cx, expr_ty, sym::Result)
+    }
+
     fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
         match expression.kind {
             ExprKind::Block(block, _) => {
@@ -161,6 +172,21 @@ fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool
         }
     }
 
+    fn expression_returns_unmodified_err(cx: &LateContext<'_>, expr: &Expr<'_>, cond_expr: &Expr<'_>) -> bool {
+        match expr.kind {
+            ExprKind::Block(block, _) => {
+                if let Some(return_expression) = Self::return_expression(block) {
+                    return Self::expression_returns_unmodified_err(cx, return_expression, cond_expr);
+                }
+
+                false
+            },
+            ExprKind::Ret(Some(ret_expr)) => Self::expression_returns_unmodified_err(cx, ret_expr, cond_expr),
+            ExprKind::Path(_) => path_to_local(expr) == path_to_local(cond_expr),
+            _ => false,
+        }
+    }
+
     fn return_expression<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
         // Check if last expression is a return statement. Then, return the expression
         if_chain! {
@@ -189,7 +215,7 @@ fn return_expression<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 
 impl<'tcx> LateLintPass<'tcx> for QuestionMark {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        Self::check_is_none_and_early_return_none(cx, expr);
-        Self::check_if_let_some_and_early_return_none(cx, expr);
+        Self::check_is_none_or_err_and_early_return(cx, expr);
+        Self::check_if_let_some_or_err_and_early_return(cx, expr);
     }
 }
index 6966230156cfa205060c6656f8b5ceb56a2f5df1..c0e4914efe0bd1778a8ba68d4505c65048bdb310 100644 (file)
@@ -1,7 +1,7 @@
 use crate::rustc_lint::LintContext;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_macro_callsite;
-use clippy_utils::{in_macro, sugg};
+use clippy_utils::sugg;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Block, ExprKind};
@@ -39,7 +39,7 @@
 impl LateLintPass<'_> for SemicolonIfNothingReturned {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
         if_chain! {
-            if !in_macro(block.span);
+            if !block.span.from_expansion();
             if let Some(expr) = block.expr;
             let t_expr = cx.typeck_results().expr_ty(expr);
             if t_expr.is_unit();
index 2ca7c18800ee2e362e299393058239cf35324ce3..64841f33cc385afa389801c7ab9f19d2d3032514 100644 (file)
@@ -162,11 +162,7 @@ fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span)
             (SHADOW_SAME, msg)
         },
         Some(expr) if is_local_used(cx, expr, shadowed) => {
-            let msg = format!(
-                "`{}` is shadowed by `{}` which reuses the original value",
-                snippet(cx, pat.span, "_"),
-                snippet(cx, expr.span, "..")
-            );
+            let msg = format!("`{}` is shadowed", snippet(cx, pat.span, "_"));
             (SHADOW_REUSE, msg)
         },
         _ => {
index 35b6bde56964c17f64c1f711dae4ed77fe9839d0..6435107b8b4643f02f94078b7fe0c70802458d56 100644 (file)
     "calling `as_bytes` on a string literal instead of using a byte string literal"
 }
 
-declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]);
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for slice operations on strings
+    ///
+    /// ### Why is this bad?
+    /// UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character
+    /// counts and string indices. This may lead to panics, and should warrant some test cases
+    /// containing wide UTF-8 characters. This lint is most useful in code that should avoid
+    /// panics at all costs.
+    ///
+    /// ### Known problems
+    /// Probably lots of false positives. If an index comes from a known valid position (e.g.
+    /// obtained via `char_indices` over the same string), it is totally OK.
+    ///
+    /// # Example
+    /// ```rust,should_panic
+    /// &"Ölkanne"[1..];
+    /// ```
+    pub STRING_SLICE,
+    restriction,
+    "slicing a string"
+}
+
+declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN, STRING_SLICE]);
 
 impl<'tcx> LateLintPass<'tcx> for StringAdd {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if in_external_macro(cx.sess(), e.span) {
             return;
         }
-
-        if let ExprKind::Binary(
-            Spanned {
-                node: BinOpKind::Add, ..
-            },
-            left,
-            _,
-        ) = e.kind
-        {
-            if is_string(cx, left) {
-                if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
-                    let parent = get_parent_expr(cx, e);
-                    if let Some(p) = parent {
-                        if let ExprKind::Assign(target, _, _) = p.kind {
-                            // avoid duplicate matches
-                            if SpanlessEq::new(cx).eq_expr(target, left) {
-                                return;
+        match e.kind {
+            ExprKind::Binary(
+                Spanned {
+                    node: BinOpKind::Add, ..
+                },
+                left,
+                _,
+            ) => {
+                if is_string(cx, left) {
+                    if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
+                        let parent = get_parent_expr(cx, e);
+                        if let Some(p) = parent {
+                            if let ExprKind::Assign(target, _, _) = p.kind {
+                                // avoid duplicate matches
+                                if SpanlessEq::new(cx).eq_expr(target, left) {
+                                    return;
+                                }
                             }
                         }
                     }
+                    span_lint(
+                        cx,
+                        STRING_ADD,
+                        e.span,
+                        "you added something to a string. Consider using `String::push_str()` instead",
+                    );
                 }
-                span_lint(
-                    cx,
-                    STRING_ADD,
-                    e.span,
-                    "you added something to a string. Consider using `String::push_str()` instead",
-                );
-            }
-        } else if let ExprKind::Assign(target, src, _) = e.kind {
-            if is_string(cx, target) && is_add(cx, src, target) {
-                span_lint(
-                    cx,
-                    STRING_ADD_ASSIGN,
-                    e.span,
-                    "you assigned the result of adding something to this string. Consider using \
-                     `String::push_str()` instead",
-                );
-            }
+            },
+            ExprKind::Assign(target, src, _) => {
+                if is_string(cx, target) && is_add(cx, src, target) {
+                    span_lint(
+                        cx,
+                        STRING_ADD_ASSIGN,
+                        e.span,
+                        "you assigned the result of adding something to this string. Consider using \
+                         `String::push_str()` instead",
+                    );
+                }
+            },
+            ExprKind::Index(target, _idx) => {
+                let e_ty = cx.typeck_results().expr_ty(target).peel_refs();
+                if matches!(e_ty.kind(), ty::Str) || is_type_diagnostic_item(cx, e_ty, sym::String) {
+                    span_lint(
+                        cx,
+                        STRING_SLICE,
+                        e.span,
+                        "indexing into a string may panic if the index is within a UTF-8 character",
+                    );
+                }
+            },
+            _ => {},
         }
     }
 }
index 44d5ff0b63ad51a5fd2c014f44969d2858644df8..201aa06782405c17921c5c08e2c2b47b9162ef78 100644 (file)
@@ -678,7 +678,7 @@ fn suggestion_with_swapped_ident(
         Some(format!(
             "{}{}{}",
             snippet_with_applicability(cx, expr.span.with_hi(current_ident.span.lo()), "..", applicability),
-            new_ident.to_string(),
+            new_ident,
             snippet_with_applicability(cx, expr.span.with_lo(current_ident.span.hi()), "..", applicability),
         ))
     })
diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
new file mode 100644 (file)
index 0000000..c216a1f
--- /dev/null
@@ -0,0 +1,77 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_hir::{HirId, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Const;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Displays a warning when a struct with a trailing zero-sized array is declared without a `repr` attribute.
+    ///
+    /// ### Why is this bad?
+    /// Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjuction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed.
+    ///
+    /// ### Example
+    /// ```rust
+    /// struct RarelyUseful {
+    ///     some_field: u32,
+    ///     last: [u32; 0],
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// #[repr(C)]
+    /// struct MoreOftenUseful {
+    ///     some_field: usize,
+    ///     last: [u32; 0],
+    /// }
+    /// ```
+    pub TRAILING_EMPTY_ARRAY,
+    nursery,
+    "struct with a trailing zero-sized array but without `#[repr(C)]` or another `repr` attribute"
+}
+declare_lint_pass!(TrailingEmptyArray => [TRAILING_EMPTY_ARRAY]);
+
+impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.hir_id()) {
+            span_lint_and_help(
+                cx,
+                TRAILING_EMPTY_ARRAY,
+                item.span,
+                "trailing zero-sized array in a struct which is not marked with a `repr` attribute",
+                None,
+                &format!(
+                    "consider annotating `{}` with `#[repr(C)]` or another `repr` attribute",
+                    cx.tcx.def_path_str(item.def_id.to_def_id())
+                ),
+            );
+        }
+    }
+}
+
+fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> 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;
+
+        // Then check if that that array zero-sized
+        let length_ldid = cx.tcx.hir().local_def_id(length.hir_id);
+        let length = Const::from_anon_const(cx.tcx, length_ldid);
+        let length = length.try_eval_usize(cx.tcx, cx.param_env);
+        if let Some(length) = length;
+        then {
+            length == 0
+        } else {
+            false
+        }
+    }
+}
+
+fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
+    cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::repr))
+}
index 33ec9c331ce5689c95055c7687823fd957539bbe..e6acf1a94c9299c6b2c59abfaa83a15da0441cb7 100644 (file)
@@ -3,6 +3,7 @@
 mod transmute_int_to_bool;
 mod transmute_int_to_char;
 mod transmute_int_to_float;
+mod transmute_num_to_bytes;
 mod transmute_ptr_to_ptr;
 mod transmute_ptr_to_ref;
 mod transmute_ref_to_ref;
     "transmutes from a float to an integer"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for transmutes from a number to an array of `u8`
+    ///
+    /// ### Why this is bad?
+    /// Transmutes are dangerous and error-prone, whereas `to_ne_bytes`
+    /// is intuitive and safe.
+    ///
+    /// ### Example
+    /// ```rust
+    /// unsafe {
+    ///     let x: [u8; 8] = std::mem::transmute(1i64);
+    /// }
+    ///
+    /// // should be
+    /// let x: [u8; 8] = 0i64.to_ne_bytes();
+    /// ```
+    pub TRANSMUTE_NUM_TO_BYTES,
+    complexity,
+    "transmutes from a number to an array of `u8`"
+}
+
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for transmutes from a pointer to a pointer, or
     TRANSMUTE_INT_TO_BOOL,
     TRANSMUTE_INT_TO_FLOAT,
     TRANSMUTE_FLOAT_TO_INT,
+    TRANSMUTE_NUM_TO_BYTES,
     UNSOUND_COLLECTION_TRANSMUTE,
     TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
 ]);
@@ -365,6 +389,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 linted |= transmute_int_to_bool::check(cx, e, from_ty, to_ty, args);
                 linted |= transmute_int_to_float::check(cx, e, from_ty, to_ty, args, const_context);
                 linted |= transmute_float_to_int::check(cx, e, from_ty, to_ty, args, const_context);
+                linted |= transmute_num_to_bytes::check(cx, e, from_ty, to_ty, args, const_context);
                 linted |= unsound_collection_transmute::check(cx, e, from_ty, to_ty);
 
                 if !linted {
index 8f884e6a4a17b74203247569d2f9b3a925a60c7c..e83d2e06b9a8d26800e7b0a65b6f02e2b42221c8 100644 (file)
@@ -33,7 +33,7 @@ pub(super) fn check<'tcx>(
                     diag.span_suggestion(
                         e.span,
                         "consider using",
-                        format!("std::char::from_u32({}).unwrap()", arg.to_string()),
+                        format!("std::char::from_u32({}).unwrap()", arg),
                         Applicability::Unspecified,
                     );
                 },
index 2b6a4cff81eb5d60549b0dc4d97497e37f89e783..05eee380d6f409bdf275384d089a16b4334abf80 100644 (file)
@@ -36,7 +36,7 @@ pub(super) fn check<'tcx>(
                     diag.span_suggestion(
                         e.span,
                         "consider using",
-                        format!("{}::from_bits({})", to_ty, arg.to_string()),
+                        format!("{}::from_bits({})", to_ty, arg),
                         Applicability::Unspecified,
                     );
                 },
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs
new file mode 100644 (file)
index 0000000..5ba58a7
--- /dev/null
@@ -0,0 +1,49 @@
+use super::TRANSMUTE_NUM_TO_BYTES;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::sugg;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty, UintTy};
+
+/// Checks for `transmute_int_to_float` lint.
+/// Returns `true` if it's triggered, otherwise returns `false`.
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    e: &'tcx Expr<'_>,
+    from_ty: Ty<'tcx>,
+    to_ty: Ty<'tcx>,
+    args: &'tcx [Expr<'_>],
+    const_context: bool,
+) -> bool {
+    match (&from_ty.kind(), &to_ty.kind()) {
+        (ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => {
+            if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) {
+                return false;
+            }
+            if matches!(from_ty.kind(), ty::Float(_)) && const_context {
+                // TODO: Remove when const_float_bits_conv is stabilized
+                // rust#72447
+                return false;
+            }
+
+            span_lint_and_then(
+                cx,
+                TRANSMUTE_NUM_TO_BYTES,
+                e.span,
+                &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
+                |diag| {
+                    let arg = sugg::Sugg::hir(cx, &args[0], "..");
+                    diag.span_suggestion(
+                        e.span,
+                        "consider using `to_ne_bytes()`",
+                        format!("{}.to_ne_bytes()", arg),
+                        Applicability::Unspecified,
+                    );
+                },
+            );
+            true
+        },
+        _ => false,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
new file mode 100644 (file)
index 0000000..11aef50
--- /dev/null
@@ -0,0 +1,226 @@
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
+use clippy_utils::source::{indent_of, reindent_multiline, snippet};
+use clippy_utils::{in_macro, is_lint_allowed};
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, 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};
+use rustc_span::{BytePos, Span};
+use std::borrow::Cow;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `unsafe` blocks without a `// Safety: ` comment
+    /// explaining why the unsafe operations performed inside
+    /// the block are safe.
+    ///
+    /// ### Why is this bad?
+    /// Undocumented unsafe blocks can make it difficult to
+    /// read and maintain code, as well as uncover unsoundness
+    /// and bugs.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::ptr::NonNull;
+    /// let a = &mut 42;
+    ///
+    /// let ptr = unsafe { NonNull::new_unchecked(a) };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::ptr::NonNull;
+    /// let a = &mut 42;
+    ///
+    /// // Safety: references are guaranteed to be non-null.
+    /// let ptr = unsafe { NonNull::new_unchecked(a) };
+    /// ```
+    pub UNDOCUMENTED_UNSAFE_BLOCKS,
+    restriction,
+    "creating an unsafe block without explaining why it is safe"
+}
+
+impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS]);
+
+#[derive(Default)]
+pub struct UndocumentedUnsafeBlocks {
+    pub local_level: u32,
+    pub local_span: Option<Span>,
+    // The local was already checked for an overall safety comment
+    // There is no need to continue checking the blocks in the local
+    pub local_checked: bool,
+    // Since we can only check the blocks from expanded macros
+    // We have to omit the suggestion due to the actual definition
+    // Not being available to us
+    pub macro_expansion: bool,
+}
+
+impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
+    fn check_block(&mut self, cx: &LateContext<'_>, block: &'_ Block<'_>) {
+        if_chain! {
+            if !self.local_checked;
+            if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id);
+            if !in_external_macro(cx.tcx.sess, block.span);
+            if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules;
+            if let Some(enclosing_scope_hir_id) = cx.tcx.hir().get_enclosing_scope(block.hir_id);
+            if self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, block.span) == Some(false);
+            then {
+                let mut span = block.span;
+
+                if let Some(local_span) = self.local_span {
+                    span = local_span;
+
+                    let result = self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, span);
+
+                    if result.unwrap_or(true) {
+                        self.local_checked = true;
+                        return;
+                    }
+                }
+
+                self.lint(cx, span);
+            }
+        }
+    }
+
+    fn check_local(&mut self, cx: &LateContext<'_>, local: &'_ Local<'_>) {
+        if_chain! {
+            if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, local.hir_id);
+            if !in_external_macro(cx.tcx.sess, local.span);
+            if let Some(init) = local.init;
+            then {
+                self.visit_expr(init);
+
+                if self.local_level > 0 {
+                    self.local_span = Some(local.span);
+                }
+            }
+        }
+    }
+
+    fn check_block_post(&mut self, _: &LateContext<'_>, _: &'_ Block<'_>) {
+        self.local_level = self.local_level.saturating_sub(1);
+
+        if self.local_level == 0 {
+            self.local_checked = false;
+            self.local_span = None;
+        }
+    }
+}
+
+impl<'hir> Visitor<'hir> for UndocumentedUnsafeBlocks {
+    type Map = Map<'hir>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_expr(&mut self, ex: &'v Expr<'v>) {
+        match ex.kind {
+            ExprKind::Block(_, _) => self.local_level = self.local_level.saturating_add(1),
+            _ => walk_expr(self, ex),
+        }
+    }
+}
+
+impl UndocumentedUnsafeBlocks {
+    fn block_has_safety_comment(&mut self, tcx: TyCtxt<'_>, enclosing_hir_id: HirId, block_span: Span) -> Option<bool> {
+        let map = tcx.hir();
+        let source_map = tcx.sess.source_map();
+
+        let enclosing_scope_span = map.opt_span(enclosing_hir_id)?;
+
+        let between_span = if in_macro(block_span) {
+            self.macro_expansion = true;
+            enclosing_scope_span.with_hi(block_span.hi())
+        } else {
+            self.macro_expansion = false;
+            enclosing_scope_span.to(block_span)
+        };
+
+        let file_name = source_map.span_to_filename(between_span);
+        let source_file = source_map.get_source_file(&file_name)?;
+
+        let lex_start = (between_span.lo().0 - source_file.start_pos.0 + 1) as usize;
+        let lex_end = (between_span.hi().0 - source_file.start_pos.0) as usize;
+        let src_str = source_file.src.as_ref()?[lex_start..lex_end].to_string();
+
+        let mut pos = 0;
+        let mut comment = false;
+
+        for token in rustc_lexer::tokenize(&src_str) {
+            match token.kind {
+                TokenKind::LineComment { doc_style: None }
+                | TokenKind::BlockComment {
+                    doc_style: None,
+                    terminated: true,
+                } => {
+                    let comment_str = src_str[pos + 2..pos + token.len].to_ascii_uppercase();
+
+                    if comment_str.contains("SAFETY:") {
+                        comment = true;
+                    }
+                },
+                // We need to add all whitespace to `pos` before checking the comment's line number
+                TokenKind::Whitespace => {},
+                _ => {
+                    if comment {
+                        // Get the line number of the "comment" (really wherever the trailing whitespace ended)
+                        let comment_line_num = source_file
+                            .lookup_file_pos_with_col_display(BytePos((lex_start + pos).try_into().unwrap()))
+                            .0;
+                        // Find the block/local's line number
+                        let block_line_num = tcx.sess.source_map().lookup_char_pos(block_span.lo()).line;
+
+                        // Check the comment is immediately followed by the block/local
+                        if block_line_num == comment_line_num + 1 || block_line_num == comment_line_num {
+                            return Some(true);
+                        }
+
+                        comment = false;
+                    }
+                },
+            }
+
+            pos += token.len;
+        }
+
+        Some(false)
+    }
+
+    fn lint(&self, cx: &LateContext<'_>, mut span: Span) {
+        let source_map = cx.tcx.sess.source_map();
+
+        if source_map.is_multiline(span) {
+            span = source_map.span_until_char(span, '\n');
+        }
+
+        if self.macro_expansion {
+            span_lint_and_help(
+                cx,
+                UNDOCUMENTED_UNSAFE_BLOCKS,
+                span,
+                "unsafe block in macro expansion missing a safety comment",
+                None,
+                "consider adding a safety comment in the macro definition",
+            );
+        } else {
+            let block_indent = indent_of(cx, span);
+            let suggestion = format!("// Safety: ...\n{}", snippet(cx, span, ".."));
+
+            span_lint_and_sugg(
+                cx,
+                UNDOCUMENTED_UNSAFE_BLOCKS,
+                span,
+                "unsafe block missing a safety comment",
+                "consider adding a safety comment",
+                reindent_multiline(Cow::Borrowed(&suggestion), true, block_indent).to_string(),
+                Applicability::HasPlaceholders,
+            );
+        }
+    }
+}
index f337dec8f2b9663faf88299154394ba35e8c49ba..f49ce696a04b77d4832cca91d62f78b12964f72d 100644 (file)
@@ -45,7 +45,7 @@
     /// let x = String::from("\u{20ac}");
     /// ```
     pub NON_ASCII_LITERAL,
-    pedantic,
+    restriction,
     "using any literal non-ASCII chars in a string literal instead of using the `\\u` escape"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
new file mode 100644 (file)
index 0000000..f3e8b68
--- /dev/null
@@ -0,0 +1,223 @@
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
+use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty};
+use clippy_utils::{is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq};
+use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, Span};
+
+// TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `set_len()` call that creates `Vec` with uninitialized elements.
+    /// This is commonly caused by calling `set_len()` right after allocating or
+    /// reserving a buffer with `new()`, `default()`, `with_capacity()`, or `reserve()`.
+    ///
+    /// ### Why is this bad?
+    /// It creates a `Vec` with uninitialized data, which leads to
+    /// undefined behavior with most safe operations. Notably, uninitialized
+    /// `Vec<u8>` must not be used with generic `Read`.
+    ///
+    /// Moreover, calling `set_len()` on a `Vec` created with `new()` or `default()`
+    /// creates out-of-bound values that lead to heap memory corruption when used.
+    ///
+    /// ### Known Problems
+    /// This lint only checks directly adjacent statements.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// let mut vec: Vec<u8> = Vec::with_capacity(1000);
+    /// unsafe { vec.set_len(1000); }
+    /// reader.read(&mut vec); // undefined behavior!
+    /// ```
+    ///
+    /// ### How to fix?
+    /// 1. Use an initialized buffer:
+    ///    ```rust,ignore
+    ///    let mut vec: Vec<u8> = vec![0; 1000];
+    ///    reader.read(&mut vec);
+    ///    ```
+    /// 2. Wrap the content in `MaybeUninit`:
+    ///    ```rust,ignore
+    ///    let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000);
+    ///    vec.set_len(1000);  // `MaybeUninit` can be uninitialized
+    ///    ```
+    /// 3. If you are on nightly, `Vec::spare_capacity_mut()` is available:
+    ///    ```rust,ignore
+    ///    let mut vec: Vec<u8> = Vec::with_capacity(1000);
+    ///    let remaining = vec.spare_capacity_mut();  // `&mut [MaybeUninit<u8>]`
+    ///    // perform initialization with `remaining`
+    ///    vec.set_len(...);  // Safe to call `set_len()` on initialized part
+    ///    ```
+    pub UNINIT_VEC,
+    correctness,
+    "Vec with uninitialized data"
+}
+
+declare_lint_pass!(UninitVec => [UNINIT_VEC]);
+
+// FIXME: update to a visitor-based implementation.
+// Threads: https://github.com/rust-lang/rust-clippy/pull/7682#discussion_r710998368
+impl<'tcx> LateLintPass<'tcx> for UninitVec {
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
+        if !in_external_macro(cx.tcx.sess, block.span) {
+            for w in block.stmts.windows(2) {
+                if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind {
+                    handle_uninit_vec_pair(cx, &w[0], expr);
+                }
+            }
+
+            if let (Some(stmt), Some(expr)) = (block.stmts.last(), block.expr) {
+                handle_uninit_vec_pair(cx, stmt, expr);
+            }
+        }
+    }
+}
+
+fn handle_uninit_vec_pair(
+    cx: &LateContext<'tcx>,
+    maybe_init_or_reserve: &'tcx Stmt<'tcx>,
+    maybe_set_len: &'tcx Expr<'tcx>,
+) {
+    if_chain! {
+        if let Some(vec) = extract_init_or_reserve_target(cx, maybe_init_or_reserve);
+        if let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len);
+        if vec.location.eq_expr(cx, set_len_self);
+        if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind();
+        if let ty::Adt(_, substs) = vec_ty.kind();
+        // `#[allow(...)]` attribute can be set on enclosing unsafe block of `set_len()`
+        if !is_lint_allowed(cx, UNINIT_VEC, maybe_set_len.hir_id);
+        then {
+            if vec.has_capacity() {
+                // with_capacity / reserve -> set_len
+
+                // Check T of Vec<T>
+                if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)) {
+                    // FIXME: #7698, false positive of the internal lints
+                    #[allow(clippy::collapsible_span_lint_calls)]
+                    span_lint_and_then(
+                        cx,
+                        UNINIT_VEC,
+                        vec![call_span, maybe_init_or_reserve.span],
+                        "calling `set_len()` immediately after reserving a buffer creates uninitialized values",
+                        |diag| {
+                            diag.help("initialize the buffer or wrap the content in `MaybeUninit`");
+                        },
+                    );
+                }
+            } else {
+                // new / default -> set_len
+                span_lint(
+                    cx,
+                    UNINIT_VEC,
+                    vec![call_span, maybe_init_or_reserve.span],
+                    "calling `set_len()` on empty `Vec` creates out-of-bound values",
+                );
+            }
+        }
+    }
+}
+
+/// The target `Vec` that is initialized or reserved
+#[derive(Clone, Copy)]
+struct TargetVec<'tcx> {
+    location: VecLocation<'tcx>,
+    /// `None` if `reserve()`
+    init_kind: Option<VecInitKind>,
+}
+
+impl TargetVec<'_> {
+    pub fn has_capacity(self) -> bool {
+        !matches!(self.init_kind, Some(VecInitKind::New | VecInitKind::Default))
+    }
+}
+
+#[derive(Clone, Copy)]
+enum VecLocation<'tcx> {
+    Local(HirId),
+    Expr(&'tcx Expr<'tcx>),
+}
+
+impl<'tcx> VecLocation<'tcx> {
+    pub fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+        match self {
+            VecLocation::Local(hir_id) => path_to_local_id(expr, hir_id),
+            VecLocation::Expr(self_expr) => SpanlessEq::new(cx).eq_expr(self_expr, expr),
+        }
+    }
+}
+
+/// Finds the target location where the result of `Vec` initialization is stored
+/// or `self` expression for `Vec::reserve()`.
+fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> Option<TargetVec<'tcx>> {
+    match stmt.kind {
+        StmtKind::Local(local) => {
+            if_chain! {
+                if let Some(init_expr) = local.init;
+                if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind;
+                if let Some(init_kind) = get_vec_init_kind(cx, init_expr);
+                then {
+                    return Some(TargetVec {
+                        location: VecLocation::Local(hir_id),
+                        init_kind: Some(init_kind),
+                    })
+                }
+            }
+        },
+        StmtKind::Expr(expr) | StmtKind::Semi(expr) => match expr.kind {
+            ExprKind::Assign(lhs, rhs, _span) => {
+                if let Some(init_kind) = get_vec_init_kind(cx, rhs) {
+                    return Some(TargetVec {
+                        location: VecLocation::Expr(lhs),
+                        init_kind: Some(init_kind),
+                    });
+                }
+            },
+            ExprKind::MethodCall(path, _, [self_expr, _], _) if is_reserve(cx, path, self_expr) => {
+                return Some(TargetVec {
+                    location: VecLocation::Expr(self_expr),
+                    init_kind: None,
+                });
+            },
+            _ => (),
+        },
+        StmtKind::Item(_) => (),
+    }
+    None
+}
+
+fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>) -> bool {
+    is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::Vec)
+        && path.ident.name.as_str() == "reserve"
+}
+
+/// Returns self if the expression is `Vec::set_len()`
+fn extract_set_len_self(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 {
+            // Extract the first statement/expression
+            match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) {
+                (None, Some(expr)) => Some(expr),
+                (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), _) => Some(expr),
+                _ => None,
+            }
+        } else {
+            None
+        }
+    });
+    match expr.kind {
+        ExprKind::MethodCall(path, _, [self_expr, _], _) => {
+            let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs();
+            if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" {
+                Some((self_expr, expr.span))
+            } else {
+                None
+            }
+        },
+        _ => None,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/unit_hash.rs b/src/tools/clippy/clippy_lints/src/unit_hash.rs
new file mode 100644 (file)
index 0000000..a3a3f2d
--- /dev/null
@@ -0,0 +1,77 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects `().hash(_)`.
+    ///
+    /// ### Why is this bad?
+    /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use std::hash::Hash;
+    /// # use std::collections::hash_map::DefaultHasher;
+    /// # enum Foo { Empty, WithValue(u8) }
+    /// # use Foo::*;
+    /// # let mut state = DefaultHasher::new();
+    /// # let my_enum = Foo::Empty;
+    /// match my_enum {
+    ///        Empty => ().hash(&mut state),
+    ///        WithValue(x) => x.hash(&mut state),
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use std::hash::Hash;
+    /// # use std::collections::hash_map::DefaultHasher;
+    /// # enum Foo { Empty, WithValue(u8) }
+    /// # use Foo::*;
+    /// # let mut state = DefaultHasher::new();
+    /// # let my_enum = Foo::Empty;
+    /// match my_enum {
+    ///        Empty => 0_u8.hash(&mut state),
+    ///        WithValue(x) => x.hash(&mut state),
+    /// }
+    /// ```
+    pub UNIT_HASH,
+    correctness,
+    "hashing a unit value, which does nothing"
+}
+declare_lint_pass!(UnitHash => [UNIT_HASH]);
+
+impl 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;
+            if name_ident.ident.name == sym::hash;
+            if let [recv, state_param] = args;
+            if cx.typeck_results().expr_ty(recv).is_unit();
+            then {
+                span_lint_and_then(
+                    cx,
+                    UNIT_HASH,
+                    expr.span,
+                    "this call to `hash` on the unit type will do nothing",
+                    |diag| {
+                        diag.span_suggestion(
+                            expr.span,
+                            "remove the call to `hash` or consider using",
+                            format!(
+                                "0_u8.hash({})",
+                                snippet(cx, state_param.span, ".."),
+                            ),
+                            Applicability::MaybeIncorrect,
+                        );
+                        diag.note("the implementation of `Hash` for `()` is a no-op");
+                    }
+                );
+            }
+        }
+    }
+}
index dd74bf367f3a58c810d484fe927561d27fb3cf9f..26b56e0f2f316c69b7e53e9f5f50020f25290c3b 100644 (file)
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
@@ -193,10 +193,15 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
             let vec_name = Sugg::hir(cx, &args[0], "..").to_string();
             let unstable = name == "sort_unstable_by";
 
+            if_chain! {
             if let ExprKind::Path(QPath::Resolved(_, Path {
                 segments: [PathSegment { ident: left_name, .. }], ..
-            })) = &left_expr.kind {
-                if left_name == left_ident {
+            })) = &left_expr.kind;
+            if left_name == left_ident;
+            if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| {
+                implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])
+            });
+                then {
                     return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }));
                 }
             }
index a4680ae137b3254e13f3c318448194a10211c8f9..6447e3fa2ca08a85d04716b6bd1f955ba8f5b931 100644 (file)
@@ -13,7 +13,7 @@
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for functions of type Result that contain `expect()` or `unwrap()`
+    /// Checks for functions of type `Result` that contain `expect()` or `unwrap()`
     ///
     /// ### Why is this bad?
     /// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics.
index 6cbada4c1505b5374758d951ca2df152eec9a4d7..122a5ce3fc8f12d19fd8d0ce877ff2a672c01537 100644 (file)
@@ -23,6 +23,14 @@ pub enum DisallowedMethod {
     WithReason { path: String, reason: Option<String> },
 }
 
+/// A single disallowed type, used by the `DISALLOWED_TYPE` lint.
+#[derive(Clone, Debug, Deserialize)]
+#[serde(untagged)]
+pub enum DisallowedType {
+    Simple(String),
+    WithReason { path: String, reason: Option<String> },
+}
+
 /// Conf with parse errors
 #[derive(Default)]
 pub struct TryConf {
@@ -255,7 +263,7 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
     /// Lint: DISALLOWED_TYPE.
     ///
     /// The list of disallowed types, written as fully qualified paths.
-    (disallowed_types: Vec<String> = Vec::new()),
+    (disallowed_types: Vec<crate::utils::conf::DisallowedType> = Vec::new()),
     /// Lint: UNREADABLE_LITERAL.
     ///
     /// Should the fraction of a decimal be linted to include separators.
@@ -280,10 +288,10 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
     ///
     /// The list of imports to always rename, a fully qualified path followed by the rename.
     (enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()),
-    /// Lint: RESTRICTED_SCRIPTS.
+    /// Lint: DISALLOWED_SCRIPT_IDENTS.
     ///
     /// The list of unicode scripts allowed to be used in the scope.
-    (allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
+    (allowed_scripts: Vec<String> = ["Latin"].iter().map(ToString::to_string).collect()),
     /// Lint: NON_SEND_FIELDS_IN_SEND_TY.
     ///
     /// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
index 9f9edbf258ac277831739b1fe2f0fb549ade8b22..824ec53ab9c75301f822805eaf5cf860fe03ff74 100644 (file)
@@ -770,8 +770,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
             let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
             if let Some(ty_did) = path_to_res(cx, &segments[..]).opt_def_id();
             // Check if the matched type is a diagnostic item
-            let diag_items = cx.tcx.diagnostic_items(ty_did.krate);
-            if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None });
+            if let Some(item_name) = cx.tcx.get_diagnostic_name(ty_did);
             then {
                 // TODO: check paths constants from external crates.
                 let cx_snippet = snippet(cx, context.span, "_");
index 0d27874b7affb88d7a4dc16f119469919cbf23ef..99cf4c1ed40fbcbd0a52105176f455b05f230995 100644 (file)
@@ -512,12 +512,21 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
     let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str);
     let mut docs = String::from(&*lines.next()?.as_str());
     let mut in_code_block = false;
+    let mut is_code_block_rust = false;
     for line in lines {
-        docs.push('\n');
         let line = line.as_str();
         let line = &*line;
+
+        // Rustdoc hides code lines starting with `# ` and this removes them from Clippy's lint list :)
+        if is_code_block_rust && line.trim_start().starts_with("# ") {
+            continue;
+        }
+
+        // The line should be represented in the lint list, even if it's just an empty line
+        docs.push('\n');
         if let Some(info) = line.trim_start().strip_prefix("```") {
             in_code_block = !in_code_block;
+            is_code_block_rust = false;
             if in_code_block {
                 let lang = info
                     .trim()
@@ -528,6 +537,8 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
                     .unwrap_or("rust");
                 docs.push_str("```");
                 docs.push_str(lang);
+
+                is_code_block_rust = lang == "rust";
                 continue;
             }
         }
index d124d948b5e69d0b57210f5ffc1e588b786d6b41..d3234b5758a575b2066f57cb673959ef5420ed3b 100644 (file)
@@ -63,13 +63,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg)));
             then {
                 // report the error around the `vec!` not inside `<std macros>:`
-                let span = arg.span
-                    .ctxt()
-                    .outer_expn_data()
-                    .call_site
-                    .ctxt()
-                    .outer_expn_data()
-                    .call_site;
+                let span = arg.span.ctxt().outer_expn_data().call_site;
                 self.check_vec_macro(cx, &vec_args, Mutability::Not, span);
             }
         }
index d8e241d72af48fa51222e9a3e86fbd01c0eb347b..b92b6ca4f4380f981ee9f9ed163d44470994555c 100644 (file)
@@ -1,16 +1,14 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{match_def_path, path_to_local, path_to_local_id, paths};
+use clippy_utils::{path_to_local, path_to_local_id};
 use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{symbol::sym, Span};
-use std::convert::TryInto;
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -41,11 +39,6 @@ pub struct VecInitThenPush {
     searcher: Option<VecPushSearcher>,
 }
 
-#[derive(Clone, Copy)]
-enum VecInitKind {
-    New,
-    WithCapacity(u64),
-}
 struct VecPushSearcher {
     local_id: HirId,
     init: VecInitKind,
@@ -58,7 +51,8 @@ impl VecPushSearcher {
     fn display_err(&self, cx: &LateContext<'_>) {
         match self.init {
             _ if self.found == 0 => return,
-            VecInitKind::WithCapacity(x) if x > self.found => return,
+            VecInitKind::WithLiteralCapacity(x) if x > self.found => return,
+            VecInitKind::WithExprCapacity(_) => return,
             _ => (),
         };
 
@@ -152,37 +146,3 @@ fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx Block<'tcx>) {
         }
     }
 }
-
-fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<VecInitKind> {
-    if let ExprKind::Call(func, args) = expr.kind {
-        match func.kind {
-            ExprKind::Path(QPath::TypeRelative(ty, name))
-                if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec) =>
-            {
-                if name.ident.name == sym::new {
-                    return Some(VecInitKind::New);
-                } else if name.ident.name.as_str() == "with_capacity" {
-                    return args.get(0).and_then(|arg| {
-                        if_chain! {
-                            if let ExprKind::Lit(lit) = &arg.kind;
-                            if let LitKind::Int(num, _) = lit.node;
-                            then {
-                                Some(VecInitKind::WithCapacity(num.try_into().ok()?))
-                            } else {
-                                None
-                            }
-                        }
-                    });
-                }
-            }
-            ExprKind::Path(QPath::Resolved(_, path))
-                if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD)
-                    && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) =>
-            {
-                return Some(VecInitKind::New);
-            }
-            _ => (),
-        }
-    }
-    None
-}
index e7fca3ae5d401b8b3f84c4c71c340145a95d27cb..d99a3d9359e1f439ba973431874f2b2b3c3941d1 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.57"
+version = "0.1.58"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/clippy_utils/src/camel_case.rs b/src/tools/clippy/clippy_utils/src/camel_case.rs
deleted file mode 100644 (file)
index a6636e3..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/// Returns the index of the character after the first camel-case component of `s`.
-#[must_use]
-pub fn until(s: &str) -> usize {
-    let mut iter = s.char_indices();
-    if let Some((_, first)) = iter.next() {
-        if !first.is_uppercase() {
-            return 0;
-        }
-    } else {
-        return 0;
-    }
-    let mut up = true;
-    let mut last_i = 0;
-    for (i, c) in iter {
-        if up {
-            if c.is_lowercase() {
-                up = false;
-            } else {
-                return last_i;
-            }
-        } else if c.is_uppercase() {
-            up = true;
-            last_i = i;
-        } else if !c.is_lowercase() {
-            return i;
-        }
-    }
-    if up { last_i } else { s.len() }
-}
-
-/// Returns index of the last camel-case component of `s`.
-#[must_use]
-pub fn from(s: &str) -> usize {
-    let mut iter = s.char_indices().rev();
-    if let Some((_, first)) = iter.next() {
-        if !first.is_lowercase() {
-            return s.len();
-        }
-    } else {
-        return s.len();
-    }
-    let mut down = true;
-    let mut last_i = s.len();
-    for (i, c) in iter {
-        if down {
-            if c.is_uppercase() {
-                down = false;
-                last_i = i;
-            } else if !c.is_lowercase() {
-                return last_i;
-            }
-        } else if c.is_lowercase() {
-            down = true;
-        } else if c.is_uppercase() {
-            last_i = i;
-        } else {
-            return last_i;
-        }
-    }
-    last_i
-}
-
-#[cfg(test)]
-mod test {
-    use super::{from, until};
-
-    #[test]
-    fn from_full() {
-        assert_eq!(from("AbcDef"), 0);
-        assert_eq!(from("Abc"), 0);
-        assert_eq!(from("ABcd"), 0);
-        assert_eq!(from("ABcdEf"), 0);
-        assert_eq!(from("AabABcd"), 0);
-    }
-
-    #[test]
-    fn from_partial() {
-        assert_eq!(from("abcDef"), 3);
-        assert_eq!(from("aDbc"), 1);
-        assert_eq!(from("aabABcd"), 3);
-    }
-
-    #[test]
-    fn from_not() {
-        assert_eq!(from("AbcDef_"), 7);
-        assert_eq!(from("AbcDD"), 5);
-    }
-
-    #[test]
-    fn from_caps() {
-        assert_eq!(from("ABCD"), 4);
-    }
-
-    #[test]
-    fn until_full() {
-        assert_eq!(until("AbcDef"), 6);
-        assert_eq!(until("Abc"), 3);
-    }
-
-    #[test]
-    fn until_not() {
-        assert_eq!(until("abcDef"), 0);
-        assert_eq!(until("aDbc"), 0);
-    }
-
-    #[test]
-    fn until_partial() {
-        assert_eq!(until("AbcDef_"), 6);
-        assert_eq!(until("CallTypeC"), 8);
-        assert_eq!(until("AbcDD"), 3);
-    }
-
-    #[test]
-    fn until_caps() {
-        assert_eq!(until("ABCD"), 0);
-    }
-}
index 8bf31807d55d1441d74e503a42e29334aee365f0..04347672e0fbb35e12241580aacfeac22de28fbc 100644 (file)
@@ -155,6 +155,19 @@ pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self)
             _ => None,
         }
     }
+
+    /// Returns the integer value or `None` if `self` or `val_type` is not integer type.
+    pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option<FullInt> {
+        if let Constant::Int(const_int) = *self {
+            match *val_type.kind() {
+                ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
+                ty::Uint(_) => Some(FullInt::U(const_int)),
+                _ => None,
+            }
+        } else {
+            None
+        }
+    }
 }
 
 /// Parses a `LitKind` to a `Constant`.
@@ -202,6 +215,52 @@ 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(
+    lcx: &LateContext<'tcx>,
+    typeck_results: &ty::TypeckResults<'tcx>,
+    e: &Expr<'_>,
+) -> Option<FullInt> {
+    constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e))
+}
+
+#[derive(Copy, Clone, Debug, Eq)]
+pub enum FullInt {
+    S(i128),
+    U(u128),
+}
+
+impl PartialEq for FullInt {
+    #[must_use]
+    fn eq(&self, other: &Self) -> bool {
+        self.cmp(other) == Ordering::Equal
+    }
+}
+
+impl PartialOrd for FullInt {
+    #[must_use]
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for FullInt {
+    #[must_use]
+    fn cmp(&self, other: &Self) -> Ordering {
+        use FullInt::{S, U};
+
+        fn cmp_s_u(s: i128, u: u128) -> Ordering {
+            u128::try_from(s).map_or(Ordering::Less, |x| x.cmp(&u))
+        }
+
+        match (*self, *other) {
+            (S(s), S(o)) => s.cmp(&o),
+            (U(s), U(o)) => s.cmp(&o),
+            (S(s), U(o)) => cmp_s_u(s, o),
+            (U(s), S(o)) => cmp_s_u(o, s).reverse(),
+        }
+    }
+}
+
 /// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`.
 pub fn constant_context<'a, 'tcx>(
     lcx: &'a LateContext<'tcx>,
index 9302e5c21faa4f7606d485726bcbf256aba1cfb8..d47b002ad7aca95a94336ac60e6b6f511913d3b4 100644 (file)
@@ -72,7 +72,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
 /// 6  |     let other_f64_nan = 0.0f64 / 0.0;
 ///    |                         ^^^^^^^^^^^^
 ///    |
-///    = help: Consider using `f64::NAN` if you would like a constant representing NaN
+///    = help: consider using `f64::NAN` if you would like a constant representing NaN
 /// ```
 pub fn span_lint_and_help<'a, T: LintContext>(
     cx: &'a T,
index ba4d50bf74469307cbfedc51e1c979c532c74d4e..b3a9a1de2ec93daa57b44eace9a0d66d1781f6d3 100644 (file)
@@ -1,14 +1,17 @@
-//! This module contains functions that retrieves specifiec elements.
+//! This module contains functions that retrieve specific elements.
 
 #![deny(clippy::missing_docs_in_private_items)]
 
-use crate::{is_expn_of, match_def_path, paths};
+use crate::ty::is_type_diagnostic_item;
+use crate::{is_expn_of, last_path_segment, match_def_path, path_to_local_id, 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, LoopSource, MatchSource, Node, Pat, StmtKind, UnOp};
+use rustc_hir::{
+    Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, PatKind, QPath, StmtKind, UnOp,
+};
 use rustc_lint::LateContext;
-use rustc_span::{sym, ExpnKind, Span, Symbol};
+use rustc_span::{sym, symbol, ExpnKind, Span, Symbol};
 
 /// 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)`.
@@ -510,6 +513,8 @@ pub struct FormatArgsExpn<'tcx> {
     pub format_string_parts: &'tcx [Expr<'tcx>],
     /// Symbols corresponding to [`Self::format_string_parts`]
     pub format_string_symbols: Vec<Symbol>,
+    /// Match arm patterns, the `arg0`, etc. from the next field `args`
+    pub arg_names: &'tcx [Pat<'tcx>],
     /// Expressions like `ArgumentV1::new(arg0, Debug::fmt)`
     pub args: &'tcx [Expr<'tcx>],
     /// The final argument passed to `Arguments::new_v1_formatted`, if applicable
@@ -554,6 +559,7 @@ pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
                     _ => None,
                 })
                 .collect();
+            if let PatKind::Tuple(arg_names, None) = arm.pat.kind;
             if let ExprKind::Array(args) = arm.body.kind;
             then {
                 Some(FormatArgsExpn {
@@ -561,6 +567,7 @@ pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
                     value_args,
                     format_string_parts,
                     format_string_symbols,
+                    arg_names,
                     args,
                     fmt_expr,
                 })
@@ -569,6 +576,112 @@ pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
             }
         }
     }
+
+    /// 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 Some(j) = self
+                                .arg_names
+                                .iter()
+                                .position(|pat| path_to_local_id(arg_name, pat.hir_id));
+                            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 }
+        }
+    }
 }
 
 /// Checks if a `let` statement is from a `for` loop desugaring.
@@ -615,11 +728,8 @@ impl PanicExpn<'tcx> {
     /// Parses an expanded `panic!` invocation
     pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
         if_chain! {
-            if let ExprKind::Block(block, _) = expr.kind;
-            if let Some(init) = block.expr;
-            if let ExprKind::Call(_, [format_args]) = init.kind;
+            if let ExprKind::Call(_, [format_args]) = expr.kind;
             let expn_data = expr.span.ctxt().outer_expn_data();
-            if let ExprKind::AddrOf(_, _, format_args) = format_args.kind;
             if let Some(format_args) = FormatArgsExpn::parse(format_args);
             then {
                 Some(PanicExpn {
@@ -632,3 +742,51 @@ pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
         }
     }
 }
+
+/// A parsed `Vec` initialization expression
+#[derive(Clone, Copy)]
+pub enum VecInitKind {
+    /// `Vec::new()`
+    New,
+    /// `Vec::default()` or `Default::default()`
+    Default,
+    /// `Vec::with_capacity(123)`
+    WithLiteralCapacity(u64),
+    /// `Vec::with_capacity(slice.len())`
+    WithExprCapacity(HirId),
+}
+
+/// Checks if given expression is an initialization of `Vec` and returns its kind.
+pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<VecInitKind> {
+    if let ExprKind::Call(func, args) = expr.kind {
+        match func.kind {
+            ExprKind::Path(QPath::TypeRelative(ty, name))
+                if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec) =>
+            {
+                if name.ident.name == sym::new {
+                    return Some(VecInitKind::New);
+                } else if name.ident.name == symbol::kw::Default {
+                    return Some(VecInitKind::Default);
+                } else if name.ident.name.as_str() == "with_capacity" {
+                    let arg = args.get(0)?;
+                    if_chain! {
+                        if let ExprKind::Lit(lit) = &arg.kind;
+                        if let LitKind::Int(num, _) = lit.node;
+                        then {
+                            return Some(VecInitKind::WithLiteralCapacity(num.try_into().ok()?))
+                        }
+                    }
+                    return Some(VecInitKind::WithExprCapacity(arg.hir_id));
+                }
+            },
+            ExprKind::Path(QPath::Resolved(_, path))
+                if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD)
+                    && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) =>
+            {
+                return Some(VecInitKind::Default);
+            },
+            _ => (),
+        }
+    }
+    None
+}
index c47aa9170e547c597711785aae6df8d83dc74844..086fbc9d3ddddcfba357846e45e897f806118814 100644 (file)
@@ -37,7 +37,6 @@
 #[allow(clippy::module_name_repetitions)]
 pub mod ast_utils;
 pub mod attrs;
-pub mod camel_case;
 pub mod comparisons;
 pub mod consts;
 pub mod diagnostics;
@@ -50,6 +49,7 @@
 pub mod ptr;
 pub mod qualify_min_const_fn;
 pub mod source;
+pub mod str_utils;
 pub mod sugg;
 pub mod ty;
 pub mod usage;
 use rustc_hir::def_id::DefId;
 use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{self, walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
 use rustc_hir::{
-    def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, GenericArgs, HirId, Impl,
-    ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node, Param, Pat,
-    PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp,
+    def, Arm, BindingAnnotation, Block, 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,
 };
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::exports::Export;
@@ -251,11 +253,7 @@ pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem
 /// Returns `true` if this `span` was expanded by any macro.
 #[must_use]
 pub fn in_macro(span: Span) -> bool {
-    if span.from_expansion() {
-        !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
-    } else {
-        false
-    }
+    span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
 }
 
 pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
@@ -714,7 +712,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 /// Checks if the top level expression can be moved into a closure as is.
 /// Currently checks for:
 /// * Break/Continue outside the given loop HIR ids.
-/// * Yield/Return statments.
+/// * Yield/Return statements.
 /// * Inline assembly.
 /// * Usages of a field of a local where the type of the local can be partially moved.
 ///
@@ -846,10 +844,13 @@ fn pat_capture_kind(cx: &LateContext<'_>, pat: &Pat<'_>) -> CaptureKind {
     let mut capture_expr_ty = e;
 
     for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) {
-        if let [Adjustment {
-            kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
-            target,
-        }, ref adjust @ ..] = *cx
+        if let [
+            Adjustment {
+                kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
+                target,
+            },
+            ref adjust @ ..,
+        ] = *cx
             .typeck_results()
             .adjustments()
             .get(child_id)
@@ -1234,9 +1235,7 @@ pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Opti
     for (_, node) in tcx.hir().parent_iter(expr.hir_id) {
         match node {
             Node::Expr(
-                e
-                @
-                Expr {
+                e @ Expr {
                     kind: ExprKind::Loop(..) | ExprKind::Closure(..),
                     ..
                 },
@@ -1285,10 +1284,9 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool
     }
     let enclosing_body = cx.tcx.hir().local_def_id(cx.tcx.hir().enclosing_body_owner(e.hir_id));
     if let Some((Constant::Int(v), _)) = constant(cx, cx.tcx.typeck(enclosing_body), e) {
-        value == v
-    } else {
-        false
+        return value == v;
     }
+    false
 }
 
 /// Checks whether the given expression is a constant literal of the given value.
@@ -1315,7 +1313,7 @@ pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 
 /// Returns the pre-expansion span if is this comes from an expansion of the
 /// macro `name`.
-/// See also `is_direct_expn_of`.
+/// See also [`is_direct_expn_of`].
 #[must_use]
 pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
     loop {
@@ -1338,13 +1336,13 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
 
 /// Returns the pre-expansion span if the span directly comes from an expansion
 /// of the macro `name`.
-/// The difference with `is_expn_of` is that in
-/// ```rust,ignore
+/// The difference with [`is_expn_of`] is that in
+/// ```rust
+/// # macro_rules! foo { ($e:tt) => { $e } }; macro_rules! bar { ($e:expr) => { $e } }
 /// foo!(bar!(42));
 /// ```
 /// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
-/// `bar!` by
-/// `is_direct_expn_of`.
+/// from `bar!` by `is_direct_expn_of`.
 #[must_use]
 pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
     if span.from_expansion() {
@@ -1467,11 +1465,9 @@ pub fn is_self(slf: &Param<'_>) -> bool {
 }
 
 pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
-    if_chain! {
-        if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind;
-        if let Res::SelfTy(..) = path.res;
-        then {
-            return true
+    if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind {
+        if let Res::SelfTy(..) = path.res {
+            return true;
         }
     }
     false
@@ -1646,7 +1642,6 @@ pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool {
         did,
         &[
             &paths::BEGIN_PANIC,
-            &paths::BEGIN_PANIC_FMT,
             &paths::PANIC_ANY,
             &paths::PANICKING_PANIC,
             &paths::PANICKING_PANIC_FMT,
@@ -1698,10 +1693,12 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool {
 pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
     if let ExprKind::Call(
         _,
-        &[Expr {
-            kind: ExprKind::Closure(_, _, body, _, _),
-            ..
-        }],
+        &[
+            Expr {
+                kind: ExprKind::Closure(_, _, body, _, _),
+                ..
+            },
+        ],
     ) = body.value.kind
     {
         if let ExprKind::Block(
@@ -2063,27 +2060,80 @@ macro_rules! unwrap_cargo_metadata {
 }
 
 pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
-    if_chain! {
-        if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
-        if let Res::Def(_, def_id) = path.res;
-        then {
-            cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr)
-        } else {
-            false
+    if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
+        if let Res::Def(_, def_id) = path.res {
+            return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr);
         }
     }
+    false
 }
 
-/// Checks whether item either has `test` attribute applied, or
-/// is a module with `test` in its name.
-pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
-    if let Some(def_id) = tcx.hir().opt_local_def_id(item.hir_id()) {
-        if tcx.has_attr(def_id.to_def_id(), sym::test) {
-            return true;
+struct VisitConstTestStruct<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    names: Vec<Symbol>,
+    found: bool,
+}
+impl<'hir> ItemLikeVisitor<'hir> for VisitConstTestStruct<'hir> {
+    fn visit_item(&mut self, item: &Item<'_>) {
+        if let ItemKind::Const(ty, _body) = item.kind {
+            if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
+                // We could also check for the type name `test::TestDescAndFn`
+                // and the `#[rustc_test_marker]` attribute?
+                if let Res::Def(DefKind::Struct, _) = path.res {
+                    let has_test_marker = self
+                        .tcx
+                        .hir()
+                        .attrs(item.hir_id())
+                        .iter()
+                        .any(|a| a.has_name(sym::rustc_test_marker));
+                    if has_test_marker && self.names.contains(&item.ident.name) {
+                        self.found = true;
+                    }
+                }
+            }
         }
     }
+    fn visit_trait_item(&mut self, _: &TraitItem<'_>) {}
+    fn visit_impl_item(&mut self, _: &ImplItem<'_>) {}
+    fn visit_foreign_item(&mut self, _: &ForeignItem<'_>) {}
+}
+
+/// Checks if the function containing the given `HirId` is a `#[test]` function
+///
+/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
+pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
+    let names: Vec<_> = tcx
+        .hir()
+        .parent_iter(id)
+        // Since you can nest functions we need to collect all until we leave
+        // function scope
+        .filter_map(|(_id, node)| {
+            if let Node::Item(item) = node {
+                if let ItemKind::Fn(_, _, _) = item.kind {
+                    return Some(item.ident.name);
+                }
+            }
+            None
+        })
+        .collect();
+    let parent_mod = tcx.parent_module(id);
+    let mut vis = VisitConstTestStruct {
+        tcx,
+        names,
+        found: false,
+    };
+    tcx.hir().visit_item_likes_in_module(parent_mod, &mut vis);
+    vis.found
+}
 
-    matches!(item.kind, ItemKind::Mod(..)) && item.ident.name.as_str().contains("test")
+/// Checks whether item either has `test` attribute applied, or
+/// is a module with `test` in its name.
+///
+/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
+pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
+    is_in_test_function(tcx, item.hir_id())
+        || matches!(item.kind, ItemKind::Mod(..))
+            && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests")
 }
 
 macro_rules! op_utils {
index e43c5756021452e30e5f0fdb5706858a5c7237c8..501b08a47f161103b9f34b46760ae2502df8d4bc 100644 (file)
 #[cfg(feature = "metadata-collector-lint")]
 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
+pub const ASSERT_EQ_MACRO: [&str; 3] = ["core", "macros", "assert_eq"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const ASSERT_MACRO: [&str; 4] = ["core", "macros", "builtin", "assert"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+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"];
-pub(super) const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"];
 /// Preferably use the diagnostic item `sym::Borrow` where possible
 pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
 pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"];
 pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
 #[cfg(feature = "internal-lints")]
 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"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const EPRINTLN_MACRO: [&str; 3] = ["std", "macros", "eprintln"];
 pub const EXIT: [&str; 3] = ["std", "process", "exit"];
 pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"];
 pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"];
 pub const FILE: [&str; 3] = ["std", "fs", "File"];
 pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const FORMAT_ARGS_MACRO: [&str; 4] = ["core", "macros", "builtin", "format_args"];
 pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
 pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"];
 pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"];
 pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
 pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
 pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const PRINT_MACRO: [&str; 3] = ["std", "macros", "print"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const PRINTLN_MACRO: [&str; 3] = ["std", "macros", "println"];
 pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"];
 pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"];
 pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
 pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
 pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
 pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const WRITE_MACRO: [&str; 3] = ["core", "macros", "write"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const WRITELN_MACRO: [&str; 3] = ["core", "macros", "writeln"];
diff --git a/src/tools/clippy/clippy_utils/src/str_utils.rs b/src/tools/clippy/clippy_utils/src/str_utils.rs
new file mode 100644 (file)
index 0000000..cba96e0
--- /dev/null
@@ -0,0 +1,230 @@
+/// Dealing with sting indices can be hard, this struct ensures that both the
+/// character and byte index are provided for correct indexing.
+#[derive(Debug, Default, PartialEq, Eq)]
+pub struct StrIndex {
+    pub char_index: usize,
+    pub byte_index: usize,
+}
+
+impl StrIndex {
+    pub fn new(char_index: usize, byte_index: usize) -> Self {
+        Self { char_index, byte_index }
+    }
+}
+
+/// Returns the index of the character after the first camel-case component of `s`.
+///
+/// ```
+/// assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
+/// assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
+/// assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
+/// assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
+/// ```
+#[must_use]
+pub fn camel_case_until(s: &str) -> StrIndex {
+    let mut iter = s.char_indices().enumerate();
+    if let Some((_char_index, (_, first))) = iter.next() {
+        if !first.is_uppercase() {
+            return StrIndex::new(0, 0);
+        }
+    } else {
+        return StrIndex::new(0, 0);
+    }
+    let mut up = true;
+    let mut last_index = StrIndex::new(0, 0);
+    for (char_index, (byte_index, c)) in iter {
+        if up {
+            if c.is_lowercase() {
+                up = false;
+            } else {
+                return last_index;
+            }
+        } else if c.is_uppercase() {
+            up = true;
+            last_index.byte_index = byte_index;
+            last_index.char_index = char_index;
+        } else if !c.is_lowercase() {
+            return StrIndex::new(char_index, byte_index);
+        }
+    }
+
+    if up {
+        last_index
+    } else {
+        StrIndex::new(s.chars().count(), s.len())
+    }
+}
+
+/// Returns index of the last camel-case component of `s`.
+///
+/// ```
+/// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
+/// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
+/// assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
+/// assert_eq!(camel_case_start("abcd"), StrIndex::new(4, 4));
+/// assert_eq!(camel_case_start("\u{f6}\u{f6}cd"), StrIndex::new(4, 6));
+/// ```
+#[must_use]
+pub fn camel_case_start(s: &str) -> StrIndex {
+    let char_count = s.chars().count();
+    let range = 0..char_count;
+    let mut iter = range.rev().zip(s.char_indices().rev());
+    if let Some((char_index, (_, first))) = iter.next() {
+        if !first.is_lowercase() {
+            return StrIndex::new(char_index, s.len());
+        }
+    } else {
+        return StrIndex::new(char_count, s.len());
+    }
+    let mut down = true;
+    let mut last_index = StrIndex::new(char_count, s.len());
+    for (char_index, (byte_index, c)) in iter {
+        if down {
+            if c.is_uppercase() {
+                down = false;
+                last_index.byte_index = byte_index;
+                last_index.char_index = char_index;
+            } else if !c.is_lowercase() {
+                return last_index;
+            }
+        } else if c.is_lowercase() {
+            down = true;
+        } else if c.is_uppercase() {
+            last_index.byte_index = byte_index;
+            last_index.char_index = char_index;
+        } else {
+            return last_index;
+        }
+    }
+    last_index
+}
+
+/// Dealing with sting comparison can be complicated, this struct ensures that both the
+/// character and byte count are provided for correct indexing.
+#[derive(Debug, Default, PartialEq, Eq)]
+pub struct StrCount {
+    pub char_count: usize,
+    pub byte_count: usize,
+}
+
+impl StrCount {
+    pub fn new(char_count: usize, byte_count: usize) -> Self {
+        Self { char_count, byte_count }
+    }
+}
+
+/// Returns the number of chars that match from the start
+///
+/// ```
+/// assert_eq!(count_match_start("hello_mouse", "hello_penguin"), StrCount::new(6, 6));
+/// assert_eq!(count_match_start("hello_clippy", "bye_bugs"), StrCount::new(0, 0));
+/// assert_eq!(count_match_start("hello_world", "hello_world"), StrCount::new(11, 11));
+/// assert_eq!(count_match_start("T\u{f6}ffT\u{f6}ff", "T\u{f6}ff"), StrCount::new(4, 5));
+/// ```
+#[must_use]
+pub fn count_match_start(str1: &str, str2: &str) -> StrCount {
+    // (char_index, char1)
+    let char_count = str1.chars().count();
+    let iter1 = (0..=char_count).zip(str1.chars());
+    // (byte_index, char2)
+    let iter2 = str2.char_indices();
+
+    iter1
+        .zip(iter2)
+        .take_while(|((_, c1), (_, c2))| c1 == c2)
+        .last()
+        .map_or_else(StrCount::default, |((char_index, _), (byte_index, character))| {
+            StrCount::new(char_index + 1, byte_index + character.len_utf8())
+        })
+}
+
+/// Returns the number of chars and bytes that match from the end
+///
+/// ```
+/// assert_eq!(count_match_end("hello_cat", "bye_cat"), StrCount::new(4, 4));
+/// assert_eq!(count_match_end("if_item_thing", "enum_value"), StrCount::new(0, 0));
+/// assert_eq!(count_match_end("Clippy", "Clippy"), StrCount::new(6, 6));
+/// assert_eq!(count_match_end("MyT\u{f6}ff", "YourT\u{f6}ff"), StrCount::new(4, 5));
+/// ```
+#[must_use]
+pub fn count_match_end(str1: &str, str2: &str) -> StrCount {
+    let char_count = str1.chars().count();
+    if char_count == 0 {
+        return StrCount::default();
+    }
+
+    // (char_index, char1)
+    let iter1 = (0..char_count).rev().zip(str1.chars().rev());
+    // (byte_index, char2)
+    let byte_count = str2.len();
+    let iter2 = str2.char_indices().rev();
+
+    iter1
+        .zip(iter2)
+        .take_while(|((_, c1), (_, c2))| c1 == c2)
+        .last()
+        .map_or_else(StrCount::default, |((char_index, _), (byte_index, _))| {
+            StrCount::new(char_count - char_index, byte_count - byte_index)
+        })
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn camel_case_start_full() {
+        assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
+        assert_eq!(camel_case_start("Abc"), StrIndex::new(0, 0));
+        assert_eq!(camel_case_start("ABcd"), StrIndex::new(0, 0));
+        assert_eq!(camel_case_start("ABcdEf"), StrIndex::new(0, 0));
+        assert_eq!(camel_case_start("AabABcd"), StrIndex::new(0, 0));
+    }
+
+    #[test]
+    fn camel_case_start_partial() {
+        assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
+        assert_eq!(camel_case_start("aDbc"), StrIndex::new(1, 1));
+        assert_eq!(camel_case_start("aabABcd"), StrIndex::new(3, 3));
+        assert_eq!(camel_case_start("\u{f6}\u{f6}AabABcd"), StrIndex::new(2, 4));
+    }
+
+    #[test]
+    fn camel_case_start_not() {
+        assert_eq!(camel_case_start("AbcDef_"), StrIndex::new(7, 7));
+        assert_eq!(camel_case_start("AbcDD"), StrIndex::new(5, 5));
+        assert_eq!(camel_case_start("all_small"), StrIndex::new(9, 9));
+        assert_eq!(camel_case_start("\u{f6}_all_small"), StrIndex::new(11, 12));
+    }
+
+    #[test]
+    fn camel_case_start_caps() {
+        assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
+    }
+
+    #[test]
+    fn camel_case_until_full() {
+        assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
+        assert_eq!(camel_case_until("Abc"), StrIndex::new(3, 3));
+        assert_eq!(camel_case_until("Abc\u{f6}\u{f6}\u{f6}"), StrIndex::new(6, 9));
+    }
+
+    #[test]
+    fn camel_case_until_not() {
+        assert_eq!(camel_case_until("abcDef"), StrIndex::new(0, 0));
+        assert_eq!(camel_case_until("aDbc"), StrIndex::new(0, 0));
+    }
+
+    #[test]
+    fn camel_case_until_partial() {
+        assert_eq!(camel_case_until("AbcDef_"), StrIndex::new(6, 6));
+        assert_eq!(camel_case_until("CallTypeC"), StrIndex::new(8, 8));
+        assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
+        assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
+    }
+
+    #[test]
+    fn until_caps() {
+        assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
+    }
+}
index 5b0efb1fd7132811c449eb408729f4ea08f40870..01fb944cc36f64dcfd266726ce70bf4aa6ba5418 100644 (file)
 use std::fmt::Display;
 use std::ops::{Add, Neg, Not, Sub};
 
-/// A helper type to build suggestion correctly handling parenthesis.
+/// A helper type to build suggestion correctly handling parentheses.
 #[derive(Clone, PartialEq)]
 pub enum Sugg<'a> {
-    /// An expression that never needs parenthesis such as `1337` or `[0; 42]`.
+    /// An expression that never needs parentheses such as `1337` or `[0; 42]`.
     NonParen(Cow<'a, str>),
     /// An expression that does not fit in other variants.
     MaybeParen(Cow<'a, str>),
@@ -283,7 +283,7 @@ pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> {
         }
     }
 
-    /// Adds parenthesis to any expression that might need them. Suitable to the
+    /// Adds parentheses to any expression that might need them. Suitable to the
     /// `self` argument of a method call
     /// (e.g., to build `bar.foo()` or `(1 + 2).foo()`).
     pub fn maybe_par(self) -> Self {
index 6ebe1a0028a315fff24a116237b52c245cf0ac5f..ca64ac7de3eea4b98fd9f609a82d153008dbc9df 100644 (file)
@@ -367,3 +367,13 @@ pub fn same_type_and_consts(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
         _ => a == b,
     }
 }
+
+/// Checks if a given type looks safe to be uninitialized.
+pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
+    match ty.kind() {
+        ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component),
+        ty::Tuple(types) => types.types().all(|ty| is_uninit_value_valid_for_ty(cx, ty)),
+        ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did),
+        _ => false,
+    }
+}
index 004eb28b44640fb59ab3d43c31203ab97c622870..bd32696d6dbda7d15b4b6975a6195f673d2f76c7 100644 (file)
@@ -16,6 +16,7 @@ because that's clearly a non-descriptive name.
   - [Edition 2018 tests](#edition-2018-tests)
   - [Testing manually](#testing-manually)
   - [Lint declaration](#lint-declaration)
+  - [Lint registration](#lint-registration)
   - [Lint passes](#lint-passes)
   - [Emitting a lint](#emitting-a-lint)
   - [Adding the lint logic](#adding-the-lint-logic)
@@ -43,9 +44,9 @@ take a look at our [lint naming guidelines][lint_naming]. To get started on this
 lint you can run `cargo dev new_lint --name=foo_functions --pass=early
 --category=pedantic` (category will default to nursery if not provided). This
 command will create two files: `tests/ui/foo_functions.rs` and
-`clippy_lints/src/foo_functions.rs`, as well as run `cargo dev update_lints` to
-register the new lint. For cargo lints, two project hierarchies (fail/pass) will
-be created by default under `tests/ui-cargo`.
+`clippy_lints/src/foo_functions.rs`, as well as
+[registering the lint](#lint-registration). For cargo lints, two project
+hierarchies (fail/pass) will be created by default under `tests/ui-cargo`.
 
 Next, we'll open up these files and add our lint!
 
@@ -220,32 +221,34 @@ declare_lint_pass!(FooFunctions => [FOO_FUNCTIONS]);
 impl EarlyLintPass for FooFunctions {}
 ```
 
-Normally after declaring the lint, we have to run `cargo dev update_lints`,
-which updates some files, so Clippy knows about the new lint. Since we used
-`cargo dev new_lint ...` to generate the lint declaration, this was done
-automatically. While `update_lints` automates most of the things, it doesn't
-automate everything. We will have to register our lint pass manually in the
-`register_plugins` function in `clippy_lints/src/lib.rs`:
+[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
+[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
+[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
+[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
+
+## Lint registration
+
+When using `cargo dev new_lint`, the lint is automatically registered and
+nothing more has to be done.
+
+When declaring a new lint by hand and `cargo dev update_lints` is used, the lint
+pass may have to be registered manually in the `register_plugins` function in
+`clippy_lints/src/lib.rs`:
 
 ```rust
-store.register_early_pass(|| box foo_functions::FooFunctions);
+store.register_early_pass(|| Box::new(foo_functions::FooFunctions));
 ```
 
 As one may expect, there is a corresponding `register_late_pass` method
 available as well. Without a call to one of `register_early_pass` or
 `register_late_pass`, the lint pass in question will not be run.
 
-One reason that `cargo dev` does not automate this step is that multiple lints
-can use the same lint pass, so registering the lint pass may already be done
-when adding a new lint. Another reason that this step is not automated is that
-the order that the passes are registered determines the order the passes
-actually run, which in turn affects the order that any emitted lints are output
-in.
-
-[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
-[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
-[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
-[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
+One reason that `cargo dev update_lints` does not automate this step is that
+multiple lints can use the same lint pass, so registering the lint pass may
+already be done when adding a new lint. Another reason that this step is not
+automated is that the order that the passes are registered determines the order
+the passes actually run, which in turn affects the order that any emitted lints
+are output in.
 
 ## Lint passes
 
@@ -564,7 +567,8 @@ in the following steps:
     /// <The configuration field doc comment>
     (configuration_ident: Type = DefaultValue),
     ```
-    The doc comment will be automatically added to the lint documentation.
+    The doc comment is automatically added to the documentation of the listed lints. The default
+    value will be formatted using the `Debug` implementation of the type.
 2. Adding the configuration value to the lint impl struct:
     1. This first requires the definition of a lint impl struct. Lint impl structs are usually
         generated with the `declare_lint_pass!` macro. This struct needs to be defined manually
index ff2e0417435bfe72edb635fd725cb476cf47a335..57a90a924ec3cf9fd0a58ab6d3d969a2b1b91ef8 100644 (file)
@@ -96,6 +96,7 @@ cargo dev setup git-hook
 # (experimental) Setup Clippy to work with IntelliJ-Rust
 cargo dev setup intellij
 ```
+More about intellij command usage and reasons [here](../CONTRIBUTING.md#intellij-rust)
 
 ## lintcheck
 `cargo lintcheck` will build and run clippy on a fixed set of crates and generate a log of the results.  
index f98819303e6827c80e373954d725f0483de628d2..09554c08987b1ae66902243826bcfec6b063c91f 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-10-07"
+channel = "nightly-2021-11-04"
 components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
index e8b1640c8693e5907cf93e491a713658b17e6a63..f25cf1d3ef56185243762a4f3296f4f7ca2eca98 100644 (file)
@@ -104,7 +104,10 @@ fn extern_flags() -> String {
 }
 
 fn default_config() -> compiletest::Config {
-    let mut config = compiletest::Config::default();
+    let mut config = compiletest::Config {
+        edition: Some("2021".into()),
+        ..compiletest::Config::default()
+    };
 
     if let Ok(filters) = env::var("TESTNAME") {
         config.filters = filters.split(',').map(std::string::ToString::to_string).collect();
@@ -149,6 +152,19 @@ fn run_ui(cfg: &mut compiletest::Config) {
     compiletest::run_tests(cfg);
 }
 
+fn run_ui_test(cfg: &mut compiletest::Config) {
+    cfg.mode = TestMode::Ui;
+    cfg.src_base = Path::new("tests").join("ui_test");
+    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
+    let rustcflags = cfg.target_rustcflags.get_or_insert_with(Default::default);
+    let len = rustcflags.len();
+    rustcflags.push_str(" --test");
+    compiletest::run_tests(cfg);
+    if let Some(ref mut flags) = &mut cfg.target_rustcflags {
+        flags.truncate(len);
+    }
+}
+
 fn run_internal_tests(cfg: &mut compiletest::Config) {
     // only run internal tests with the internal-tests feature
     if !RUN_INTERNAL_TESTS {
@@ -312,6 +328,7 @@ fn compile_test() {
     prepare_env();
     let mut config = default_config();
     run_ui(&mut config);
+    run_ui_test(&mut config);
     run_ui_toml(&mut config);
     run_ui_cargo(&mut config);
     run_internal_tests(&mut config);
index bd342e390f52f3d065bdef329f2c082ed3f322c7..7d6edc2b1e095fb1cb59e81cca7b28bba7f44497 100644 (file)
@@ -1,7 +1,10 @@
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(clippy::assertions_on_constants)]
+#![feature(path_file_prefix)]
 
+use std::cmp::Ordering;
+use std::ffi::OsStr;
 use std::fs::{self, DirEntry};
 use std::path::Path;
 
@@ -21,29 +24,39 @@ fn test_missing_tests() {
     }
 }
 
-/*
-Test for missing files.
-
-Since rs files are alphabetically before stderr/stdout, we can sort by the full name
-and iter in that order. If we've seen the file stem for the first time and it's not
-a rust file, it means the rust file has to be missing.
-*/
+// Test for missing files.
 fn explore_directory(dir: &Path) -> Vec<String> {
     let mut missing_files: Vec<String> = Vec::new();
     let mut current_file = String::new();
     let mut files: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect();
-    files.sort_by_key(std::fs::DirEntry::path);
+    files.sort_by(|x, y| {
+        match x.path().file_prefix().cmp(&y.path().file_prefix()) {
+            Ordering::Equal => (),
+            ord => return ord,
+        }
+        // Sort rs files before the others if they share the same prefix. So when we see
+        // the file prefix for the first time and it's not a rust file, it means the rust
+        // file has to be missing.
+        match (
+            x.path().extension().and_then(OsStr::to_str),
+            y.path().extension().and_then(OsStr::to_str),
+        ) {
+            (Some("rs"), _) => Ordering::Less,
+            (_, Some("rs")) => Ordering::Greater,
+            _ => Ordering::Equal,
+        }
+    });
     for entry in &files {
         let path = entry.path();
         if path.is_dir() {
             missing_files.extend(explore_directory(&path));
         } else {
-            let file_stem = path.file_stem().unwrap().to_str().unwrap().to_string();
+            let file_prefix = path.file_prefix().unwrap().to_str().unwrap().to_string();
             if let Some(ext) = path.extension() {
                 match ext.to_str().unwrap() {
-                    "rs" => current_file = file_stem.clone(),
+                    "rs" => current_file = file_prefix.clone(),
                     "stderr" | "stdout" => {
-                        if file_stem != current_file {
+                        if file_prefix != current_file {
                             missing_files.push(path.to_str().unwrap().to_string());
                         }
                     },
index 2ec0efe4c10a5125ed60d9220ebdb419bc78214a..95b8c6dfe89eea23435b45dfd0ae6386ae34367a 100644 (file)
@@ -11,6 +11,6 @@ fn main() {
     Symbol::intern("foo") == rustc_span::sym::clippy;
     Symbol::intern("foo") == rustc_span::symbol::kw::SelfLower;
     Symbol::intern("foo") != rustc_span::symbol::kw::SelfUpper;
-    Ident::invalid().name == rustc_span::sym::clippy;
-    rustc_span::sym::clippy == Ident::invalid().name;
+    Ident::empty().name == rustc_span::sym::clippy;
+    rustc_span::sym::clippy == Ident::empty().name;
 }
index 87e1b3a2ee76a9ebd8d53268d29835a5a3904a34..ad6937cf60a65c71035adde5ff4ea9a6681ce63b 100644 (file)
@@ -11,6 +11,6 @@ fn main() {
     Symbol::intern("foo").as_str() == "clippy";
     Symbol::intern("foo").to_string() == "self";
     Symbol::intern("foo").to_ident_string() != "Self";
-    &*Ident::invalid().as_str() == "clippy";
-    "clippy" == Ident::invalid().to_string();
+    &*Ident::empty().as_str() == "clippy";
+    "clippy" == Ident::empty().to_string();
 }
index b1284b7c8ffd036393046ea09ab8dcebd6abe0cd..12e05eaa7a09ab1070681f50275dbffff46e065d 100644 (file)
@@ -26,14 +26,14 @@ LL |     Symbol::intern("foo").to_ident_string() != "Self";
 error: unnecessary `Symbol` to string conversion
   --> $DIR/unnecessary_symbol_str.rs:14:5
    |
-LL |     &*Ident::invalid().as_str() == "clippy";
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::invalid().name == rustc_span::sym::clippy`
+LL |     &*Ident::empty().as_str() == "clippy";
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::clippy`
 
 error: unnecessary `Symbol` to string conversion
   --> $DIR/unnecessary_symbol_str.rs:15:5
    |
-LL |     "clippy" == Ident::invalid().to_string();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::invalid().name`
+LL |     "clippy" == Ident::empty().to_string();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name`
 
 error: aborting due to 5 previous errors
 
index 33a3ef7513631aab7d1fb367d49c9993ab1c44ad..e678c896fd3e3b3dc8e7bcba92fb5b641a6f8797 100644 (file)
@@ -1,5 +1,3 @@
-// edition:2018
-
 #![warn(clippy::too_many_lines)]
 
 // This function should be considered one line.
index 7551cac9f504b968918e65f3d82ae0ee1b800cf0..d736bf899735a5cfb5ed02eef151b4c20cbd635f 100644 (file)
@@ -1,5 +1,5 @@
 error: this function has too many lines (2/1)
-  --> $DIR/test.rs:20:1
+  --> $DIR/test.rs:18:1
    |
 LL | / fn too_many_lines() {
 LL | |     println!("This is bad.");
@@ -10,7 +10,7 @@ LL | | }
    = note: `-D clippy::too-many-lines` implied by `-D warnings`
 
 error: this function has too many lines (4/1)
-  --> $DIR/test.rs:26:1
+  --> $DIR/test.rs:24:1
    |
 LL | / async fn async_too_many_lines() {
 LL | |     println!("This is bad.");
@@ -19,7 +19,7 @@ LL | | }
    | |_^
 
 error: this function has too many lines (4/1)
-  --> $DIR/test.rs:32:1
+  --> $DIR/test.rs:30:1
    |
 LL | / fn closure_too_many_lines() {
 LL | |     let _ = {
@@ -30,7 +30,7 @@ LL | | }
    | |_^
 
 error: this function has too many lines (2/1)
-  --> $DIR/test.rs:54:1
+  --> $DIR/test.rs:52:1
    |
 LL | / fn comment_before_code() {
 LL | |     let _ = "test";
index dac4446703b0f5e24977580aa667815b866b286f..6cb9e2ef95467be59c0ba74c9dc8d25de2411c09 100644 (file)
@@ -7,5 +7,9 @@ disallowed-types = [
     "std::time::Instant",
     "std::io::Read",
     "std::primitive::usize",
-    "bool"
+    "bool",
+    # can give path and reason with an inline table
+    { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
+    # can use an inline table but omit reason
+    { path = "std::net::TcpListener" },
 ]
index 0871a3073abd302c4f86b342f01b6203af164fae..410f076505511c6d84c4eae6224ae4625517d516 100644 (file)
@@ -25,6 +25,10 @@ fn const_generics<const C: usize>() {}
 
 static BAD: foo::atomic::AtomicPtr<()> = foo::atomic::AtomicPtr::new(std::ptr::null_mut());
 
+fn ip(_: std::net::Ipv4Addr) {}
+
+fn listener(_: std::net::TcpListener) {}
+
 #[allow(clippy::diverging_sub_expression)]
 fn main() {
     let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
index 90ce7db2cc4e6b4007fe5d439784b09a5abba4e9..08a400a83675b916a59ca597472bdd6a7c6cb524 100644 (file)
@@ -60,59 +60,73 @@ error: `usize` is not allowed according to config
 LL | struct GenArg<const U: usize>([u8; U]);
    |                        ^^^^^
 
+error: `std::net::Ipv4Addr` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:28:10
+   |
+LL | fn ip(_: std::net::Ipv4Addr) {}
+   |          ^^^^^^^^^^^^^^^^^^
+   |
+   = note: no IPv4 allowed (from clippy.toml)
+
+error: `std::net::TcpListener` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:30:16
+   |
+LL | fn listener(_: std::net::TcpListener) {}
+   |                ^^^^^^^^^^^^^^^^^^^^^
+
 error: `std::collections::HashMap` is not allowed according to config
-  --> $DIR/conf_disallowed_type.rs:30:48
+  --> $DIR/conf_disallowed_type.rs:34:48
    |
 LL |     let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
    |                                                ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `std::collections::HashMap` is not allowed according to config
-  --> $DIR/conf_disallowed_type.rs:30:12
+  --> $DIR/conf_disallowed_type.rs:34:12
    |
 LL |     let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `std::time::Instant` is not allowed according to config
-  --> $DIR/conf_disallowed_type.rs:31:13
+  --> $DIR/conf_disallowed_type.rs:35:13
    |
 LL |     let _ = Sneaky::now();
    |             ^^^^^^
 
 error: `std::sync::atomic::AtomicU32` is not allowed according to config
-  --> $DIR/conf_disallowed_type.rs:32:13
+  --> $DIR/conf_disallowed_type.rs:36:13
    |
 LL |     let _ = foo::atomic::AtomicU32::new(0);
    |             ^^^^^^^^^^^^^^^^^^^^^^
 
 error: `std::sync::atomic::AtomicU32` is not allowed according to config
-  --> $DIR/conf_disallowed_type.rs:33:17
+  --> $DIR/conf_disallowed_type.rs:37:17
    |
 LL |     static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `std::sync::atomic::AtomicU32` is not allowed according to config
-  --> $DIR/conf_disallowed_type.rs:33:48
+  --> $DIR/conf_disallowed_type.rs:37:48
    |
 LL |     static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1);
    |                                                ^^^^^^^^^^^^^^^^^^^^^^
 
 error: `syn::TypePath` is not allowed according to config
-  --> $DIR/conf_disallowed_type.rs:34:43
+  --> $DIR/conf_disallowed_type.rs:38:43
    |
 LL |     let _: std::collections::BTreeMap<(), syn::TypePath> = Default::default();
    |                                           ^^^^^^^^^^^^^
 
 error: `syn::Ident` is not allowed according to config
-  --> $DIR/conf_disallowed_type.rs:35:13
+  --> $DIR/conf_disallowed_type.rs:39:13
    |
 LL |     let _ = syn::Ident::new("", todo!());
    |             ^^^^^^^^^^
 
 error: `usize` is not allowed according to config
-  --> $DIR/conf_disallowed_type.rs:37:12
+  --> $DIR/conf_disallowed_type.rs:41:12
    |
 LL |     let _: usize = 64_usize;
    |            ^^^^^
 
-error: aborting due to 19 previous errors
+error: aborting due to 21 previous errors
 
index 2180f848d62cd256f7538d100d6cf5c634398ec2..cb516d0f97783fee0b7b4a71c3cc9336a5072c64 100644 (file)
@@ -1,3 +1,4 @@
+//FIXME: suggestions are wrongly expanded, this should be fixed along with #7843
 #![allow(non_fmt_panics)]
 
 macro_rules! assert_const {
@@ -6,7 +7,6 @@ macro_rules! assert_const {
         debug_assert!($len < 0);
     };
 }
-
 fn main() {
     assert!(true);
     assert!(false);
@@ -14,7 +14,7 @@ fn main() {
     assert!(false, "false message");
 
     let msg = "panic message";
-    assert!(false, msg.to_uppercase());
+    assert!(false, "{}", msg.to_uppercase());
 
     const B: bool = true;
     assert!(B);
index 4ca1e6f6e88cc783cf0b2ecd25d9b0c44ddfea5e..ec80ec702fb574ad4cf6380b9e7b2179230a8c84 100644 (file)
@@ -26,22 +26,13 @@ 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, "false message")` should probably be replaced
+error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced
   --> $DIR/assertions_on_constants.rs:14:5
    |
 LL |     assert!(false, "false message");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: use `panic!("false message")` or `unreachable!("false message")`
-   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `assert!(false, msg.to_uppercase())` should probably be replaced
-  --> $DIR/assertions_on_constants.rs:17:5
-   |
-LL |     assert!(false, msg.to_uppercase());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: use `panic!(msg.to_uppercase())` or `unreachable!(msg.to_uppercase())`
+   = 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)
 
 error: `assert!(true)` will be optimized out by the compiler
@@ -62,13 +53,13 @@ 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, "C message")` should probably be replaced
+error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced
   --> $DIR/assertions_on_constants.rs:24:5
    |
 LL |     assert!(C, "C message");
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: use `panic!("C message")` or `unreachable!("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)
 
 error: `debug_assert!(true)` will be optimized out by the compiler
@@ -80,5 +71,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 9 previous errors
+error: aborting due to 8 previous errors
 
index 9b1a7ac3ba9de85493244232abca89ce4d5d5452..e20b58269b93e60485b68b74618b3bc4a6fe77d3 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-// edition:2018
 
 #![feature(async_closure)]
 #![warn(clippy::async_yields_async)]
index 731c094edb42b16b7a8488293fb09affc43d92db..c1dfa398450250f6d67a6d1290e34c139865d8e1 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-// edition:2018
 
 #![feature(async_closure)]
 #![warn(clippy::async_yields_async)]
index 3f2051458f677c219930503943f5ef00ae44224a..b0c4215e7ddf1be1c4bbcaeb031e3896096f9386 100644 (file)
@@ -1,5 +1,5 @@
 error: an async construct yields a type which is itself awaitable
-  --> $DIR/async_yields_async.rs:40:9
+  --> $DIR/async_yields_async.rs:39:9
    |
 LL |        let _h = async {
    |   ____________________-
@@ -20,7 +20,7 @@ LL +         }.await
    |
 
 error: an async construct yields a type which is itself awaitable
-  --> $DIR/async_yields_async.rs:45:9
+  --> $DIR/async_yields_async.rs:44:9
    |
 LL |       let _i = async {
    |  ____________________-
@@ -33,7 +33,7 @@ LL | |     };
    | |_____- outer async construct
 
 error: an async construct yields a type which is itself awaitable
-  --> $DIR/async_yields_async.rs:51:9
+  --> $DIR/async_yields_async.rs:50:9
    |
 LL |        let _j = async || {
    |   _______________________-
@@ -53,7 +53,7 @@ LL +         }.await
    |
 
 error: an async construct yields a type which is itself awaitable
-  --> $DIR/async_yields_async.rs:56:9
+  --> $DIR/async_yields_async.rs:55:9
    |
 LL |       let _k = async || {
    |  _______________________-
@@ -66,7 +66,7 @@ LL | |     };
    | |_____- outer async construct
 
 error: an async construct yields a type which is itself awaitable
-  --> $DIR/async_yields_async.rs:58:23
+  --> $DIR/async_yields_async.rs:57:23
    |
 LL |     let _l = async || CustomFutureType;
    |                       ^^^^^^^^^^^^^^^^
@@ -76,7 +76,7 @@ LL |     let _l = async || CustomFutureType;
    |                       help: consider awaiting this value: `CustomFutureType.await`
 
 error: an async construct yields a type which is itself awaitable
-  --> $DIR/async_yields_async.rs:64:9
+  --> $DIR/async_yields_async.rs:63:9
    |
 LL |       let _m = async || {
    |  _______________________-
index 170955e726cc573853764fbaaf16b187450bada7..0251fada9e85a6ea8aa5dbfc954292835fab394c 100644 (file)
@@ -113,3 +113,10 @@ macro_rules! default_numeric_fallback {
         let x = 22;
     };
 }
+
+#[macro_export]
+macro_rules! mut_mut {
+    () => {
+        let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32;
+    };
+}
index 0458950edee1c9660d41a4e15a974038f3949eac..dd6640a387a23877548f96c8b6a40185b27c7cfd 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 #![warn(clippy::await_holding_lock)]
 
 use std::sync::Mutex;
index a5fcff7e0e44363f02087f6c87fdfacc46638734..ddfb104cdfbd07ab1207f133e075182b3d409d0e 100644 (file)
@@ -1,12 +1,12 @@
 error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
-  --> $DIR/await_holding_lock.rs:7:9
+  --> $DIR/await_holding_lock.rs:6:9
    |
 LL |     let guard = x.lock().unwrap();
    |         ^^^^^
    |
    = note: `-D clippy::await-holding-lock` implied by `-D warnings`
 note: these are all the await points this lock is held through
-  --> $DIR/await_holding_lock.rs:7:5
+  --> $DIR/await_holding_lock.rs:6:5
    |
 LL | /     let guard = x.lock().unwrap();
 LL | |     baz().await
@@ -14,13 +14,13 @@ LL | | }
    | |_^
 
 error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
-  --> $DIR/await_holding_lock.rs:28:9
+  --> $DIR/await_holding_lock.rs:27:9
    |
 LL |     let guard = x.lock().unwrap();
    |         ^^^^^
    |
 note: these are all the await points this lock is held through
-  --> $DIR/await_holding_lock.rs:28:5
+  --> $DIR/await_holding_lock.rs:27:5
    |
 LL | /     let guard = x.lock().unwrap();
 LL | |
@@ -32,13 +32,13 @@ LL | | }
    | |_^
 
 error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
-  --> $DIR/await_holding_lock.rs:41:13
+  --> $DIR/await_holding_lock.rs:40:13
    |
 LL |         let guard = x.lock().unwrap();
    |             ^^^^^
    |
 note: these are all the await points this lock is held through
-  --> $DIR/await_holding_lock.rs:41:9
+  --> $DIR/await_holding_lock.rs:40:9
    |
 LL | /         let guard = x.lock().unwrap();
 LL | |         baz().await
@@ -46,13 +46,13 @@ LL | |     };
    | |_____^
 
 error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
-  --> $DIR/await_holding_lock.rs:53:13
+  --> $DIR/await_holding_lock.rs:52:13
    |
 LL |         let guard = x.lock().unwrap();
    |             ^^^^^
    |
 note: these are all the await points this lock is held through
-  --> $DIR/await_holding_lock.rs:53:9
+  --> $DIR/await_holding_lock.rs:52:9
    |
 LL | /         let guard = x.lock().unwrap();
 LL | |         baz().await
index 88841597bb60bf5bc8a8bff346fdfc9391a40cfe..23b7095de3a39ae31a36bbc37a7b625c38bec5b3 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 #![warn(clippy::await_holding_refcell_ref)]
 
 use std::cell::RefCell;
index 55e41dbca96f834046b43c624e377ddcb6bbb6d3..67cc0032be2f46742725351dd9beca969d458b4e 100644 (file)
@@ -1,12 +1,12 @@
 error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
-  --> $DIR/await_holding_refcell_ref.rs:7:9
+  --> $DIR/await_holding_refcell_ref.rs:6:9
    |
 LL |     let b = x.borrow();
    |         ^
    |
    = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings`
 note: these are all the await points this ref is held through
-  --> $DIR/await_holding_refcell_ref.rs:7:5
+  --> $DIR/await_holding_refcell_ref.rs:6:5
    |
 LL | /     let b = x.borrow();
 LL | |     baz().await
@@ -14,13 +14,13 @@ LL | | }
    | |_^
 
 error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
-  --> $DIR/await_holding_refcell_ref.rs:12:9
+  --> $DIR/await_holding_refcell_ref.rs:11:9
    |
 LL |     let b = x.borrow_mut();
    |         ^
    |
 note: these are all the await points this ref is held through
-  --> $DIR/await_holding_refcell_ref.rs:12:5
+  --> $DIR/await_holding_refcell_ref.rs:11:5
    |
 LL | /     let b = x.borrow_mut();
 LL | |     baz().await
@@ -28,13 +28,13 @@ LL | | }
    | |_^
 
 error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
-  --> $DIR/await_holding_refcell_ref.rs:33:9
+  --> $DIR/await_holding_refcell_ref.rs:32:9
    |
 LL |     let b = x.borrow_mut();
    |         ^
    |
 note: these are all the await points this ref is held through
-  --> $DIR/await_holding_refcell_ref.rs:33:5
+  --> $DIR/await_holding_refcell_ref.rs:32:5
    |
 LL | /     let b = x.borrow_mut();
 LL | |
@@ -46,13 +46,13 @@ LL | | }
    | |_^
 
 error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
-  --> $DIR/await_holding_refcell_ref.rs:45:9
+  --> $DIR/await_holding_refcell_ref.rs:44:9
    |
 LL |     let b = x.borrow_mut();
    |         ^
    |
 note: these are all the await points this ref is held through
-  --> $DIR/await_holding_refcell_ref.rs:45:5
+  --> $DIR/await_holding_refcell_ref.rs:44:5
    |
 LL | /     let b = x.borrow_mut();
 LL | |
@@ -64,13 +64,13 @@ LL | | }
    | |_^
 
 error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
-  --> $DIR/await_holding_refcell_ref.rs:60:13
+  --> $DIR/await_holding_refcell_ref.rs:59:13
    |
 LL |         let b = x.borrow_mut();
    |             ^
    |
 note: these are all the await points this ref is held through
-  --> $DIR/await_holding_refcell_ref.rs:60:9
+  --> $DIR/await_holding_refcell_ref.rs:59:9
    |
 LL | /         let b = x.borrow_mut();
 LL | |         baz().await
@@ -78,13 +78,13 @@ LL | |     };
    | |_____^
 
 error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
-  --> $DIR/await_holding_refcell_ref.rs:72:13
+  --> $DIR/await_holding_refcell_ref.rs:71:13
    |
 LL |         let b = x.borrow_mut();
    |             ^
    |
 note: these are all the await points this ref is held through
-  --> $DIR/await_holding_refcell_ref.rs:72:9
+  --> $DIR/await_holding_refcell_ref.rs:71:9
    |
 LL | /         let b = x.borrow_mut();
 LL | |         baz().await
index 8ee0969b0f0761b16371eb485570ac83ad3abe5d..ebc1ed5587fe30a9b8f6675e6ac51b79f1a9725f 100644 (file)
@@ -92,4 +92,27 @@ fn main() {
     (1i64).checked_rem_euclid(-1i64).unwrap() as u64;
     (1i64).checked_rem_euclid(-1i64).unwrap() as u128;
     (1isize).checked_rem_euclid(-1isize).unwrap() as usize;
+
+    // no lint for `cast_possible_truncation`
+    // with `signum` method call (see issue #5395)
+    let x: i64 = 5;
+    let _ = x.signum() as i32;
+
+    let s = x.signum();
+    let _ = s as i32;
+
+    // Test for signed min
+    (-99999999999i64).min(1) as i8; // should be linted because signed
+
+    // Test for various operations that remove enough bits for the result to fit
+    (999999u64 & 1) as u8;
+    (999999u64 % 15) as u8;
+    (999999u64 / 0x1_0000_0000_0000) as u16;
+    ({ 999999u64 >> 56 }) as u8;
+    ({
+        let x = 999999u64;
+        x.min(1)
+    }) as u8;
+    999999u64.clamp(0, 255) as u8;
+    999999u64.clamp(0, 256) as u8; // should still be linted
 }
index 4c66d736494843955903b39f917ac5ee187f61d5..edf8790cf33d861c3978669145d5e500f2232314 100644 (file)
@@ -138,5 +138,17 @@ error: casting `isize` to `usize` may lose the sign of the value
 LL |     -1isize as usize;
    |     ^^^^^^^^^^^^^^^^
 
-error: aborting due to 22 previous errors
+error: casting `i64` to `i8` may truncate the value
+  --> $DIR/cast.rs:105:5
+   |
+LL |     (-99999999999i64).min(1) as i8; // should be linted because signed
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: casting `u64` to `u8` may truncate the value
+  --> $DIR/cast.rs:117:5
+   |
+LL |     999999u64.clamp(0, 256) as u8; // should still be linted
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 24 previous errors
 
index 4e583a25b94c2a517555585caf76f5631e263847..061a4ab9b2ef8da2809901e986d07b3b45ab64ca 100644 (file)
@@ -1,7 +1,7 @@
 // run-rustfix
 #![feature(stmt_expr_attributes)]
 
-#![allow(unused, clippy::no_effect)]
+#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
 #![warn(clippy::deprecated_cfg_attr)]
 
 // This doesn't get linted, see known problems
index 9c0fcf6fb454c4ac00a89b8bcb1b5b34aa58e2cf..035169fab85befb570e7d06ebcc5ff518652109b 100644 (file)
@@ -1,7 +1,7 @@
 // run-rustfix
 #![feature(stmt_expr_attributes)]
 
-#![allow(unused, clippy::no_effect)]
+#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
 #![warn(clippy::deprecated_cfg_attr)]
 
 // This doesn't get linted, see known problems
diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7868-aux.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7868-aux.rs
new file mode 100644 (file)
index 0000000..bee2989
--- /dev/null
@@ -0,0 +1,3 @@
+fn zero() {
+    unsafe { 0 };
+}
index 4feab7910b7445da53bf0c73ac25bea9ce160a66..9b68cac7ff4854abc60352d7c8cbff472604cf44 100644 (file)
@@ -7,7 +7,6 @@
 // in type inference.
 #![feature(trivial_bounds)]
 #![allow(unused)]
-
 trait A {}
 
 impl A for i32 {}
@@ -22,9 +21,9 @@ struct TwoStrs(str, str)
 
 fn unsized_local()
 where
-    for<'a> Dst<A + 'a>: Sized,
+    for<'a> Dst<dyn A + 'a>: Sized,
 {
-    let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
+    let x: Dst<dyn A> = *(Box::new(Dst { x: 1 }) as Box<Dst<dyn A>>);
 }
 
 fn return_str() -> str
index 9a89047f072777cd7f6bf3f5588083be74b7f6b0..79018080886c0561d33fc88fe31890911f4ccd9f 100644 (file)
@@ -1,30 +1,34 @@
-error: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/ice-3969.rs:25:17
+error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
+  --> $DIR/ice-3969.rs:20:10
    |
-LL |     for<'a> Dst<A + 'a>: Sized,
-   |                 ^^^^^^ help: use `dyn`: `dyn A + 'a`
+LL |     str: Sized;
+   |          ^^^^^
    |
-   = note: `-D bare-trait-objects` implied by `-D warnings`
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: `-D trivial-bounds` implied by `-D warnings`
 
-error: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/ice-3969.rs:27:16
+error: trait bound for<'a> Dst<(dyn A + 'a)>: std::marker::Sized does not depend on any type or lifetime parameters
+  --> $DIR/ice-3969.rs:24:30
    |
-LL |     let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
-   |                ^ help: use `dyn`: `dyn A`
+LL |     for<'a> Dst<dyn A + 'a>: Sized,
+   |                              ^^^^^
+
+error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
+  --> $DIR/ice-3969.rs:31:10
    |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+LL |     str: Sized,
+   |          ^^^^^
 
-error: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/ice-3969.rs:27:57
+error: trait bound std::string::String: std::ops::Neg does not depend on any type or lifetime parameters
+  --> $DIR/ice-3969.rs:38:13
    |
-LL |     let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
-   |                                                         ^ help: use `dyn`: `dyn A`
+LL |     String: ::std::ops::Neg<Output = String>,
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bound i32: std::iter::Iterator does not depend on any type or lifetime parameters
+  --> $DIR/ice-3969.rs:45:10
    |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+LL |     i32: Iterator,
+   |          ^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
index 1b20c9defac823185ec31b6a3229167d0abb5e58..f463f78a99ab738bc0117ad3391817145323c146 100644 (file)
@@ -1,5 +1,3 @@
-// edition:2018
-
 // Regression test for https://github.com/rust-lang/rust-clippy/issues/5207
 
 pub async fn bar<'a, T: 'a>(_: T) {}
index 2e3d9fd1e9240ed097512ca6216325968fa4c078..0ccf0aae9d74298099fd483995d2d73ce76763b3 100644 (file)
@@ -1,6 +1,5 @@
 // originally from glacier fixed/77919.rs
 // encountered errors resolving bounds after type-checking
-
 trait TypeVal<T> {
     const VAL: T;
 }
index eaa5e6f51cb4abd51ed518386e1fb9a867061237..c8239897f3abb5b7032d8f574aeae103599b1e71 100644 (file)
@@ -1,16 +1,20 @@
 error[E0412]: cannot find type `PhantomData` in this scope
-  --> $DIR/ice-6252.rs:9:9
+  --> $DIR/ice-6252.rs:8:9
    |
 LL |     _n: PhantomData,
    |         ^^^^^^^^^^^ not found in this scope
    |
-help: consider importing this struct
+help: consider importing one of these items
+   |
+LL | use core::marker::PhantomData;
+   |
+LL | use serde::__private::PhantomData;
    |
 LL | use std::marker::PhantomData;
    |
 
 error[E0412]: cannot find type `VAL` in this scope
-  --> $DIR/ice-6252.rs:11:63
+  --> $DIR/ice-6252.rs:10:63
    |
 LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    |          -                                                    ^^^ not found in this scope
@@ -18,7 +22,7 @@ LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    |          help: you might be missing a type parameter: `, VAL`
 
 error[E0046]: not all trait items implemented, missing: `VAL`
-  --> $DIR/ice-6252.rs:11:1
+  --> $DIR/ice-6252.rs:10:1
    |
 LL |     const VAL: T;
    |     ------------- `VAL` from trait
index 5595d8d1d626978d136f7c61e26daa74a07010dd..4ad0d351372f7559de26a2a84d6974f0cdf3643a 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 #![allow(clippy::never_loop)]
 
 async fn f() {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7868.rs b/src/tools/clippy/tests/ui/crashes/ice-7868.rs
new file mode 100644 (file)
index 0000000..c693216
--- /dev/null
@@ -0,0 +1,7 @@
+#![warn(clippy::undocumented_unsafe_blocks)]
+#![allow(clippy::no_effect)]
+
+#[path = "auxiliary/ice-7868-aux.rs"]
+mod zero;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7868.stderr b/src/tools/clippy/tests/ui/crashes/ice-7868.stderr
new file mode 100644 (file)
index 0000000..d7b49eb
--- /dev/null
@@ -0,0 +1,15 @@
+error: unsafe block missing a safety comment
+  --> $DIR/auxiliary/ice-7868-aux.rs:2:5
+   |
+LL |     unsafe { 0 };
+   |     ^^^^^^^^^^^^
+   |
+   = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
+help: consider adding a safety comment
+   |
+LL ~     // Safety: ...
+LL ~     unsafe { 0 };
+   |
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7869.rs b/src/tools/clippy/tests/ui/crashes/ice-7869.rs
new file mode 100644 (file)
index 0000000..8f97a06
--- /dev/null
@@ -0,0 +1,7 @@
+enum Tila {
+    TyöAlkoi,
+    TyöKeskeytyi,
+    TyöValmis,
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7869.stderr b/src/tools/clippy/tests/ui/crashes/ice-7869.stderr
new file mode 100644 (file)
index 0000000..4fa9fb2
--- /dev/null
@@ -0,0 +1,15 @@
+error: all variants have the same prefix: `Työ`
+  --> $DIR/ice-7869.rs:1:1
+   |
+LL | / enum Tila {
+LL | |     TyöAlkoi,
+LL | |     TyöKeskeytyi,
+LL | |     TyöValmis,
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::enum-variant-names` implied by `-D warnings`
+   = help: remove the prefixes and use full paths to the variants instead of glob imports
+
+error: aborting due to previous error
+
index c57a45dc7aab9b1c1f3e48dfc7e41558b6002fc9..901eb4e50398888f50747c1ba2a496703474d82e 100644 (file)
@@ -1,5 +1,3 @@
-// edition:2018
-
 use serde::Deserialize;
 
 /// Tests that we do not lint for unused underscores in a `MacroAttribute`
index 477a47118d4116587fc6526ca01f3f72edf639e2..c5de412556567ffe6718fc9ada4471dcb5e4cc8b 100644 (file)
@@ -1,9 +1,9 @@
-// compile-flags: --edition=2018
 #![feature(custom_inner_attributes)]
 #![rustfmt::skip]
 #![warn(clippy::debug_assert_with_mut_call)]
 #![allow(clippy::redundant_closure_call)]
 
+
 struct S;
 
 impl S {
index 1943d0092e6244851b9c5480a879116b788e56b9..39a2601fee9aca39e6d3882f27c8d1008ffce339 100644 (file)
@@ -1,19 +1,18 @@
-#[warn(clippy::unstable_as_slice)]
-#[warn(clippy::unstable_as_mut_slice)]
-#[warn(clippy::misaligned_transmute)]
-#[warn(clippy::unused_collect)]
-#[warn(clippy::invalid_ref)]
-#[warn(clippy::into_iter_on_array)]
-#[warn(clippy::unused_label)]
-#[warn(clippy::regex_macro)]
-#[warn(clippy::drop_bounds)]
-#[warn(clippy::temporary_cstring_as_ptr)]
-#[warn(clippy::panic_params)]
-#[warn(clippy::unknown_clippy_lints)]
-#[warn(clippy::find_map)]
-#[warn(clippy::filter_map)]
-#[warn(clippy::pub_enum_variant_names)]
-#[warn(clippy::wrong_pub_self_convention)]
-#[warn(clippy::invalid_atomic_ordering)]
+#![warn(clippy::should_assert_eq)]
+#![warn(clippy::extend_from_slice)]
+#![warn(clippy::range_step_by_zero)]
+#![warn(clippy::unstable_as_slice)]
+#![warn(clippy::unstable_as_mut_slice)]
+#![warn(clippy::misaligned_transmute)]
+#![warn(clippy::assign_ops)]
+#![warn(clippy::if_let_redundant_pattern_matching)]
+#![warn(clippy::unsafe_vector_initialization)]
+#![warn(clippy::unused_collect)]
+#![warn(clippy::replace_consts)]
+#![warn(clippy::regex_macro)]
+#![warn(clippy::find_map)]
+#![warn(clippy::filter_map)]
+#![warn(clippy::pub_enum_variant_names)]
+#![warn(clippy::wrong_pub_self_convention)]
 
 fn main() {}
index 51048e45c0677c208bb8e050edc7fa0169eb8a82..6095f134d55e0d2ea7452696adfb9a047521f077 100644 (file)
-error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
-  --> $DIR/deprecated.rs:1:8
+error: lint `clippy::should_assert_eq` has been removed: `assert!()` will be more flexible with RFC 2011
+  --> $DIR/deprecated.rs:1:9
    |
-LL | #[warn(clippy::unstable_as_slice)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::should_assert_eq)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
-error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
-  --> $DIR/deprecated.rs:2:8
+error: lint `clippy::extend_from_slice` has been removed: `.extend_from_slice(_)` is a faster way to extend a Vec by a slice
+  --> $DIR/deprecated.rs:2:9
    |
-LL | #[warn(clippy::unstable_as_mut_slice)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::extend_from_slice)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
-  --> $DIR/deprecated.rs:3:8
+error: lint `clippy::range_step_by_zero` has been removed: `iterator.step_by(0)` panics nowadays
+  --> $DIR/deprecated.rs:3:9
    |
-LL | #[warn(clippy::misaligned_transmute)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::range_step_by_zero)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint
-  --> $DIR/deprecated.rs:4:8
+error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
+  --> $DIR/deprecated.rs:4:9
    |
-LL | #[warn(clippy::unused_collect)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::unstable_as_slice)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/deprecated.rs:5:8
+error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
+  --> $DIR/deprecated.rs:5:9
    |
-LL | #[warn(clippy::invalid_ref)]
-   |        ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
+LL | #![warn(clippy::unstable_as_mut_slice)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/deprecated.rs:6:8
+error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
+  --> $DIR/deprecated.rs:6:9
    |
-LL | #[warn(clippy::into_iter_on_array)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
+LL | #![warn(clippy::misaligned_transmute)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/deprecated.rs:7:8
+error: lint `clippy::assign_ops` has been removed: using compound assignment operators (e.g., `+=`) is harmless
+  --> $DIR/deprecated.rs:7:9
    |
-LL | #[warn(clippy::unused_label)]
-   |        ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
+LL | #![warn(clippy::assign_ops)]
+   |         ^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018
-  --> $DIR/deprecated.rs:8:8
+error: lint `clippy::if_let_redundant_pattern_matching` has been removed: this lint has been changed to redundant_pattern_matching
+  --> $DIR/deprecated.rs:8:9
    |
-LL | #[warn(clippy::regex_macro)]
-   |        ^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::if_let_redundant_pattern_matching)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/deprecated.rs:9:8
+error: lint `clippy::unsafe_vector_initialization` has been removed: the replacement suggested by this lint had substantially different behavior
+  --> $DIR/deprecated.rs:9:9
    |
-LL | #[warn(clippy::drop_bounds)]
-   |        ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
+LL | #![warn(clippy::unsafe_vector_initialization)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/deprecated.rs:10:8
+error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint
+  --> $DIR/deprecated.rs:10:9
    |
-LL | #[warn(clippy::temporary_cstring_as_ptr)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
+LL | #![warn(clippy::unused_collect)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/deprecated.rs:11:8
+error: lint `clippy::replace_consts` has been removed: associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants
+  --> $DIR/deprecated.rs:11:9
    |
-LL | #[warn(clippy::panic_params)]
-   |        ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
+LL | #![warn(clippy::replace_consts)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/deprecated.rs:12:8
+error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018
+  --> $DIR/deprecated.rs:12:9
    |
-LL | #[warn(clippy::unknown_clippy_lints)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
+LL | #![warn(clippy::regex_macro)]
+   |         ^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::find_map` has been removed: this lint has been replaced by `manual_find_map`, a more specific lint
-  --> $DIR/deprecated.rs:13:8
+  --> $DIR/deprecated.rs:13:9
    |
-LL | #[warn(clippy::find_map)]
-   |        ^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::find_map)]
+   |         ^^^^^^^^^^^^^^^^
 
 error: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint
-  --> $DIR/deprecated.rs:14:8
+  --> $DIR/deprecated.rs:14:9
    |
-LL | #[warn(clippy::filter_map)]
-   |        ^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::filter_map)]
+   |         ^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items
-  --> $DIR/deprecated.rs:15:8
+  --> $DIR/deprecated.rs:15:9
    |
-LL | #[warn(clippy::pub_enum_variant_names)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::pub_enum_variant_names)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items
-  --> $DIR/deprecated.rs:16:8
-   |
-LL | #[warn(clippy::wrong_pub_self_convention)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/deprecated.rs:17:8
+  --> $DIR/deprecated.rs:16:9
    |
-LL | #[warn(clippy::invalid_atomic_ordering)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
+LL | #![warn(clippy::wrong_pub_self_convention)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
 
index 4df241c9fc39be35b1fe3a00ac017e637ad69e82..e27f9fea708ee16c0bcfd889cf27ad6ed7b39b8d 100644 (file)
@@ -1,6 +1,5 @@
 #![warn(clippy::diverging_sub_expression)]
 #![allow(clippy::match_same_arms, clippy::logic_bug)]
-
 #[allow(clippy::empty_loop)]
 fn diverge() -> ! {
     loop {}
index 170e7d92de4acff6b643a1ead8d762e2d61e2d8b..c712a6a7e38eaf1433c0aee8f46e4897612370a7 100644 (file)
@@ -1,5 +1,5 @@
 error: sub-expression diverges
-  --> $DIR/diverging_sub_expression.rs:20:10
+  --> $DIR/diverging_sub_expression.rs:19:10
    |
 LL |     b || diverge();
    |          ^^^^^^^^^
@@ -7,34 +7,42 @@ LL |     b || diverge();
    = note: `-D clippy::diverging-sub-expression` implied by `-D warnings`
 
 error: sub-expression diverges
-  --> $DIR/diverging_sub_expression.rs:21:10
+  --> $DIR/diverging_sub_expression.rs:20:10
    |
 LL |     b || A.foo();
    |          ^^^^^^^
 
 error: sub-expression diverges
-  --> $DIR/diverging_sub_expression.rs:30:26
+  --> $DIR/diverging_sub_expression.rs:29:26
    |
 LL |             6 => true || return,
    |                          ^^^^^^
 
 error: sub-expression diverges
-  --> $DIR/diverging_sub_expression.rs:31:26
+  --> $DIR/diverging_sub_expression.rs:30:26
    |
 LL |             7 => true || continue,
    |                          ^^^^^^^^
 
 error: sub-expression diverges
-  --> $DIR/diverging_sub_expression.rs:34:26
+  --> $DIR/diverging_sub_expression.rs:33:26
    |
 LL |             3 => true || diverge(),
    |                          ^^^^^^^^^
 
 error: sub-expression diverges
-  --> $DIR/diverging_sub_expression.rs:39:26
+  --> $DIR/diverging_sub_expression.rs:36:30
+   |
+LL |                 _ => true || panic!("boo"),
+   |                              ^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: sub-expression diverges
+  --> $DIR/diverging_sub_expression.rs:38:26
    |
 LL |             _ => true || break,
    |                          ^^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
new file mode 100644 (file)
index 0000000..747801b
--- /dev/null
@@ -0,0 +1,215 @@
+// run-rustfix
+//! This file tests for the `DOC_MARKDOWN` lint.
+
+#![allow(dead_code, incomplete_features)]
+#![warn(clippy::doc_markdown)]
+#![feature(custom_inner_attributes, generic_const_exprs, const_option)]
+#![rustfmt::skip]
+
+/// The `foo_bar` function does _nothing_. See also `foo::bar`. (note the dot there)
+/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not `Foo::some_fun`
+/// which should be reported only once despite being __doubly bad__.
+/// Here be `::a::global:path`, and _`::another::global::path`_.  :: is not a path though.
+/// Import an item from `::awesome::global::blob::` (Intended postfix)
+/// These are the options for `::Cat`: (Intended trailing single colon, shouldn't be linted)
+/// That's not code ~`NotInCodeBlock`~.
+/// `be_sure_we_got_to_the_end_of_it`
+fn foo_bar() {
+}
+
+/// That one tests multiline ticks.
+/// ```rust
+/// foo_bar FOO_BAR
+/// _foo bar_
+/// ```
+///
+/// ~~~rust
+/// foo_bar FOO_BAR
+/// _foo bar_
+/// ~~~
+/// `be_sure_we_got_to_the_end_of_it`
+fn multiline_codeblock() {
+}
+
+/// This _is a test for
+/// multiline
+/// emphasis_.
+/// `be_sure_we_got_to_the_end_of_it`
+fn test_emphasis() {
+}
+
+/// This tests units. See also #835.
+/// kiB MiB GiB TiB PiB EiB
+/// kib Mib Gib Tib Pib Eib
+/// kB MB GB TB PB EB
+/// kb Mb Gb Tb Pb Eb
+/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
+/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
+/// 32kB 32MB 32GB 32TB 32PB 32EB
+/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
+/// NaN
+/// `be_sure_we_got_to_the_end_of_it`
+fn test_units() {
+}
+
+/// This tests allowed identifiers.
+/// KiB MiB GiB TiB PiB EiB
+/// DirectX
+/// ECMAScript
+/// GPLv2 GPLv3
+/// GitHub GitLab
+/// IPv4 IPv6
+/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
+/// NaN NaNs
+/// OAuth GraphQL
+/// OCaml
+/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
+/// WebGL
+/// TensorFlow
+/// TrueType
+/// iOS macOS FreeBSD
+/// TeX LaTeX BibTeX BibLaTeX
+/// MinGW
+/// CamelCase (see also #2395)
+/// `be_sure_we_got_to_the_end_of_it`
+fn test_allowed() {
+}
+
+/// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
+/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
+/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
+/// It can also be [`inline_link2`].
+///
+/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
+/// [inline_link]: https://foobar
+/// [inline_link2]: https://foobar
+/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
+/// `multiline_ticks` functions.
+///
+/// expression of the type  `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
+/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
+/// `be_sure_we_got_to_the_end_of_it`
+fn main() {
+    foo_bar();
+    multiline_codeblock();
+    test_emphasis();
+    test_units();
+}
+
+/// ## `CamelCaseThing`
+/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
+///
+/// # `CamelCaseThing`
+///
+/// Not a title #897 `CamelCaseThing`
+/// `be_sure_we_got_to_the_end_of_it`
+fn issue897() {
+}
+
+/// I am confused by brackets? (`x_y`)
+/// I am confused by brackets? (foo `x_y`)
+/// I am confused by brackets? (`x_y` foo)
+/// `be_sure_we_got_to_the_end_of_it`
+fn issue900() {
+}
+
+/// Diesel queries also have a similar problem to [Iterator][iterator], where
+/// /// More talking
+/// returning them from a function requires exposing the implementation of that
+/// function. The [`helper_types`][helper_types] module exists to help with this,
+/// but you might want to hide the return type or have it conditionally change.
+/// Boxing can achieve both.
+///
+/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
+/// [helper_types]: ../helper_types/index.html
+/// `be_sure_we_got_to_the_end_of_it`
+fn issue883() {
+}
+
+/// `foo_bar
+/// baz_quz`
+/// [foo
+/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
+fn multiline() {
+}
+
+/** E.g., serialization of an empty list: `FooBar`
+```
+That's in a code block: `PackedNode`
+```
+
+And `BarQuz` too.
+`be_sure_we_got_to_the_end_of_it`
+*/
+fn issue1073() {
+}
+
+/** E.g., serialization of an empty list: `FooBar`
+```
+That's in a code block: PackedNode
+```
+
+And `BarQuz` too.
+`be_sure_we_got_to_the_end_of_it`
+*/
+fn issue1073_alt() {
+}
+
+/// Tests more than three quotes:
+/// ````
+/// DoNotWarn
+/// ```
+/// StillDont
+/// ````
+/// `be_sure_we_got_to_the_end_of_it`
+fn four_quotes() {
+}
+
+#[cfg_attr(feature = "a", doc = " ```")]
+#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
+/// fn main() {
+///     let s = "localhost:10000".to_string();
+///     println!("{}", s);
+/// }
+/// ```
+fn issue_1469() {}
+
+/**
+ * This is a doc comment that should not be a list
+ *This would also be an error under a strict common mark interpretation
+ */
+fn issue_1920() {}
+
+/// An iterator over `mycrate::Collection`'s values.
+/// It should not lint a `'static` lifetime in ticks.
+fn issue_2210() {}
+
+/// This should not cause the lint to trigger:
+/// #REQ-data-family.lint_partof_exists
+fn issue_2343() {}
+
+/// This should not cause an ICE:
+/// __|_ _|__||_|
+fn pulldown_cmark_crash() {}
+
+/// This should not lint
+/// (regression test for #7758)
+/// [plain text][path::to::item]
+fn intra_doc_link() {}
+
+// issue #7033 - generic_const_exprs ICE
+struct S<T, const N: usize>
+where [(); N.checked_next_power_of_two().unwrap()]: {
+    arr: [T; N.checked_next_power_of_two().unwrap()],
+    n: usize,
+}
+
+impl<T: Copy + Default, const N: usize> S<T, N>
+where [(); N.checked_next_power_of_two().unwrap()]: {
+    fn new() -> Self {
+        Self {
+            arr: [T::default(); N.checked_next_power_of_two().unwrap()],
+            n: 0,
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
new file mode 100644 (file)
index 0000000..f3cf966
--- /dev/null
@@ -0,0 +1,215 @@
+// run-rustfix
+//! This file tests for the `DOC_MARKDOWN` lint.
+
+#![allow(dead_code, incomplete_features)]
+#![warn(clippy::doc_markdown)]
+#![feature(custom_inner_attributes, generic_const_exprs, const_option)]
+#![rustfmt::skip]
+
+/// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
+/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun
+/// which should be reported only once despite being __doubly bad__.
+/// Here be ::a::global:path, and _::another::global::path_.  :: is not a path though.
+/// Import an item from ::awesome::global::blob:: (Intended postfix)
+/// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted)
+/// That's not code ~NotInCodeBlock~.
+/// be_sure_we_got_to_the_end_of_it
+fn foo_bar() {
+}
+
+/// That one tests multiline ticks.
+/// ```rust
+/// foo_bar FOO_BAR
+/// _foo bar_
+/// ```
+///
+/// ~~~rust
+/// foo_bar FOO_BAR
+/// _foo bar_
+/// ~~~
+/// be_sure_we_got_to_the_end_of_it
+fn multiline_codeblock() {
+}
+
+/// This _is a test for
+/// multiline
+/// emphasis_.
+/// be_sure_we_got_to_the_end_of_it
+fn test_emphasis() {
+}
+
+/// This tests units. See also #835.
+/// kiB MiB GiB TiB PiB EiB
+/// kib Mib Gib Tib Pib Eib
+/// kB MB GB TB PB EB
+/// kb Mb Gb Tb Pb Eb
+/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
+/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
+/// 32kB 32MB 32GB 32TB 32PB 32EB
+/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
+/// NaN
+/// be_sure_we_got_to_the_end_of_it
+fn test_units() {
+}
+
+/// This tests allowed identifiers.
+/// KiB MiB GiB TiB PiB EiB
+/// DirectX
+/// ECMAScript
+/// GPLv2 GPLv3
+/// GitHub GitLab
+/// IPv4 IPv6
+/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
+/// NaN NaNs
+/// OAuth GraphQL
+/// OCaml
+/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
+/// WebGL
+/// TensorFlow
+/// TrueType
+/// iOS macOS FreeBSD
+/// TeX LaTeX BibTeX BibLaTeX
+/// MinGW
+/// CamelCase (see also #2395)
+/// be_sure_we_got_to_the_end_of_it
+fn test_allowed() {
+}
+
+/// This test has [a link_with_underscores][chunked-example] inside it. See #823.
+/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
+/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
+/// It can also be [inline_link2].
+///
+/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
+/// [inline_link]: https://foobar
+/// [inline_link2]: https://foobar
+/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
+/// `multiline_ticks` functions.
+///
+/// expression of the type  `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
+/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
+/// be_sure_we_got_to_the_end_of_it
+fn main() {
+    foo_bar();
+    multiline_codeblock();
+    test_emphasis();
+    test_units();
+}
+
+/// ## CamelCaseThing
+/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
+///
+/// # CamelCaseThing
+///
+/// Not a title #897 CamelCaseThing
+/// be_sure_we_got_to_the_end_of_it
+fn issue897() {
+}
+
+/// I am confused by brackets? (`x_y`)
+/// I am confused by brackets? (foo `x_y`)
+/// I am confused by brackets? (`x_y` foo)
+/// be_sure_we_got_to_the_end_of_it
+fn issue900() {
+}
+
+/// Diesel queries also have a similar problem to [Iterator][iterator], where
+/// /// More talking
+/// returning them from a function requires exposing the implementation of that
+/// function. The [`helper_types`][helper_types] module exists to help with this,
+/// but you might want to hide the return type or have it conditionally change.
+/// Boxing can achieve both.
+///
+/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
+/// [helper_types]: ../helper_types/index.html
+/// be_sure_we_got_to_the_end_of_it
+fn issue883() {
+}
+
+/// `foo_bar
+/// baz_quz`
+/// [foo
+/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
+fn multiline() {
+}
+
+/** E.g., serialization of an empty list: FooBar
+```
+That's in a code block: `PackedNode`
+```
+
+And BarQuz too.
+be_sure_we_got_to_the_end_of_it
+*/
+fn issue1073() {
+}
+
+/** E.g., serialization of an empty list: FooBar
+```
+That's in a code block: PackedNode
+```
+
+And BarQuz too.
+be_sure_we_got_to_the_end_of_it
+*/
+fn issue1073_alt() {
+}
+
+/// Tests more than three quotes:
+/// ````
+/// DoNotWarn
+/// ```
+/// StillDont
+/// ````
+/// be_sure_we_got_to_the_end_of_it
+fn four_quotes() {
+}
+
+#[cfg_attr(feature = "a", doc = " ```")]
+#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
+/// fn main() {
+///     let s = "localhost:10000".to_string();
+///     println!("{}", s);
+/// }
+/// ```
+fn issue_1469() {}
+
+/**
+ * This is a doc comment that should not be a list
+ *This would also be an error under a strict common mark interpretation
+ */
+fn issue_1920() {}
+
+/// An iterator over mycrate::Collection's values.
+/// It should not lint a `'static` lifetime in ticks.
+fn issue_2210() {}
+
+/// This should not cause the lint to trigger:
+/// #REQ-data-family.lint_partof_exists
+fn issue_2343() {}
+
+/// This should not cause an ICE:
+/// __|_ _|__||_|
+fn pulldown_cmark_crash() {}
+
+/// This should not lint
+/// (regression test for #7758)
+/// [plain text][path::to::item]
+fn intra_doc_link() {}
+
+// issue #7033 - generic_const_exprs ICE
+struct S<T, const N: usize>
+where [(); N.checked_next_power_of_two().unwrap()]: {
+    arr: [T; N.checked_next_power_of_two().unwrap()],
+    n: usize,
+}
+
+impl<T: Copy + Default, const N: usize> S<T, N>
+where [(); N.checked_next_power_of_two().unwrap()]: {
+    fn new() -> Self {
+        Self {
+            arr: [T::default(); N.checked_next_power_of_two().unwrap()],
+            n: 0,
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
new file mode 100644 (file)
index 0000000..31132f8
--- /dev/null
@@ -0,0 +1,184 @@
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:9:9
+   |
+LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
+   |         ^^^^^^^ help: try: ``foo_bar``
+   |
+   = note: `-D clippy::doc-markdown` implied by `-D warnings`
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:9:51
+   |
+LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
+   |                                                   ^^^^^^^^ help: try: ``foo::bar``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:10:83
+   |
+LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun
+   |                                                                                   ^^^^^^^^^^^^^ help: try: ``Foo::some_fun``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:12:13
+   |
+LL | /// Here be ::a::global:path, and _::another::global::path_.  :: is not a path though.
+   |             ^^^^^^^^^^^^^^^^ help: try: ``::a::global:path``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:12:36
+   |
+LL | /// Here be ::a::global:path, and _::another::global::path_.  :: is not a path though.
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::another::global::path``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:13:25
+   |
+LL | /// Import an item from ::awesome::global::blob:: (Intended postfix)
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::awesome::global::blob::``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:14:31
+   |
+LL | /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted)
+   |                               ^^^^^ help: try: ``::Cat``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:15:22
+   |
+LL | /// That's not code ~NotInCodeBlock~.
+   |                      ^^^^^^^^^^^^^^ help: try: ``NotInCodeBlock``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:16:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:30:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:37:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:51:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:74:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:78:22
+   |
+LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
+   |                      ^^^^^^^^^^^^^^^^^^^^^ help: try: ``link_with_underscores``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:81:21
+   |
+LL | /// It can also be [inline_link2].
+   |                     ^^^^^^^^^^^^ help: try: ``inline_link2``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:91:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:99:8
+   |
+LL | /// ## CamelCaseThing
+   |        ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:102:7
+   |
+LL | /// # CamelCaseThing
+   |       ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:104:22
+   |
+LL | /// Not a title #897 CamelCaseThing
+   |                      ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:105:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:112:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:125:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:136:43
+   |
+LL | /** E.g., serialization of an empty list: FooBar
+   |                                           ^^^^^^ help: try: ``FooBar``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:141:5
+   |
+LL | And BarQuz too.
+   |     ^^^^^^ help: try: ``BarQuz``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:142:1
+   |
+LL | be_sure_we_got_to_the_end_of_it
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:147:43
+   |
+LL | /** E.g., serialization of an empty list: FooBar
+   |                                           ^^^^^^ help: try: ``FooBar``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:152:5
+   |
+LL | And BarQuz too.
+   |     ^^^^^^ help: try: ``BarQuz``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:153:1
+   |
+LL | be_sure_we_got_to_the_end_of_it
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:164:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+  --> $DIR/doc-fixable.rs:183:22
+   |
+LL | /// An iterator over mycrate::Collection's values.
+   |                      ^^^^^^^^^^^^^^^^^^^ help: try: ``mycrate::Collection``
+
+error: aborting due to 30 previous errors
+
diff --git a/src/tools/clippy/tests/ui/doc/doc.rs b/src/tools/clippy/tests/ui/doc/doc.rs
deleted file mode 100644 (file)
index 342208e..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-//! This file tests for the `DOC_MARKDOWN` lint.
-
-#![allow(dead_code, incomplete_features)]
-#![warn(clippy::doc_markdown)]
-#![feature(custom_inner_attributes, generic_const_exprs, const_option)]
-#![rustfmt::skip]
-
-/// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
-/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun
-/// which should be reported only once despite being __doubly bad__.
-/// Here be ::a::global:path.
-/// That's not code ~NotInCodeBlock~.
-/// be_sure_we_got_to_the_end_of_it
-fn foo_bar() {
-}
-
-/// That one tests multiline ticks.
-/// ```rust
-/// foo_bar FOO_BAR
-/// _foo bar_
-/// ```
-///
-/// ~~~rust
-/// foo_bar FOO_BAR
-/// _foo bar_
-/// ~~~
-/// be_sure_we_got_to_the_end_of_it
-fn multiline_codeblock() {
-}
-
-/// This _is a test for
-/// multiline
-/// emphasis_.
-/// be_sure_we_got_to_the_end_of_it
-fn test_emphasis() {
-}
-
-/// This tests units. See also #835.
-/// kiB MiB GiB TiB PiB EiB
-/// kib Mib Gib Tib Pib Eib
-/// kB MB GB TB PB EB
-/// kb Mb Gb Tb Pb Eb
-/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
-/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
-/// 32kB 32MB 32GB 32TB 32PB 32EB
-/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
-/// NaN
-/// be_sure_we_got_to_the_end_of_it
-fn test_units() {
-}
-
-/// This tests allowed identifiers.
-/// KiB MiB GiB TiB PiB EiB
-/// DirectX
-/// ECMAScript
-/// GPLv2 GPLv3
-/// GitHub GitLab
-/// IPv4 IPv6
-/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
-/// NaN NaNs
-/// OAuth GraphQL
-/// OCaml
-/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
-/// WebGL
-/// TensorFlow
-/// TrueType
-/// iOS macOS FreeBSD
-/// TeX LaTeX BibTeX BibLaTeX
-/// MinGW
-/// CamelCase (see also #2395)
-/// be_sure_we_got_to_the_end_of_it
-fn test_allowed() {
-}
-
-/// This test has [a link_with_underscores][chunked-example] inside it. See #823.
-/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
-/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
-/// It can also be [inline_link2].
-///
-/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
-/// [inline_link]: https://foobar
-/// [inline_link2]: https://foobar
-/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
-/// `multiline_ticks` functions.
-///
-/// expression of the type  `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
-/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
-/// be_sure_we_got_to_the_end_of_it
-fn main() {
-    foo_bar();
-    multiline_codeblock();
-    test_emphasis();
-    test_units();
-}
-
-/// ## CamelCaseThing
-/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
-///
-/// # CamelCaseThing
-///
-/// Not a title #897 CamelCaseThing
-/// be_sure_we_got_to_the_end_of_it
-fn issue897() {
-}
-
-/// I am confused by brackets? (`x_y`)
-/// I am confused by brackets? (foo `x_y`)
-/// I am confused by brackets? (`x_y` foo)
-/// be_sure_we_got_to_the_end_of_it
-fn issue900() {
-}
-
-/// Diesel queries also have a similar problem to [Iterator][iterator], where
-/// /// More talking
-/// returning them from a function requires exposing the implementation of that
-/// function. The [`helper_types`][helper_types] module exists to help with this,
-/// but you might want to hide the return type or have it conditionally change.
-/// Boxing can achieve both.
-///
-/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
-/// [helper_types]: ../helper_types/index.html
-/// be_sure_we_got_to_the_end_of_it
-fn issue883() {
-}
-
-/// `foo_bar
-/// baz_quz`
-/// [foo
-/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
-fn multiline() {
-}
-
-/** E.g., serialization of an empty list: FooBar
-```
-That's in a code block: `PackedNode`
-```
-
-And BarQuz too.
-be_sure_we_got_to_the_end_of_it
-*/
-fn issue1073() {
-}
-
-/** E.g., serialization of an empty list: FooBar
-```
-That's in a code block: PackedNode
-```
-
-And BarQuz too.
-be_sure_we_got_to_the_end_of_it
-*/
-fn issue1073_alt() {
-}
-
-/// Tests more than three quotes:
-/// ````
-/// DoNotWarn
-/// ```
-/// StillDont
-/// ````
-/// be_sure_we_got_to_the_end_of_it
-fn four_quotes() {
-}
-
-/// See [NIST SP 800-56A, revision 2].
-///
-/// [NIST SP 800-56A, revision 2]:
-///     https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419
-fn issue_902_comment() {}
-
-#[cfg_attr(feature = "a", doc = " ```")]
-#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
-/// fn main() {
-///     let s = "localhost:10000".to_string();
-///     println!("{}", s);
-/// }
-/// ```
-fn issue_1469() {}
-
-/**
- * This is a doc comment that should not be a list
- *This would also be an error under a strict common mark interpretation
- */
-fn issue_1920() {}
-
-/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels>
-///
-/// Not ok: http://www.unicode.org
-/// Not ok: https://www.unicode.org
-/// Not ok: http://www.unicode.org/
-/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
-fn issue_1832() {}
-
-/// An iterator over mycrate::Collection's values.
-/// It should not lint a `'static` lifetime in ticks.
-fn issue_2210() {}
-
-/// This should not cause the lint to trigger:
-/// #REQ-data-family.lint_partof_exists
-fn issue_2343() {}
-
-/// This should not cause an ICE:
-/// __|_ _|__||_|
-fn pulldown_cmark_crash() {}
-
-/// This should not lint
-/// (regression test for #7758)
-/// [plain text][path::to::item]
-fn intra_doc_link() {}
-
-// issue #7033 - generic_const_exprs ICE
-struct S<T, const N: usize>
-where [(); N.checked_next_power_of_two().unwrap()]: {
-    arr: [T; N.checked_next_power_of_two().unwrap()],
-    n: usize,
-}
-
-impl<T: Copy + Default, const N: usize> S<T, N>
-where [(); N.checked_next_power_of_two().unwrap()]: {
-    fn new() -> Self {
-        Self {
-            arr: [T::default(); N.checked_next_power_of_two().unwrap()],
-            n: 0,
-        }
-    }
-}
diff --git a/src/tools/clippy/tests/ui/doc/doc.stderr b/src/tools/clippy/tests/ui/doc/doc.stderr
deleted file mode 100644 (file)
index 7eab8a8..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-error: you should put `foo_bar` between ticks in the documentation
-  --> $DIR/doc.rs:8:9
-   |
-LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
-   |         ^^^^^^^
-   |
-   = note: `-D clippy::doc-markdown` implied by `-D warnings`
-
-error: you should put `foo::bar` between ticks in the documentation
-  --> $DIR/doc.rs:8:51
-   |
-LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
-   |                                                   ^^^^^^^^
-
-error: you should put `Foo::some_fun` between ticks in the documentation
-  --> $DIR/doc.rs:9:83
-   |
-LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun
-   |                                                                                   ^^^^^^^^^^^^^
-
-error: you should put `a::global:path` between ticks in the documentation
-  --> $DIR/doc.rs:11:15
-   |
-LL | /// Here be ::a::global:path.
-   |               ^^^^^^^^^^^^^^
-
-error: you should put `NotInCodeBlock` between ticks in the documentation
-  --> $DIR/doc.rs:12:22
-   |
-LL | /// That's not code ~NotInCodeBlock~.
-   |                      ^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:13:5
-   |
-LL | /// be_sure_we_got_to_the_end_of_it
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:27:5
-   |
-LL | /// be_sure_we_got_to_the_end_of_it
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:34:5
-   |
-LL | /// be_sure_we_got_to_the_end_of_it
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:48:5
-   |
-LL | /// be_sure_we_got_to_the_end_of_it
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:71:5
-   |
-LL | /// be_sure_we_got_to_the_end_of_it
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `link_with_underscores` between ticks in the documentation
-  --> $DIR/doc.rs:75:22
-   |
-LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
-   |                      ^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `inline_link2` between ticks in the documentation
-  --> $DIR/doc.rs:78:21
-   |
-LL | /// It can also be [inline_link2].
-   |                     ^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:88:5
-   |
-LL | /// be_sure_we_got_to_the_end_of_it
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `CamelCaseThing` between ticks in the documentation
-  --> $DIR/doc.rs:96:8
-   |
-LL | /// ## CamelCaseThing
-   |        ^^^^^^^^^^^^^^
-
-error: you should put `CamelCaseThing` between ticks in the documentation
-  --> $DIR/doc.rs:99:7
-   |
-LL | /// # CamelCaseThing
-   |       ^^^^^^^^^^^^^^
-
-error: you should put `CamelCaseThing` between ticks in the documentation
-  --> $DIR/doc.rs:101:22
-   |
-LL | /// Not a title #897 CamelCaseThing
-   |                      ^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:102:5
-   |
-LL | /// be_sure_we_got_to_the_end_of_it
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:109:5
-   |
-LL | /// be_sure_we_got_to_the_end_of_it
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:122:5
-   |
-LL | /// be_sure_we_got_to_the_end_of_it
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `FooBar` between ticks in the documentation
-  --> $DIR/doc.rs:133:43
-   |
-LL | /** E.g., serialization of an empty list: FooBar
-   |                                           ^^^^^^
-
-error: you should put `BarQuz` between ticks in the documentation
-  --> $DIR/doc.rs:138:5
-   |
-LL | And BarQuz too.
-   |     ^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:139:1
-   |
-LL | be_sure_we_got_to_the_end_of_it
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `FooBar` between ticks in the documentation
-  --> $DIR/doc.rs:144:43
-   |
-LL | /** E.g., serialization of an empty list: FooBar
-   |                                           ^^^^^^
-
-error: you should put `BarQuz` between ticks in the documentation
-  --> $DIR/doc.rs:149:5
-   |
-LL | And BarQuz too.
-   |     ^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:150:1
-   |
-LL | be_sure_we_got_to_the_end_of_it
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-  --> $DIR/doc.rs:161:5
-   |
-LL | /// be_sure_we_got_to_the_end_of_it
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put bare URLs between `<`/`>` or make a proper Markdown link
-  --> $DIR/doc.rs:188:13
-   |
-LL | /// Not ok: http://www.unicode.org
-   |             ^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put bare URLs between `<`/`>` or make a proper Markdown link
-  --> $DIR/doc.rs:189:13
-   |
-LL | /// Not ok: https://www.unicode.org
-   |             ^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put bare URLs between `<`/`>` or make a proper Markdown link
-  --> $DIR/doc.rs:190:13
-   |
-LL | /// Not ok: http://www.unicode.org/
-   |             ^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put bare URLs between `<`/`>` or make a proper Markdown link
-  --> $DIR/doc.rs:191:13
-   |
-LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `mycrate::Collection` between ticks in the documentation
-  --> $DIR/doc.rs:194:22
-   |
-LL | /// An iterator over mycrate::Collection's values.
-   |                      ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 31 previous errors
-
diff --git a/src/tools/clippy/tests/ui/doc/issue_1832.rs b/src/tools/clippy/tests/ui/doc/issue_1832.rs
new file mode 100644 (file)
index 0000000..10586f1
--- /dev/null
@@ -0,0 +1,9 @@
+/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels>
+///
+/// Not ok: http://www.unicode.org
+/// Not ok: https://www.unicode.org
+/// Not ok: http://www.unicode.org/
+/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
+fn issue_1832() {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/doc/issue_902.rs b/src/tools/clippy/tests/ui/doc/issue_902.rs
new file mode 100644 (file)
index 0000000..4b0c835
--- /dev/null
@@ -0,0 +1,7 @@
+/// See [NIST SP 800-56A, revision 2].
+///
+/// [NIST SP 800-56A, revision 2]:
+///     https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419
+fn issue_902_comment() {}
+
+fn main() {}
index 45ca34e2a8c8b34a2e6ede2509ad9367abac2709..9670e5c24fb3ecbcf5a9febdca1e2a93ddf61c07 100644 (file)
@@ -18,11 +18,11 @@ LL | /// This paragraph has `unbalanced_tick marks and should stop_linting.
    |
    = help: a backtick may be missing a pair
 
-error: you should put `should_be` between ticks in the documentation
+error: item in documentation is missing backticks
   --> $DIR/unbalanced_ticks.rs:15:32
    |
 LL | /// This paragraph is fine and should_be linted normally.
-   |                                ^^^^^^^^^
+   |                                ^^^^^^^^^ help: try: ``should_be``
 
 error: backticks are unbalanced
   --> $DIR/unbalanced_ticks.rs:17:1
@@ -32,11 +32,11 @@ LL | /// Double unbalanced backtick from ``here to here` should lint.
    |
    = help: a backtick may be missing a pair
 
-error: you should put `not_fine` between ticks in the documentation
+error: item in documentation is missing backticks
   --> $DIR/unbalanced_ticks.rs:30:8
    |
 LL | /// ## not_fine
-   |        ^^^^^^^^
+   |        ^^^^^^^^ help: try: ``not_fine``
 
 error: backticks are unbalanced
   --> $DIR/unbalanced_ticks.rs:32:1
@@ -54,11 +54,11 @@ LL | /// - This `item has unbalanced tick marks
    |
    = help: a backtick may be missing a pair
 
-error: you should put `backticks_here` between ticks in the documentation
+error: item in documentation is missing backticks
   --> $DIR/unbalanced_ticks.rs:35:23
    |
 LL | /// - This item needs backticks_here
-   |                       ^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^ help: try: ``backticks_here``
 
 error: aborting due to 8 previous errors
 
index c77a74a58f22c6072dcfb295ea22794afbe1309c..30fdd3b087371226352c9b07dd81f60119f744b3 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 #![warn(clippy::missing_errors_doc)]
 #![allow(clippy::result_unit_err)]
 #![allow(clippy::unnecessary_wraps)]
index b5a81419daee35d295197158c9e20d5a17f21871..c7b616e2897087c01ee59976e37fe287afb6dbbc 100644 (file)
@@ -1,5 +1,5 @@
 error: docs for function returning `Result` missing `# Errors` section
-  --> $DIR/doc_errors.rs:8:1
+  --> $DIR/doc_errors.rs:7:1
    |
 LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> {
 LL | |     unimplemented!();
@@ -9,7 +9,7 @@ LL | | }
    = note: `-D clippy::missing-errors-doc` implied by `-D warnings`
 
 error: docs for function returning `Result` missing `# Errors` section
-  --> $DIR/doc_errors.rs:12:1
+  --> $DIR/doc_errors.rs:11:1
    |
 LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> {
 LL | |     unimplemented!();
@@ -17,7 +17,7 @@ LL | | }
    | |_^
 
 error: docs for function returning `Result` missing `# Errors` section
-  --> $DIR/doc_errors.rs:17:1
+  --> $DIR/doc_errors.rs:16:1
    |
 LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> {
 LL | |     unimplemented!();
@@ -25,7 +25,7 @@ LL | | }
    | |_^
 
 error: docs for function returning `Result` missing `# Errors` section
-  --> $DIR/doc_errors.rs:22:1
+  --> $DIR/doc_errors.rs:21:1
    |
 LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> {
 LL | |     unimplemented!();
@@ -33,7 +33,7 @@ LL | | }
    | |_^
 
 error: docs for function returning `Result` missing `# Errors` section
-  --> $DIR/doc_errors.rs:52:5
+  --> $DIR/doc_errors.rs:51:5
    |
 LL | /     pub fn pub_method_missing_errors_header() -> Result<(), ()> {
 LL | |         unimplemented!();
@@ -41,7 +41,7 @@ LL | |     }
    | |_____^
 
 error: docs for function returning `Result` missing `# Errors` section
-  --> $DIR/doc_errors.rs:57:5
+  --> $DIR/doc_errors.rs:56:5
    |
 LL | /     pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> {
 LL | |         unimplemented!();
@@ -49,7 +49,7 @@ LL | |     }
    | |_____^
 
 error: docs for function returning `Result` missing `# Errors` section
-  --> $DIR/doc_errors.rs:86:5
+  --> $DIR/doc_errors.rs:85:5
    |
 LL |     fn trait_method_missing_errors_header() -> Result<(), ()>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 8f823f1672ba2d30e868414cdf87104a39caa175..4464a21b3b654bdf89b238a5c0594b61edbf06ce 100644 (file)
@@ -115,3 +115,18 @@ fn main() {
         drive();
     }
 }
+
+// do not lint if any parent has `#[doc(hidden)]` attribute
+// see #7347
+#[doc(hidden)]
+pub mod __macro {
+    pub struct T;
+    impl T {
+        pub unsafe fn f() {}
+    }
+}
+
+/// # Implementation safety
+pub unsafe trait DocumentedUnsafeTraitWithImplementationHeader {
+    fn method();
+}
index 447fbb9e1bff3440c35200354408ccdeb9fe60b1..add8a91e26b85a2b9745a73053ff73d418a54cdd 100644 (file)
@@ -60,7 +60,7 @@ LL | | }
    |
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
-error: all variants have the same prefix: `With`
+error: all variants have the same prefix: `WithOut`
   --> $DIR/enum_variants.rs:81:1
    |
 LL | / enum Seallll {
index ba72cc237b4a58e1b0c51f5470f88273e6f87292..88918d9671e42f6d90037eae22fc8985ab5de651 100644 (file)
@@ -66,4 +66,13 @@ fn main() {
     if g == NotStructuralEq::A {}
     if let Some(NotPartialEq::A) = Some(f) {}
     if Some(g) == Some(NotStructuralEq::A) {}
+
+    macro_rules! m1 {
+        (x) => {
+            "abc"
+        };
+    }
+    if "abc" == m1!(x) {
+        println!("OK");
+    }
 }
index 12526ca193db6b6fd6b1ca3244070a7faa5c9a20..9a7ab75ef450f528f5ff1543f3bdd361c1881f67 100644 (file)
@@ -66,4 +66,13 @@ fn main() {
     if let NotStructuralEq::A = g {}
     if let Some(NotPartialEq::A) = Some(f) {}
     if let Some(NotStructuralEq::A) = Some(g) {}
+
+    macro_rules! m1 {
+        (x) => {
+            "abc"
+        };
+    }
+    if let m1!(x) = "abc" {
+        println!("OK");
+    }
 }
index 79ef919384df28abc1032e096565ade0147f3d79..760ff88f448f094561f008b0e29be43824306260 100644 (file)
@@ -60,5 +60,11 @@ error: this pattern matching can be expressed using equality
 LL |     if let Some(NotStructuralEq::A) = Some(g) {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)`
 
-error: aborting due to 10 previous errors
+error: this pattern matching can be expressed using equality
+  --> $DIR/equatable_if_let.rs:75:8
+   |
+LL |     if let m1!(x) = "abc" {
+   |        ^^^^^^^^^^^^^^^^^^ help: try: `"abc" == m1!(x)`
+
+error: aborting due to 11 previous errors
 
index 8e6a32b7be33d2eccde04199653c2d467942f3c0..aad78319d48209549db51ff8e3de027a5b4a8b59 100644 (file)
@@ -1,5 +1,3 @@
-// edition:2018
-
 #[warn(clippy::eval_order_dependence)]
 #[allow(
     unused_assignments,
index 4f611e308e18619e50f0b408ed7c07f60c28b47d..7c6265a08790deee6d8df446b49846dab095e770 100644 (file)
@@ -1,48 +1,48 @@
 error: unsequenced read of `x`
-  --> $DIR/eval_order_dependence.rs:16:9
+  --> $DIR/eval_order_dependence.rs:14:9
    |
 LL |     } + x;
    |         ^
    |
    = note: `-D clippy::eval-order-dependence` implied by `-D warnings`
 note: whether read occurs before this write depends on evaluation order
-  --> $DIR/eval_order_dependence.rs:14:9
+  --> $DIR/eval_order_dependence.rs:12:9
    |
 LL |         x = 1;
    |         ^^^^^
 
 error: unsequenced read of `x`
-  --> $DIR/eval_order_dependence.rs:19:5
+  --> $DIR/eval_order_dependence.rs:17:5
    |
 LL |     x += {
    |     ^
    |
 note: whether read occurs before this write depends on evaluation order
-  --> $DIR/eval_order_dependence.rs:20:9
+  --> $DIR/eval_order_dependence.rs:18:9
    |
 LL |         x = 20;
    |         ^^^^^^
 
 error: unsequenced read of `x`
-  --> $DIR/eval_order_dependence.rs:32:12
+  --> $DIR/eval_order_dependence.rs:30:12
    |
 LL |         a: x,
    |            ^
    |
 note: whether read occurs before this write depends on evaluation order
-  --> $DIR/eval_order_dependence.rs:34:13
+  --> $DIR/eval_order_dependence.rs:32:13
    |
 LL |             x = 6;
    |             ^^^^^
 
 error: unsequenced read of `x`
-  --> $DIR/eval_order_dependence.rs:41:9
+  --> $DIR/eval_order_dependence.rs:39:9
    |
 LL |         x += {
    |         ^
    |
 note: whether read occurs before this write depends on evaluation order
-  --> $DIR/eval_order_dependence.rs:42:13
+  --> $DIR/eval_order_dependence.rs:40:13
    |
 LL |             x = 20;
    |             ^^^^^^
index a756d1cf50659473e1c43bbaca97ed675b9c4755..cf923a6a5940c3574216eca71be849f9cd89d6e5 100644 (file)
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::expect_fun_call)]
+#![allow(clippy::to_string_in_format_args)]
 
 /// Checks implementation of the `EXPECT_FUN_CALL` lint
 
index 60bbaa89d42825819edae4191b6d3a3cccaa35fe..e6f252259df70427e2da39b9ca9a3c6172f51659 100644 (file)
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::expect_fun_call)]
+#![allow(clippy::to_string_in_format_args)]
 
 /// Checks implementation of the `EXPECT_FUN_CALL` lint
 
index 6dc796f5cee37d7e4effecde55e3775344710dc8..ac48a06671cd2e0d572ecc36637c0237bc90426c 100644 (file)
@@ -1,5 +1,5 @@
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:28:26
+  --> $DIR/expect_fun_call.rs:29:26
    |
 LL |     with_none_and_format.expect(&format!("Error {}: fake error", error_code));
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
@@ -7,67 +7,67 @@ LL |     with_none_and_format.expect(&format!("Error {}: fake error", error_code
    = note: `-D clippy::expect-fun-call` implied by `-D warnings`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:31:26
+  --> $DIR/expect_fun_call.rs:32:26
    |
 LL |     with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:41:25
+  --> $DIR/expect_fun_call.rs:42:25
    |
 LL |     with_err_and_format.expect(&format!("Error {}: fake error", error_code));
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:44:25
+  --> $DIR/expect_fun_call.rs:45:25
    |
 LL |     with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:56:17
+  --> $DIR/expect_fun_call.rs:57:17
    |
 LL |     Some("foo").expect(format!("{} {}", 1, 2).as_ref());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{} {}", 1, 2))`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:77:21
+  --> $DIR/expect_fun_call.rs:78:21
    |
 LL |         Some("foo").expect(&get_string());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:78:21
+  --> $DIR/expect_fun_call.rs:79:21
    |
 LL |         Some("foo").expect(get_string().as_ref());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:79:21
+  --> $DIR/expect_fun_call.rs:80:21
    |
 LL |         Some("foo").expect(get_string().as_str());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:81:21
+  --> $DIR/expect_fun_call.rs:82:21
    |
 LL |         Some("foo").expect(get_static_str());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_static_str()) })`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:82:21
+  --> $DIR/expect_fun_call.rs:83:21
    |
 LL |         Some("foo").expect(get_non_static_str(&0));
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:86:16
+  --> $DIR/expect_fun_call.rs:87:16
    |
 LL |     Some(true).expect(&format!("key {}, {}", 1, 2));
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:92:17
+  --> $DIR/expect_fun_call.rs:93:17
    |
 LL |         opt_ref.expect(&format!("{:?}", opt_ref));
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{:?}", opt_ref))`
index 495cd97e05e15d472bef961da5a2e9eab1573814..5d5af4e4632970afe821f9b42b82eae5bd445e08 100644 (file)
@@ -1,5 +1,4 @@
 #![deny(clippy::fallible_impl_from)]
-#![allow(clippy::if_then_panic)]
 
 // docs example
 struct Foo(i32);
index f5d0b98c10862cd11a4db14d65c484f90c988dd4..4e0f08a1215c0401fa8f18493fb8ad0a833dcd63 100644 (file)
@@ -1,5 +1,5 @@
 error: consider implementing `TryFrom` instead
-  --> $DIR/fallible_impl_from.rs:6:1
+  --> $DIR/fallible_impl_from.rs:5:1
    |
 LL | / impl From<String> for Foo {
 LL | |     fn from(s: String) -> Self {
@@ -15,13 +15,13 @@ LL | #![deny(clippy::fallible_impl_from)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
 note: potential failure(s)
-  --> $DIR/fallible_impl_from.rs:8:13
+  --> $DIR/fallible_impl_from.rs:7:13
    |
 LL |         Foo(s.parse().unwrap())
    |             ^^^^^^^^^^^^^^^^^^
 
 error: consider implementing `TryFrom` instead
-  --> $DIR/fallible_impl_from.rs:27:1
+  --> $DIR/fallible_impl_from.rs:26:1
    |
 LL | / impl From<usize> for Invalid {
 LL | |     fn from(i: usize) -> Invalid {
@@ -34,14 +34,14 @@ LL | | }
    |
    = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
 note: potential failure(s)
-  --> $DIR/fallible_impl_from.rs:30:13
+  --> $DIR/fallible_impl_from.rs:29:13
    |
 LL |             panic!();
    |             ^^^^^^^^
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: consider implementing `TryFrom` instead
-  --> $DIR/fallible_impl_from.rs:36:1
+  --> $DIR/fallible_impl_from.rs:35:1
    |
 LL | / impl From<Option<String>> for Invalid {
 LL | |     fn from(s: Option<String>) -> Invalid {
@@ -54,7 +54,7 @@ LL | | }
    |
    = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
 note: potential failure(s)
-  --> $DIR/fallible_impl_from.rs:38:17
+  --> $DIR/fallible_impl_from.rs:37:17
    |
 LL |         let s = s.unwrap();
    |                 ^^^^^^^^^^
@@ -65,10 +65,10 @@ LL |         } else if s.parse::<u32>().unwrap() != 42 {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |             panic!("{:?}", s);
    |             ^^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: consider implementing `TryFrom` instead
-  --> $DIR/fallible_impl_from.rs:54:1
+  --> $DIR/fallible_impl_from.rs:53:1
    |
 LL | / impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid {
 LL | |     fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid {
@@ -81,13 +81,13 @@ LL | | }
    |
    = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
 note: potential failure(s)
-  --> $DIR/fallible_impl_from.rs:56:12
+  --> $DIR/fallible_impl_from.rs:55:12
    |
 LL |         if s.parse::<u32>().ok().unwrap() != 42 {
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |             panic!("{:?}", s);
    |             ^^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 4 previous errors
 
index 787053fb00064c861a75c37410ae26767ab2322e..7367910eaa126fdc54319aa3d7232765dcca376d 100644 (file)
@@ -183,3 +183,67 @@ struct WrapperMulti<T, U> {
     i: T,
     j: U,
 }
+
+mod issue6312 {
+    use std::sync::atomic::AtomicBool;
+    use std::sync::Arc;
+
+    // do not lint: type implements `Drop` but not all fields are `Copy`
+    #[derive(Clone, Default)]
+    pub struct ImplDropNotAllCopy {
+        name: String,
+        delay_data_sync: Arc<AtomicBool>,
+    }
+
+    impl Drop for ImplDropNotAllCopy {
+        fn drop(&mut self) {
+            self.close()
+        }
+    }
+
+    impl ImplDropNotAllCopy {
+        fn new(name: &str) -> Self {
+            let mut f = ImplDropNotAllCopy::default();
+            f.name = name.to_owned();
+            f
+        }
+        fn close(&self) {}
+    }
+
+    // lint: type implements `Drop` and all fields are `Copy`
+    #[derive(Clone, Default)]
+    pub struct ImplDropAllCopy {
+        name: usize,
+        delay_data_sync: bool,
+    }
+
+    impl Drop for ImplDropAllCopy {
+        fn drop(&mut self) {
+            self.close()
+        }
+    }
+
+    impl ImplDropAllCopy {
+        fn new(name: &str) -> Self {
+            let mut f = ImplDropAllCopy::default();
+            f.name = name.len();
+            f
+        }
+        fn close(&self) {}
+    }
+
+    // lint: type does not implement `Drop` though all fields are `Copy`
+    #[derive(Clone, Default)]
+    pub struct NoDropAllCopy {
+        name: usize,
+        delay_data_sync: bool,
+    }
+
+    impl NoDropAllCopy {
+        fn new(name: &str) -> Self {
+            let mut f = NoDropAllCopy::default();
+            f.name = name.len();
+            f
+        }
+    }
+}
index b56db08ec8a787f63c3edc31fde93178a0237982..3ce4b91a54869d13c4b72ce7235cc51981a6169e 100644 (file)
@@ -107,5 +107,29 @@ note: consider initializing the variable with `WrapperMulti::<i32, i64> { i: 42,
 LL |     let mut a: WrapperMulti<i32, i64> = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 9 previous errors
+error: field assignment outside of initializer for an instance created with Default::default()
+  --> $DIR/field_reassign_with_default.rs:229:13
+   |
+LL |             f.name = name.len();
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+note: consider initializing the variable with `issue6312::ImplDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:228:13
+   |
+LL |             let mut f = ImplDropAllCopy::default();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: field assignment outside of initializer for an instance created with Default::default()
+  --> $DIR/field_reassign_with_default.rs:245:13
+   |
+LL |             f.name = name.len();
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+note: consider initializing the variable with `issue6312::NoDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:244:13
+   |
+LL |             let mut f = NoDropAllCopy::default();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.rs b/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.rs
new file mode 100644 (file)
index 0000000..4670468
--- /dev/null
@@ -0,0 +1,76 @@
+#![warn(clippy::fn_to_numeric_cast_any)]
+#![allow(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)]
+
+fn foo() -> u8 {
+    0
+}
+
+fn generic_foo<T>(x: T) -> T {
+    x
+}
+
+trait Trait {
+    fn static_method() -> u32 {
+        2
+    }
+}
+
+struct Struct;
+
+impl Trait for Struct {}
+
+fn fn_pointer_to_integer() {
+    let _ = foo as i8;
+    let _ = foo as i16;
+    let _ = foo as i32;
+    let _ = foo as i64;
+    let _ = foo as i128;
+    let _ = foo as isize;
+
+    let _ = foo as u8;
+    let _ = foo as u16;
+    let _ = foo as u32;
+    let _ = foo as u64;
+    let _ = foo as u128;
+    let _ = foo as usize;
+}
+
+fn static_method_to_integer() {
+    let _ = Struct::static_method as usize;
+}
+
+fn fn_with_fn_arg(f: fn(i32) -> u32) -> usize {
+    f as usize
+}
+
+fn fn_with_generic_static_trait_method<T: Trait>() -> usize {
+    T::static_method as usize
+}
+
+fn closure_to_fn_to_integer() {
+    let clos = |x| x * 2_u32;
+
+    let _ = (clos as fn(u32) -> u32) as usize;
+}
+
+fn fn_to_raw_ptr() {
+    let _ = foo as *const ();
+}
+
+fn cast_fn_to_self() {
+    // Casting to the same function pointer type should be permitted.
+    let _ = foo as fn() -> u8;
+}
+
+fn cast_generic_to_concrete() {
+    // Casting to a more concrete function pointer type should be permitted.
+    let _ = generic_foo as fn(usize) -> usize;
+}
+
+fn cast_closure_to_fn() {
+    // Casting a closure to a function pointer should be permitted.
+    let id = |x| x;
+    let _ = id as fn(usize) -> usize;
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr b/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr
new file mode 100644 (file)
index 0000000..a6c4a77
--- /dev/null
@@ -0,0 +1,106 @@
+error: casting function pointer `foo` to `i8`
+  --> $DIR/fn_to_numeric_cast_any.rs:23:13
+   |
+LL |     let _ = foo as i8;
+   |             ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i8`
+   |
+   = note: `-D clippy::fn-to-numeric-cast-any` implied by `-D warnings`
+
+error: casting function pointer `foo` to `i16`
+  --> $DIR/fn_to_numeric_cast_any.rs:24:13
+   |
+LL |     let _ = foo as i16;
+   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i16`
+
+error: casting function pointer `foo` to `i32`
+  --> $DIR/fn_to_numeric_cast_any.rs:25:13
+   |
+LL |     let _ = foo as i32;
+   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i32`
+
+error: casting function pointer `foo` to `i64`
+  --> $DIR/fn_to_numeric_cast_any.rs:26:13
+   |
+LL |     let _ = foo as i64;
+   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i64`
+
+error: casting function pointer `foo` to `i128`
+  --> $DIR/fn_to_numeric_cast_any.rs:27:13
+   |
+LL |     let _ = foo as i128;
+   |             ^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i128`
+
+error: casting function pointer `foo` to `isize`
+  --> $DIR/fn_to_numeric_cast_any.rs:28:13
+   |
+LL |     let _ = foo as isize;
+   |             ^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as isize`
+
+error: casting function pointer `foo` to `u8`
+  --> $DIR/fn_to_numeric_cast_any.rs:30:13
+   |
+LL |     let _ = foo as u8;
+   |             ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u8`
+
+error: casting function pointer `foo` to `u16`
+  --> $DIR/fn_to_numeric_cast_any.rs:31:13
+   |
+LL |     let _ = foo as u16;
+   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u16`
+
+error: casting function pointer `foo` to `u32`
+  --> $DIR/fn_to_numeric_cast_any.rs:32:13
+   |
+LL |     let _ = foo as u32;
+   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u32`
+
+error: casting function pointer `foo` to `u64`
+  --> $DIR/fn_to_numeric_cast_any.rs:33:13
+   |
+LL |     let _ = foo as u64;
+   |             ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u64`
+
+error: casting function pointer `foo` to `u128`
+  --> $DIR/fn_to_numeric_cast_any.rs:34:13
+   |
+LL |     let _ = foo as u128;
+   |             ^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u128`
+
+error: casting function pointer `foo` to `usize`
+  --> $DIR/fn_to_numeric_cast_any.rs:35:13
+   |
+LL |     let _ = foo as usize;
+   |             ^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as usize`
+
+error: casting function pointer `Struct::static_method` to `usize`
+  --> $DIR/fn_to_numeric_cast_any.rs:39:13
+   |
+LL |     let _ = Struct::static_method as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `Struct::static_method() as usize`
+
+error: casting function pointer `f` to `usize`
+  --> $DIR/fn_to_numeric_cast_any.rs:43:5
+   |
+LL |     f as usize
+   |     ^^^^^^^^^^ help: did you mean to invoke the function?: `f() as usize`
+
+error: casting function pointer `T::static_method` to `usize`
+  --> $DIR/fn_to_numeric_cast_any.rs:47:5
+   |
+LL |     T::static_method as usize
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `T::static_method() as usize`
+
+error: casting function pointer `(clos as fn(u32) -> u32)` to `usize`
+  --> $DIR/fn_to_numeric_cast_any.rs:53:13
+   |
+LL |     let _ = (clos as fn(u32) -> u32) as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `(clos as fn(u32) -> u32)() as usize`
+
+error: casting function pointer `foo` to `*const ()`
+  --> $DIR/fn_to_numeric_cast_any.rs:57:13
+   |
+LL |     let _ = foo as *const ();
+   |             ^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as *const ()`
+
+error: aborting due to 17 previous errors
+
index 5dd64140e81165880f3d6285c60825838d96a0e2..64cb7b1cfb80f6c33ff5e81f7af29cceb1e8b73d 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(clippy::print_literal, clippy::redundant_clone)]
+#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)]
 #![warn(clippy::useless_format)]
 
 struct Foo(pub String);
@@ -16,6 +16,8 @@ fn main() {
     r##"foo {}
 " bar"##.to_string();
 
+    let _ = String::new();
+
     "foo".to_string();
     format!("{:?}", "foo"); // Don't warn about `Debug`.
     format!("{:8}", "foo");
index 4599fb5207ea85c280f07b863d39f798f6262eaa..a065b1b5683c1b9ccbfeb81df5cf1b96d7d12c4d 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(clippy::print_literal, clippy::redundant_clone)]
+#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)]
 #![warn(clippy::useless_format)]
 
 struct Foo(pub String);
@@ -18,6 +18,8 @@ fn main() {
 " bar"##
     );
 
+    let _ = format!("");
+
     format!("{}", "foo");
     format!("{:?}", "foo"); // Don't warn about `Debug`.
     format!("{:8}", "foo");
index 701399b32d62834a9d993339b83df1f5ba8d03ab..58ad7499bb26f530c5202239ac79858ab1aaa79c 100644 (file)
@@ -34,64 +34,70 @@ LL ~ " bar"##.to_string();
    |
 
 error: useless use of `format!`
-  --> $DIR/format.rs:21:5
+  --> $DIR/format.rs:21:13
+   |
+LL |     let _ = format!("");
+   |             ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:23:5
    |
 LL |     format!("{}", "foo");
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:25:5
+  --> $DIR/format.rs:27:5
    |
 LL |     format!("{:+}", "foo"); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:26:5
+  --> $DIR/format.rs:28:5
    |
 LL |     format!("{:<}", "foo"); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:31:5
+  --> $DIR/format.rs:33:5
    |
 LL |     format!("{}", arg);
    |     ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:35:5
+  --> $DIR/format.rs:37:5
    |
 LL |     format!("{:+}", arg); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:36:5
+  --> $DIR/format.rs:38:5
    |
 LL |     format!("{:<}", arg); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:63:5
+  --> $DIR/format.rs:65:5
    |
 LL |     format!("{}", 42.to_string());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:65:5
+  --> $DIR/format.rs:67:5
    |
 LL |     format!("{}", x.display().to_string());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:69:18
+  --> $DIR/format.rs:71:18
    |
 LL |     let _ = Some(format!("{}", a + "bar"));
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:73:22
+  --> $DIR/format.rs:75:22
    |
 LL |     let _s: String = format!("{}", &*v.join("/n"));
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
 
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/format_args.fixed b/src/tools/clippy/tests/ui/format_args.fixed
new file mode 100644 (file)
index 0000000..69b5e1c
--- /dev/null
@@ -0,0 +1,117 @@
+// run-rustfix
+
+#![allow(unreachable_code)]
+#![allow(unused_macros)]
+#![allow(unused_variables)]
+#![allow(clippy::assertions_on_constants)]
+#![allow(clippy::eq_op)]
+#![allow(clippy::print_literal)]
+#![warn(clippy::to_string_in_format_args)]
+
+use std::io::{stdout, Write};
+use std::ops::Deref;
+use std::panic::Location;
+
+struct Somewhere;
+
+impl ToString for Somewhere {
+    fn to_string(&self) -> String {
+        String::from("somewhere")
+    }
+}
+
+struct X(u32);
+
+impl Deref for X {
+    type Target = u32;
+
+    fn deref(&self) -> &u32 {
+        &self.0
+    }
+}
+
+struct Y<'a>(&'a X);
+
+impl<'a> Deref for Y<'a> {
+    type Target = &'a X;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+struct Z(u32);
+
+impl Deref for Z {
+    type Target = u32;
+
+    fn deref(&self) -> &u32 {
+        &self.0
+    }
+}
+
+impl std::fmt::Display for Z {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "Z")
+    }
+}
+
+macro_rules! my_macro {
+    () => {
+        // here be dragons, do not enter (or lint)
+        println!("error: something failed at {}", Location::caller().to_string());
+    };
+}
+
+macro_rules! my_other_macro {
+    () => {
+        Location::caller().to_string()
+    };
+}
+
+fn main() {
+    let x = &X(1);
+    let x_ref = &x;
+
+    let _ = format!("error: something failed at {}", Location::caller());
+    let _ = write!(
+        stdout(),
+        "error: something failed at {}",
+        Location::caller()
+    );
+    let _ = writeln!(
+        stdout(),
+        "error: something failed at {}",
+        Location::caller()
+    );
+    print!("error: something failed at {}", Location::caller());
+    println!("error: something failed at {}", Location::caller());
+    eprint!("error: something failed at {}", Location::caller());
+    eprintln!("error: something failed at {}", Location::caller());
+    let _ = format_args!("error: something failed at {}", Location::caller());
+    assert!(true, "error: something failed at {}", Location::caller());
+    assert_eq!(0, 0, "error: something failed at {}", Location::caller());
+    assert_ne!(0, 0, "error: something failed at {}", Location::caller());
+    panic!("error: something failed at {}", Location::caller());
+    println!("{}", *X(1));
+    println!("{}", ***Y(&X(1)));
+    println!("{}", Z(1));
+    println!("{}", **x);
+    println!("{}", ***x_ref);
+    // https://github.com/rust-lang/rust-clippy/issues/7903
+    println!("{foo}{bar}", foo = "foo", bar = "bar");
+    println!("{foo}{bar}", foo = "foo", bar = "bar");
+    println!("{foo}{bar}", bar = "bar", foo = "foo");
+    println!("{foo}{bar}", bar = "bar", foo = "foo");
+
+    // negative tests
+    println!("error: something failed at {}", Somewhere.to_string());
+    // The next two tests are negative because caching the string might be faster than calling `<X as
+    // Display>::fmt` twice.
+    println!("{} and again {0}", x.to_string());
+    println!("{foo}{foo}", foo = "foo".to_string());
+    my_macro!();
+    println!("error: something failed at {}", my_other_macro!());
+    // https://github.com/rust-lang/rust-clippy/issues/7903
+    println!("{foo}{foo:?}", foo = "foo".to_string());
+}
diff --git a/src/tools/clippy/tests/ui/format_args.rs b/src/tools/clippy/tests/ui/format_args.rs
new file mode 100644 (file)
index 0000000..3a434c5
--- /dev/null
@@ -0,0 +1,117 @@
+// run-rustfix
+
+#![allow(unreachable_code)]
+#![allow(unused_macros)]
+#![allow(unused_variables)]
+#![allow(clippy::assertions_on_constants)]
+#![allow(clippy::eq_op)]
+#![allow(clippy::print_literal)]
+#![warn(clippy::to_string_in_format_args)]
+
+use std::io::{stdout, Write};
+use std::ops::Deref;
+use std::panic::Location;
+
+struct Somewhere;
+
+impl ToString for Somewhere {
+    fn to_string(&self) -> String {
+        String::from("somewhere")
+    }
+}
+
+struct X(u32);
+
+impl Deref for X {
+    type Target = u32;
+
+    fn deref(&self) -> &u32 {
+        &self.0
+    }
+}
+
+struct Y<'a>(&'a X);
+
+impl<'a> Deref for Y<'a> {
+    type Target = &'a X;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+struct Z(u32);
+
+impl Deref for Z {
+    type Target = u32;
+
+    fn deref(&self) -> &u32 {
+        &self.0
+    }
+}
+
+impl std::fmt::Display for Z {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "Z")
+    }
+}
+
+macro_rules! my_macro {
+    () => {
+        // here be dragons, do not enter (or lint)
+        println!("error: something failed at {}", Location::caller().to_string());
+    };
+}
+
+macro_rules! my_other_macro {
+    () => {
+        Location::caller().to_string()
+    };
+}
+
+fn main() {
+    let x = &X(1);
+    let x_ref = &x;
+
+    let _ = format!("error: something failed at {}", Location::caller().to_string());
+    let _ = write!(
+        stdout(),
+        "error: something failed at {}",
+        Location::caller().to_string()
+    );
+    let _ = writeln!(
+        stdout(),
+        "error: something failed at {}",
+        Location::caller().to_string()
+    );
+    print!("error: something failed at {}", Location::caller().to_string());
+    println!("error: something failed at {}", Location::caller().to_string());
+    eprint!("error: something failed at {}", Location::caller().to_string());
+    eprintln!("error: something failed at {}", Location::caller().to_string());
+    let _ = format_args!("error: something failed at {}", Location::caller().to_string());
+    assert!(true, "error: something failed at {}", Location::caller().to_string());
+    assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string());
+    assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string());
+    panic!("error: something failed at {}", Location::caller().to_string());
+    println!("{}", X(1).to_string());
+    println!("{}", Y(&X(1)).to_string());
+    println!("{}", Z(1).to_string());
+    println!("{}", x.to_string());
+    println!("{}", x_ref.to_string());
+    // https://github.com/rust-lang/rust-clippy/issues/7903
+    println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar");
+    println!("{foo}{bar}", foo = "foo", bar = "bar".to_string());
+    println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo");
+    println!("{foo}{bar}", bar = "bar", foo = "foo".to_string());
+
+    // negative tests
+    println!("error: something failed at {}", Somewhere.to_string());
+    // The next two tests are negative because caching the string might be faster than calling `<X as
+    // Display>::fmt` twice.
+    println!("{} and again {0}", x.to_string());
+    println!("{foo}{foo}", foo = "foo".to_string());
+    my_macro!();
+    println!("error: something failed at {}", my_other_macro!());
+    // https://github.com/rust-lang/rust-clippy/issues/7903
+    println!("{foo}{foo:?}", foo = "foo".to_string());
+}
diff --git a/src/tools/clippy/tests/ui/format_args.stderr b/src/tools/clippy/tests/ui/format_args.stderr
new file mode 100644 (file)
index 0000000..c0cbca5
--- /dev/null
@@ -0,0 +1,130 @@
+error: `to_string` applied to a type that implements `Display` in `format!` args
+  --> $DIR/format_args.rs:76:72
+   |
+LL |     let _ = format!("error: something failed at {}", Location::caller().to_string());
+   |                                                                        ^^^^^^^^^^^^ help: remove this
+   |
+   = note: `-D clippy::to-string-in-format-args` implied by `-D warnings`
+
+error: `to_string` applied to a type that implements `Display` in `write!` args
+  --> $DIR/format_args.rs:80:27
+   |
+LL |         Location::caller().to_string()
+   |                           ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `writeln!` args
+  --> $DIR/format_args.rs:85:27
+   |
+LL |         Location::caller().to_string()
+   |                           ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `print!` args
+  --> $DIR/format_args.rs:87:63
+   |
+LL |     print!("error: something failed at {}", Location::caller().to_string());
+   |                                                               ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+  --> $DIR/format_args.rs:88:65
+   |
+LL |     println!("error: something failed at {}", Location::caller().to_string());
+   |                                                                 ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `eprint!` args
+  --> $DIR/format_args.rs:89:64
+   |
+LL |     eprint!("error: something failed at {}", Location::caller().to_string());
+   |                                                                ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `eprintln!` args
+  --> $DIR/format_args.rs:90:66
+   |
+LL |     eprintln!("error: something failed at {}", Location::caller().to_string());
+   |                                                                  ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `format_args!` args
+  --> $DIR/format_args.rs:91:77
+   |
+LL |     let _ = format_args!("error: something failed at {}", Location::caller().to_string());
+   |                                                                             ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `assert!` args
+  --> $DIR/format_args.rs:92:70
+   |
+LL |     assert!(true, "error: something failed at {}", Location::caller().to_string());
+   |                                                                      ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `assert_eq!` args
+  --> $DIR/format_args.rs:93:73
+   |
+LL |     assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string());
+   |                                                                         ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `assert_ne!` args
+  --> $DIR/format_args.rs:94:73
+   |
+LL |     assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string());
+   |                                                                         ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `panic!` args
+  --> $DIR/format_args.rs:95:63
+   |
+LL |     panic!("error: something failed at {}", Location::caller().to_string());
+   |                                                               ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+  --> $DIR/format_args.rs:96:20
+   |
+LL |     println!("{}", X(1).to_string());
+   |                    ^^^^^^^^^^^^^^^^ help: use this: `*X(1)`
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+  --> $DIR/format_args.rs:97:20
+   |
+LL |     println!("{}", Y(&X(1)).to_string());
+   |                    ^^^^^^^^^^^^^^^^^^^^ help: use this: `***Y(&X(1))`
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+  --> $DIR/format_args.rs:98:24
+   |
+LL |     println!("{}", Z(1).to_string());
+   |                        ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+  --> $DIR/format_args.rs:99:20
+   |
+LL |     println!("{}", x.to_string());
+   |                    ^^^^^^^^^^^^^ help: use this: `**x`
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+  --> $DIR/format_args.rs:100:20
+   |
+LL |     println!("{}", x_ref.to_string());
+   |                    ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref`
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+  --> $DIR/format_args.rs:102:39
+   |
+LL |     println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar");
+   |                                       ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+  --> $DIR/format_args.rs:103:52
+   |
+LL |     println!("{foo}{bar}", foo = "foo", bar = "bar".to_string());
+   |                                                    ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+  --> $DIR/format_args.rs:104:39
+   |
+LL |     println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo");
+   |                                       ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+  --> $DIR/format_args.rs:105:52
+   |
+LL |     println!("{foo}{bar}", bar = "bar", foo = "foo".to_string());
+   |                                                    ^^^^^^^^^^^^ help: remove this
+
+error: aborting due to 21 previous errors
+
diff --git a/src/tools/clippy/tests/ui/format_args_unfixable.rs b/src/tools/clippy/tests/ui/format_args_unfixable.rs
new file mode 100644 (file)
index 0000000..b24ddf7
--- /dev/null
@@ -0,0 +1,61 @@
+#![allow(clippy::assertions_on_constants)]
+#![allow(clippy::eq_op)]
+#![warn(clippy::format_in_format_args)]
+#![warn(clippy::to_string_in_format_args)]
+
+use std::io::{stdout, Error, ErrorKind, Write};
+use std::ops::Deref;
+use std::panic::Location;
+
+macro_rules! my_macro {
+    () => {
+        // here be dragons, do not enter (or lint)
+        println!("error: {}", format!("something failed at {}", Location::caller()));
+    };
+}
+
+macro_rules! my_other_macro {
+    () => {
+        format!("something failed at {}", Location::caller())
+    };
+}
+
+fn main() {
+    let error = Error::new(ErrorKind::Other, "bad thing");
+    let x = 'x';
+
+    println!("error: {}", format!("something failed at {}", Location::caller()));
+    println!("{}: {}", error, format!("something failed at {}", Location::caller()));
+    println!("{:?}: {}", error, format!("something failed at {}", Location::caller()));
+    println!("{{}}: {}", format!("something failed at {}", Location::caller()));
+    println!(r#"error: "{}""#, format!("something failed at {}", Location::caller()));
+    println!("error: {}", format!(r#"something failed at "{}""#, Location::caller()));
+    println!("error: {}", format!("something failed at {} {0}", Location::caller()));
+    let _ = format!("error: {}", format!("something failed at {}", Location::caller()));
+    let _ = write!(
+        stdout(),
+        "error: {}",
+        format!("something failed at {}", Location::caller())
+    );
+    let _ = writeln!(
+        stdout(),
+        "error: {}",
+        format!("something failed at {}", Location::caller())
+    );
+    print!("error: {}", format!("something failed at {}", Location::caller()));
+    eprint!("error: {}", format!("something failed at {}", Location::caller()));
+    eprintln!("error: {}", format!("something failed at {}", Location::caller()));
+    let _ = format_args!("error: {}", format!("something failed at {}", Location::caller()));
+    assert!(true, "error: {}", format!("something failed at {}", Location::caller()));
+    assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
+    assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
+    panic!("error: {}", format!("something failed at {}", Location::caller()));
+
+    // negative tests
+    println!("error: {}", format_args!("something failed at {}", Location::caller()));
+    println!("error: {:>70}", format!("something failed at {}", Location::caller()));
+    println!("error: {} {0}", format!("something failed at {}", Location::caller()));
+    println!("{} and again {0}", format!("hi {}", x));
+    my_macro!();
+    println!("error: {}", my_other_macro!());
+}
diff --git a/src/tools/clippy/tests/ui/format_args_unfixable.stderr b/src/tools/clippy/tests/ui/format_args_unfixable.stderr
new file mode 100644 (file)
index 0000000..4476218
--- /dev/null
@@ -0,0 +1,175 @@
+error: `format!` in `println!` args
+  --> $DIR/format_args_unfixable.rs:27:5
+   |
+LL |     println!("error: {}", format!("something failed at {}", Location::caller()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::format-in-format-args` implied by `-D warnings`
+   = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+  --> $DIR/format_args_unfixable.rs:28:5
+   |
+LL |     println!("{}: {}", error, format!("something failed at {}", Location::caller()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+  --> $DIR/format_args_unfixable.rs:29:5
+   |
+LL |     println!("{:?}: {}", error, format!("something failed at {}", Location::caller()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+  --> $DIR/format_args_unfixable.rs:30:5
+   |
+LL |     println!("{{}}: {}", format!("something failed at {}", Location::caller()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+  --> $DIR/format_args_unfixable.rs:31:5
+   |
+LL |     println!(r#"error: "{}""#, format!("something failed at {}", Location::caller()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+  --> $DIR/format_args_unfixable.rs:32:5
+   |
+LL |     println!("error: {}", format!(r#"something failed at "{}""#, Location::caller()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+  --> $DIR/format_args_unfixable.rs:33:5
+   |
+LL |     println!("error: {}", format!("something failed at {} {0}", Location::caller()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `format!` args
+  --> $DIR/format_args_unfixable.rs:34:13
+   |
+LL |     let _ = format!("error: {}", format!("something failed at {}", Location::caller()));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `format!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `write!` args
+  --> $DIR/format_args_unfixable.rs:35:13
+   |
+LL |       let _ = write!(
+   |  _____________^
+LL | |         stdout(),
+LL | |         "error: {}",
+LL | |         format!("something failed at {}", Location::caller())
+LL | |     );
+   | |_____^
+   |
+   = help: combine the `format!(..)` arguments with the outer `write!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `writeln!` args
+  --> $DIR/format_args_unfixable.rs:40:13
+   |
+LL |       let _ = writeln!(
+   |  _____________^
+LL | |         stdout(),
+LL | |         "error: {}",
+LL | |         format!("something failed at {}", Location::caller())
+LL | |     );
+   | |_____^
+   |
+   = help: combine the `format!(..)` arguments with the outer `writeln!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `print!` args
+  --> $DIR/format_args_unfixable.rs:45:5
+   |
+LL |     print!("error: {}", format!("something failed at {}", Location::caller()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `print!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `eprint!` args
+  --> $DIR/format_args_unfixable.rs:46:5
+   |
+LL |     eprint!("error: {}", format!("something failed at {}", Location::caller()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `eprint!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `eprintln!` args
+  --> $DIR/format_args_unfixable.rs:47:5
+   |
+LL |     eprintln!("error: {}", format!("something failed at {}", Location::caller()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `eprintln!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `format_args!` args
+  --> $DIR/format_args_unfixable.rs:48:13
+   |
+LL |     let _ = format_args!("error: {}", format!("something failed at {}", Location::caller()));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `format_args!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `assert!` args
+  --> $DIR/format_args_unfixable.rs:49:5
+   |
+LL |     assert!(true, "error: {}", format!("something failed at {}", Location::caller()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `assert!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `assert_eq!` args
+  --> $DIR/format_args_unfixable.rs:50:5
+   |
+LL |     assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `assert_eq!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `assert_ne!` args
+  --> $DIR/format_args_unfixable.rs:51:5
+   |
+LL |     assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `assert_ne!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `panic!` args
+  --> $DIR/format_args_unfixable.rs:52:5
+   |
+LL |     panic!("error: {}", format!("something failed at {}", Location::caller()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: combine the `format!(..)` arguments with the outer `panic!(..)` call
+   = help: or consider changing `format!` to `format_args!`
+
+error: aborting due to 18 previous errors
+
index d3a920de4b6ad8a685f3c04096a3afd414826998..858036692d68f401d36c464754b82662f150c540 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 #![warn(clippy::future_not_send)]
 
 use std::cell::Cell;
index c734051ccf320b086567185414793a707c50a379..3cc05e2fdbec65c0b9574b0c45b924f63bcd6ca5 100644 (file)
@@ -1,12 +1,12 @@
 error: future cannot be sent between threads safely
-  --> $DIR/future_not_send.rs:8:62
+  --> $DIR/future_not_send.rs:7:62
    |
 LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
    |                                                              ^^^^ future returned by `private_future` is not `Send`
    |
    = note: `-D clippy::future-not-send` implied by `-D warnings`
 note: future is not `Send` as this value is used across an await
-  --> $DIR/future_not_send.rs:9:5
+  --> $DIR/future_not_send.rs:8:5
    |
 LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
    |                         -- has type `std::rc::Rc<[u8]>` which is not `Send`
@@ -16,7 +16,7 @@ LL | }
    | - `rc` is later dropped here
    = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
 note: future is not `Send` as this value is used across an await
-  --> $DIR/future_not_send.rs:9:5
+  --> $DIR/future_not_send.rs:8:5
    |
 LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
    |                                       ---- has type `&std::cell::Cell<usize>` which is not `Send`
@@ -27,13 +27,13 @@ LL | }
    = note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
 
 error: future cannot be sent between threads safely
-  --> $DIR/future_not_send.rs:12:42
+  --> $DIR/future_not_send.rs:11:42
    |
 LL | pub async fn public_future(rc: Rc<[u8]>) {
    |                                          ^ future returned by `public_future` is not `Send`
    |
 note: future is not `Send` as this value is used across an await
-  --> $DIR/future_not_send.rs:13:5
+  --> $DIR/future_not_send.rs:12:5
    |
 LL | pub async fn public_future(rc: Rc<[u8]>) {
    |                            -- has type `std::rc::Rc<[u8]>` which is not `Send`
@@ -44,45 +44,45 @@ LL | }
    = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
 
 error: future cannot be sent between threads safely
-  --> $DIR/future_not_send.rs:20:63
+  --> $DIR/future_not_send.rs:19:63
    |
 LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
    |                                                               ^^^^ future returned by `private_future2` is not `Send`
    |
 note: captured value is not `Send`
-  --> $DIR/future_not_send.rs:20:26
+  --> $DIR/future_not_send.rs:19:26
    |
 LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
    |                          ^^ has type `std::rc::Rc<[u8]>` which is not `Send`
    = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
 note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
-  --> $DIR/future_not_send.rs:20:40
+  --> $DIR/future_not_send.rs:19:40
    |
 LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
    |                                        ^^^^ has type `&std::cell::Cell<usize>` which is not `Send`, because `std::cell::Cell<usize>` is not `Sync`
    = note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
 
 error: future cannot be sent between threads safely
-  --> $DIR/future_not_send.rs:24:43
+  --> $DIR/future_not_send.rs:23:43
    |
 LL | pub async fn public_future2(rc: Rc<[u8]>) {}
    |                                           ^ future returned by `public_future2` is not `Send`
    |
 note: captured value is not `Send`
-  --> $DIR/future_not_send.rs:24:29
+  --> $DIR/future_not_send.rs:23:29
    |
 LL | pub async fn public_future2(rc: Rc<[u8]>) {}
    |                             ^^ has type `std::rc::Rc<[u8]>` which is not `Send`
    = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
 
 error: future cannot be sent between threads safely
-  --> $DIR/future_not_send.rs:35:39
+  --> $DIR/future_not_send.rs:34:39
    |
 LL |     async fn private_future(&self) -> usize {
    |                                       ^^^^^ future returned by `private_future` is not `Send`
    |
 note: future is not `Send` as this value is used across an await
-  --> $DIR/future_not_send.rs:36:9
+  --> $DIR/future_not_send.rs:35:9
    |
 LL |     async fn private_future(&self) -> usize {
    |                             ----- has type `&Dummy` which is not `Send`
@@ -94,13 +94,13 @@ LL |     }
    = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
 
 error: future cannot be sent between threads safely
-  --> $DIR/future_not_send.rs:40:39
+  --> $DIR/future_not_send.rs:39:39
    |
 LL |     pub async fn public_future(&self) {
    |                                       ^ future returned by `public_future` is not `Send`
    |
 note: future is not `Send` as this value is used across an await
-  --> $DIR/future_not_send.rs:41:9
+  --> $DIR/future_not_send.rs:40:9
    |
 LL |     pub async fn public_future(&self) {
    |                                ----- has type `&Dummy` which is not `Send`
@@ -111,13 +111,13 @@ LL |     }
    = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
 
 error: future cannot be sent between threads safely
-  --> $DIR/future_not_send.rs:50:37
+  --> $DIR/future_not_send.rs:49:37
    |
 LL | async fn generic_future<T>(t: T) -> T
    |                                     ^ future returned by `generic_future` is not `Send`
    |
 note: future is not `Send` as this value is used across an await
-  --> $DIR/future_not_send.rs:55:5
+  --> $DIR/future_not_send.rs:54:5
    |
 LL |     let rt = &t;
    |         -- has type `&T` which is not `Send`
@@ -129,13 +129,13 @@ LL | }
    = note: `T` doesn't implement `std::marker::Sync`
 
 error: future cannot be sent between threads safely
-  --> $DIR/future_not_send.rs:66:34
+  --> $DIR/future_not_send.rs:65:34
    |
 LL | async fn unclear_future<T>(t: T) {}
    |                                  ^ future returned by `unclear_future` is not `Send`
    |
 note: captured value is not `Send`
-  --> $DIR/future_not_send.rs:66:28
+  --> $DIR/future_not_send.rs:65:28
    |
 LL | async fn unclear_future<T>(t: T) {}
    |                            ^ has type `T` which is not `Send`
index dc3fb1ceac9a44ba1dd69d063040b49f9feff534..b7012b43d29766d154786e866357b15b838d5756 100644 (file)
@@ -1,6 +1,9 @@
 #![warn(clippy::all)]
 #![warn(clippy::if_not_else)]
 
+fn foo() -> bool {
+    unimplemented!()
+}
 fn bla() -> bool {
     unimplemented!()
 }
@@ -16,4 +19,11 @@ fn main() {
     } else {
         println!("Bunny");
     }
+    if !foo() {
+        println!("Foo");
+    } else if !bla() {
+        println!("Bugs");
+    } else {
+        println!("Bunny");
+    }
 }
index 53d1b86d02a962a639631ea29c6415573cb8ee51..8c8cc44bb035882e2484a96a8874351632c6be89 100644 (file)
@@ -1,5 +1,5 @@
 error: unnecessary boolean `not` operation
-  --> $DIR/if_not_else.rs:9:5
+  --> $DIR/if_not_else.rs:12:5
    |
 LL | /     if !bla() {
 LL | |         println!("Bugs");
@@ -12,7 +12,7 @@ LL | |     }
    = help: remove the `!` and swap the blocks of the `if`/`else`
 
 error: unnecessary `!=` operation
-  --> $DIR/if_not_else.rs:14:5
+  --> $DIR/if_not_else.rs:17:5
    |
 LL | /     if 4 != 5 {
 LL | |         println!("Bugs");
diff --git a/src/tools/clippy/tests/ui/if_then_panic.fixed b/src/tools/clippy/tests/ui/if_then_panic.fixed
deleted file mode 100644 (file)
index 0998f8f..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// run-rustfix
-#![warn(clippy::if_then_panic)]
-
-fn main() {
-    let a = vec![1, 2, 3];
-    let c = Some(2);
-    if !a.is_empty()
-        && a.len() == 3
-        && c != None
-        && !a.is_empty()
-        && a.len() == 3
-        && !a.is_empty()
-        && a.len() == 3
-        && !a.is_empty()
-        && a.len() == 3
-    {
-        panic!("qaqaq{:?}", a);
-    }
-    assert!(a.is_empty(), "qaqaq{:?}", a);
-    assert!(a.is_empty(), "qwqwq");
-    if a.len() == 3 {
-        println!("qwq");
-        println!("qwq");
-        println!("qwq");
-    }
-    if let Some(b) = c {
-        panic!("orz {}", b);
-    }
-    if a.len() == 3 {
-        panic!("qaqaq");
-    } else {
-        println!("qwq");
-    }
-    let b = vec![1, 2, 3];
-    assert!(!b.is_empty(), "panic1");
-    assert!(!(b.is_empty() && a.is_empty()), "panic2");
-    assert!(!(a.is_empty() && !b.is_empty()), "panic3");
-    assert!(!(b.is_empty() || a.is_empty()), "panic4");
-    assert!(!(a.is_empty() || !b.is_empty()), "panic5");
-}
diff --git a/src/tools/clippy/tests/ui/if_then_panic.rs b/src/tools/clippy/tests/ui/if_then_panic.rs
deleted file mode 100644 (file)
index 10433c8..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-// run-rustfix
-#![warn(clippy::if_then_panic)]
-
-fn main() {
-    let a = vec![1, 2, 3];
-    let c = Some(2);
-    if !a.is_empty()
-        && a.len() == 3
-        && c != None
-        && !a.is_empty()
-        && a.len() == 3
-        && !a.is_empty()
-        && a.len() == 3
-        && !a.is_empty()
-        && a.len() == 3
-    {
-        panic!("qaqaq{:?}", a);
-    }
-    if !a.is_empty() {
-        panic!("qaqaq{:?}", a);
-    }
-    if !a.is_empty() {
-        panic!("qwqwq");
-    }
-    if a.len() == 3 {
-        println!("qwq");
-        println!("qwq");
-        println!("qwq");
-    }
-    if let Some(b) = c {
-        panic!("orz {}", b);
-    }
-    if a.len() == 3 {
-        panic!("qaqaq");
-    } else {
-        println!("qwq");
-    }
-    let b = vec![1, 2, 3];
-    if b.is_empty() {
-        panic!("panic1");
-    }
-    if b.is_empty() && a.is_empty() {
-        panic!("panic2");
-    }
-    if a.is_empty() && !b.is_empty() {
-        panic!("panic3");
-    }
-    if b.is_empty() || a.is_empty() {
-        panic!("panic4");
-    }
-    if a.is_empty() || !b.is_empty() {
-        panic!("panic5");
-    }
-}
diff --git a/src/tools/clippy/tests/ui/if_then_panic.stderr b/src/tools/clippy/tests/ui/if_then_panic.stderr
deleted file mode 100644 (file)
index 5bb62f8..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-error: only a `panic!` in `if`-then statement
-  --> $DIR/if_then_panic.rs:19:5
-   |
-LL | /     if !a.is_empty() {
-LL | |         panic!("qaqaq{:?}", a);
-LL | |     }
-   | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
-   |
-   = note: `-D clippy::if-then-panic` implied by `-D warnings`
-
-error: only a `panic!` in `if`-then statement
-  --> $DIR/if_then_panic.rs:22:5
-   |
-LL | /     if !a.is_empty() {
-LL | |         panic!("qwqwq");
-LL | |     }
-   | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
-
-error: only a `panic!` in `if`-then statement
-  --> $DIR/if_then_panic.rs:39:5
-   |
-LL | /     if b.is_empty() {
-LL | |         panic!("panic1");
-LL | |     }
-   | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
-
-error: only a `panic!` in `if`-then statement
-  --> $DIR/if_then_panic.rs:42:5
-   |
-LL | /     if b.is_empty() && a.is_empty() {
-LL | |         panic!("panic2");
-LL | |     }
-   | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
-
-error: only a `panic!` in `if`-then statement
-  --> $DIR/if_then_panic.rs:45:5
-   |
-LL | /     if a.is_empty() && !b.is_empty() {
-LL | |         panic!("panic3");
-LL | |     }
-   | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
-
-error: only a `panic!` in `if`-then statement
-  --> $DIR/if_then_panic.rs:48:5
-   |
-LL | /     if b.is_empty() || a.is_empty() {
-LL | |         panic!("panic4");
-LL | |     }
-   | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
-
-error: only a `panic!` in `if`-then statement
-  --> $DIR/if_then_panic.rs:51:5
-   |
-LL | /     if a.is_empty() || !b.is_empty() {
-LL | |         panic!("panic5");
-LL | |     }
-   | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
-
-error: aborting due to 7 previous errors
-
index aa69b0974101c822a06a790c742bed645e46813b..fd96ca3f466eabe7cc9ed034040925a658f274c9 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 // aux-build:implicit_hasher_macros.rs
 #![deny(clippy::implicit_hasher)]
 #![allow(unused)]
index 3f5f56b923fe2453b25e792bc9b5a912f880cd90..59b0fba2a4cfee460b8e2d120a91b01fb1c3d952 100644 (file)
@@ -1,11 +1,11 @@
 error: impl for `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:17:35
+  --> $DIR/implicit_hasher.rs:16:35
    |
 LL | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> {
    |                                   ^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/implicit_hasher.rs:3:9
+  --> $DIR/implicit_hasher.rs:2:9
    |
 LL | #![deny(clippy::implicit_hasher)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^
@@ -19,7 +19,7 @@ LL |         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default:
    |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: impl for `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:26:36
+  --> $DIR/implicit_hasher.rs:25:36
    |
 LL | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) {
    |                                    ^^^^^^^^^^^^^
@@ -34,7 +34,7 @@ LL |         ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Defa
    |           ~~~~~~~~~~~~~~~~~~     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: impl for `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:31:19
+  --> $DIR/implicit_hasher.rs:30:19
    |
 LL | impl Foo<i16> for HashMap<String, String> {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL |         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default:
    |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: impl for `HashSet` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:48:32
+  --> $DIR/implicit_hasher.rs:47:32
    |
 LL | impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
    |                                ^^^^^^^^^^
@@ -64,7 +64,7 @@ LL |         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default:
    |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: impl for `HashSet` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:53:19
+  --> $DIR/implicit_hasher.rs:52:19
    |
 LL | impl Foo<i16> for HashSet<String> {
    |                   ^^^^^^^^^^^^^^^
@@ -79,7 +79,7 @@ LL |         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default:
    |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: parameter of type `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:70:23
+  --> $DIR/implicit_hasher.rs:69:23
    |
 LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
    |                       ^^^^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _s
    |           +++++++++++++++++++++++++++++            ~~~~~~~~~~~~~~~~~~~~
 
 error: parameter of type `HashSet` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:70:53
+  --> $DIR/implicit_hasher.rs:69:53
    |
 LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
    |                                                     ^^^^^^^^^^^^
@@ -101,7 +101,7 @@ LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set:
    |           +++++++++++++++++++++++++++++                                          ~~~~~~~~~~~~~~~
 
 error: impl for `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:74:43
+  --> $DIR/implicit_hasher.rs:73:43
    |
 LL |         impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
    |                                           ^^^^^^^^^^^^^
@@ -120,7 +120,7 @@ LL |                 (HashMap::default(), HashMap::with_capacity_and_hasher(10,
    |                  ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: parameter of type `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:82:33
+  --> $DIR/implicit_hasher.rs:81:33
    |
 LL |         pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
    |                                 ^^^^^^^^^^^^^^^^^
@@ -135,7 +135,7 @@ LL |         pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i
    |                     +++++++++++++++++++++++++++++            ~~~~~~~~~~~~~~~~~~~~
 
 error: parameter of type `HashSet` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:82:63
+  --> $DIR/implicit_hasher.rs:81:63
    |
 LL |         pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
    |                                                               ^^^^^^^^^^^^
@@ -150,7 +150,7 @@ LL |         pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i
    |                     +++++++++++++++++++++++++++++                                          ~~~~~~~~~~~~~~~
 
 error: parameter of type `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:101:35
+  --> $DIR/implicit_hasher.rs:100:35
    |
 LL | pub async fn election_vote(_data: HashMap<i32, i32>) {}
    |                                   ^^^^^^^^^^^^^^^^^
index 7698b88a88c8aa80a143ac27ab11e145a880ef51..a51f7bc6a29ffff52a301b84053f3c8f58bddc53 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 // run-rustfix
 
 #![warn(clippy::implicit_return)]
index 45bbc2ec670e05463d1a0f8d6f8d5fc557561cfe..03f8ec49d51e5457a57e2c9a71e30669fb984b1d 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 // run-rustfix
 
 #![warn(clippy::implicit_return)]
index 5e078b15ce393f6070b3f932ec0553d0c880f91f..522bc3bf895a7a3159dccdb74e56fe032c10c483 100644 (file)
@@ -1,5 +1,5 @@
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:13:5
+  --> $DIR/implicit_return.rs:12:5
    |
 LL |     true
    |     ^^^^ help: add `return` as shown: `return true`
@@ -7,85 +7,85 @@ LL |     true
    = note: `-D clippy::implicit-return` implied by `-D warnings`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:17:15
+  --> $DIR/implicit_return.rs:16:15
    |
 LL |     if true { true } else { false }
    |               ^^^^ help: add `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:17:29
+  --> $DIR/implicit_return.rs:16:29
    |
 LL |     if true { true } else { false }
    |                             ^^^^^ help: add `return` as shown: `return false`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:23:17
+  --> $DIR/implicit_return.rs:22:17
    |
 LL |         true => false,
    |                 ^^^^^ help: add `return` as shown: `return false`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:24:20
+  --> $DIR/implicit_return.rs:23:20
    |
 LL |         false => { true },
    |                    ^^^^ help: add `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:37:9
+  --> $DIR/implicit_return.rs:36:9
    |
 LL |         break true;
    |         ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:44:13
+  --> $DIR/implicit_return.rs:43:13
    |
 LL |             break true;
    |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:52:13
+  --> $DIR/implicit_return.rs:51:13
    |
 LL |             break true;
    |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:70:18
+  --> $DIR/implicit_return.rs:69:18
    |
 LL |     let _ = || { true };
    |                  ^^^^ help: add `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:71:16
+  --> $DIR/implicit_return.rs:70:16
    |
 LL |     let _ = || true;
    |                ^^^^ help: add `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:79:5
+  --> $DIR/implicit_return.rs:78:5
    |
 LL |     format!("test {}", "test")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:88:5
+  --> $DIR/implicit_return.rs:87:5
    |
 LL |     m!(true, false)
    |     ^^^^^^^^^^^^^^^ help: add `return` as shown: `return m!(true, false)`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:94:13
+  --> $DIR/implicit_return.rs:93:13
    |
 LL |             break true;
    |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:99:17
+  --> $DIR/implicit_return.rs:98:17
    |
 LL |                 break 'outer false;
    |                 ^^^^^^^^^^^^^^^^^^ help: change `break` to `return` as shown: `return false`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:114:5
+  --> $DIR/implicit_return.rs:113:5
    |
 LL | /     loop {
 LL | |         m!(true);
@@ -100,7 +100,7 @@ LL +     }
    |
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:128:5
+  --> $DIR/implicit_return.rs:127:5
    |
 LL |     true
    |     ^^^^ help: add `return` as shown: `return true`
index 859765d08a70bbb83d313b53f608cd23d07aff4b..e6f57e9267eac93091e423180bbaef8f9d97315b 100644 (file)
@@ -157,4 +157,12 @@ fn main() {
     if i_64 != 0 {
         i_64 -= 1;
     }
+
+    // issue #7831
+    // No Lint
+    if u_32 > 0 {
+        u_32 -= 1;
+    } else {
+        println!("side effect");
+    }
 }
index 2f32a7b1578219a2a5c951b9099994a22681bed5..8bb28d149c62895c210a5e4ba68082daf6ff9813 100644 (file)
@@ -203,4 +203,12 @@ fn main() {
     if i_64 != 0 {
         i_64 -= 1;
     }
+
+    // issue #7831
+    // No Lint
+    if u_32 > 0 {
+        u_32 -= 1;
+    } else {
+        println!("side effect");
+    }
 }
index d1025743790a9747bfb95c6bb746d0b1e15b917c..eb66d1afddce39dfce67d421a7229232b52b2b6f 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-// edition:2018
 #![warn(clippy::inconsistent_struct_constructor)]
 #![allow(clippy::redundant_field_names)]
 #![allow(clippy::unnecessary_operation)]
index b095aa64a2174371e94d9f2c240ed910c9c893ca..5caadc7c62083fb2b214df04ded3b16e2bb665f7 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-// edition:2018
 #![warn(clippy::inconsistent_struct_constructor)]
 #![allow(clippy::redundant_field_names)]
 #![allow(clippy::unnecessary_operation)]
index ef308dedb1661c331703d68d9ab973477f473d51..c90189e964f09e68cea01babbb5d25ba03689909 100644 (file)
@@ -1,5 +1,5 @@
 error: struct constructor field order is inconsistent with struct definition field order
-  --> $DIR/inconsistent_struct_constructor.rs:34:9
+  --> $DIR/inconsistent_struct_constructor.rs:33:9
    |
 LL |         Foo { y, x, z };
    |         ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }`
@@ -7,7 +7,7 @@ LL |         Foo { y, x, z };
    = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings`
 
 error: struct constructor field order is inconsistent with struct definition field order
-  --> $DIR/inconsistent_struct_constructor.rs:56:9
+  --> $DIR/inconsistent_struct_constructor.rs:55:9
    |
 LL | /         Foo {
 LL | |             z,
diff --git a/src/tools/clippy/tests/ui/issue-7447.stderr b/src/tools/clippy/tests/ui/issue-7447.stderr
new file mode 100644 (file)
index 0000000..463a48b
--- /dev/null
@@ -0,0 +1,19 @@
+error: sub-expression diverges
+  --> $DIR/issue-7447.rs:23:15
+   |
+LL |     byte_view(panic!());
+   |               ^^^^^^^^
+   |
+   = note: `-D clippy::diverging-sub-expression` implied by `-D warnings`
+   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: sub-expression diverges
+  --> $DIR/issue-7447.rs:24:19
+   |
+LL |     group_entries(panic!());
+   |                   ^^^^^^^^
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
index cc699b79e433ca39756717f16714487a05421da7..d9d48189bd74e741f381f9449783ecefd5cce514 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 #![allow(dead_code)]
 
 async fn sink1<'a>(_: &'a str) {} // lint
index 0426508e622f8fd471a61e0464e1ba53ccf537a3..20419457b47f0ee3018f9ec888939e1d96cfbae4 100644 (file)
@@ -1,5 +1,5 @@
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/issue_4266.rs:4:1
+  --> $DIR/issue_4266.rs:3:1
    |
 LL | async fn sink1<'a>(_: &'a str) {} // lint
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | async fn sink1<'a>(_: &'a str) {} // lint
    = note: `-D clippy::needless-lifetimes` implied by `-D warnings`
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/issue_4266.rs:8:1
+  --> $DIR/issue_4266.rs:7:1
    |
 LL | async fn one_to_one<'a>(s: &'a str) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 97c5929783d882c51dd754244c8bec46ff292f5d..90a6eef75261f505c6fd517b1280c548581f2d8e 100644 (file)
@@ -33,6 +33,7 @@ impl HasIter {
     }
 }
 
+#[allow(unused_must_use)]
 fn main() {
     let mut vec = vec![0, 1, 2, 3];
     let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
@@ -50,7 +51,7 @@ fn main() {
     linked_list.push_back(1);
     binary_heap.push(1);
 
-    let _ = &vec[..].len();
+    &vec[..].len();
     vec.len();
     boxed_slice.len();
     vec_deque.len();
@@ -62,13 +63,13 @@ fn main() {
     binary_heap.len();
 
     vec.len();
-    let _ = &vec[..].len();
+    &vec[..].len();
     vec_deque.len();
     hash_map.len();
     b_tree_map.len();
     linked_list.len();
 
-    let _ = &vec[..].len();
+    &vec[..].len();
     vec.len();
     vec_deque.len();
     hash_set.len();
index 70bb734763f09bef26eb35bc4b45f9c196dce29b..6681a480a28c817472eb5bdb1976bb5a948cd61b 100644 (file)
@@ -33,6 +33,7 @@ fn into_iter(self) -> IteratorFalsePositives {
     }
 }
 
+#[allow(unused_must_use)]
 fn main() {
     let mut vec = vec![0, 1, 2, 3];
     let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
@@ -50,7 +51,7 @@ fn main() {
     linked_list.push_back(1);
     binary_heap.push(1);
 
-    let _ = &vec[..].iter().count();
+    &vec[..].iter().count();
     vec.iter().count();
     boxed_slice.iter().count();
     vec_deque.iter().count();
@@ -62,13 +63,13 @@ fn main() {
     binary_heap.iter().count();
 
     vec.iter_mut().count();
-    let _ = &vec[..].iter_mut().count();
+    &vec[..].iter_mut().count();
     vec_deque.iter_mut().count();
     hash_map.iter_mut().count();
     b_tree_map.iter_mut().count();
     linked_list.iter_mut().count();
 
-    let _ = &vec[..].into_iter().count();
+    &vec[..].into_iter().count();
     vec.into_iter().count();
     vec_deque.into_iter().count();
     hash_set.into_iter().count();
index 1d2c22f9dfad5470e0b1d478b439a26587bc7a1b..2e3d7fc35de9c0de17d3f712bbc87a892c90dbad 100644 (file)
 error: called `.iter().count()` on a `slice`
-  --> $DIR/iter_count.rs:53:14
+  --> $DIR/iter_count.rs:54:6
    |
-LL |     let _ = &vec[..].iter().count();
-   |              ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
+LL |     &vec[..].iter().count();
+   |      ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
    |
    = note: `-D clippy::iter-count` implied by `-D warnings`
 
 error: called `.iter().count()` on a `Vec`
-  --> $DIR/iter_count.rs:54:5
+  --> $DIR/iter_count.rs:55:5
    |
 LL |     vec.iter().count();
    |     ^^^^^^^^^^^^^^^^^^ help: try: `vec.len()`
 
 error: called `.iter().count()` on a `slice`
-  --> $DIR/iter_count.rs:55:5
+  --> $DIR/iter_count.rs:56:5
    |
 LL |     boxed_slice.iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice.len()`
 
 error: called `.iter().count()` on a `VecDeque`
-  --> $DIR/iter_count.rs:56:5
+  --> $DIR/iter_count.rs:57:5
    |
 LL |     vec_deque.iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()`
 
 error: called `.iter().count()` on a `HashSet`
-  --> $DIR/iter_count.rs:57:5
+  --> $DIR/iter_count.rs:58:5
    |
 LL |     hash_set.iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()`
 
 error: called `.iter().count()` on a `HashMap`
-  --> $DIR/iter_count.rs:58:5
+  --> $DIR/iter_count.rs:59:5
    |
 LL |     hash_map.iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()`
 
 error: called `.iter().count()` on a `BTreeMap`
-  --> $DIR/iter_count.rs:59:5
+  --> $DIR/iter_count.rs:60:5
    |
 LL |     b_tree_map.iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()`
 
 error: called `.iter().count()` on a `BTreeSet`
-  --> $DIR/iter_count.rs:60:5
+  --> $DIR/iter_count.rs:61:5
    |
 LL |     b_tree_set.iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_set.len()`
 
 error: called `.iter().count()` on a `LinkedList`
-  --> $DIR/iter_count.rs:61:5
+  --> $DIR/iter_count.rs:62:5
    |
 LL |     linked_list.iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()`
 
 error: called `.iter().count()` on a `BinaryHeap`
-  --> $DIR/iter_count.rs:62:5
+  --> $DIR/iter_count.rs:63:5
    |
 LL |     binary_heap.iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `binary_heap.len()`
 
 error: called `.iter_mut().count()` on a `Vec`
-  --> $DIR/iter_count.rs:64:5
+  --> $DIR/iter_count.rs:65:5
    |
 LL |     vec.iter_mut().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()`
 
 error: called `.iter_mut().count()` on a `slice`
-  --> $DIR/iter_count.rs:65:14
+  --> $DIR/iter_count.rs:66:6
    |
-LL |     let _ = &vec[..].iter_mut().count();
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
+LL |     &vec[..].iter_mut().count();
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
 
 error: called `.iter_mut().count()` on a `VecDeque`
-  --> $DIR/iter_count.rs:66:5
+  --> $DIR/iter_count.rs:67:5
    |
 LL |     vec_deque.iter_mut().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()`
 
 error: called `.iter_mut().count()` on a `HashMap`
-  --> $DIR/iter_count.rs:67:5
+  --> $DIR/iter_count.rs:68:5
    |
 LL |     hash_map.iter_mut().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()`
 
 error: called `.iter_mut().count()` on a `BTreeMap`
-  --> $DIR/iter_count.rs:68:5
+  --> $DIR/iter_count.rs:69:5
    |
 LL |     b_tree_map.iter_mut().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()`
 
 error: called `.iter_mut().count()` on a `LinkedList`
-  --> $DIR/iter_count.rs:69:5
+  --> $DIR/iter_count.rs:70:5
    |
 LL |     linked_list.iter_mut().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()`
 
 error: called `.into_iter().count()` on a `slice`
-  --> $DIR/iter_count.rs:71:14
+  --> $DIR/iter_count.rs:72:6
    |
-LL |     let _ = &vec[..].into_iter().count();
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
+LL |     &vec[..].into_iter().count();
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
 
 error: called `.into_iter().count()` on a `Vec`
-  --> $DIR/iter_count.rs:72:5
+  --> $DIR/iter_count.rs:73:5
    |
 LL |     vec.into_iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()`
 
 error: called `.into_iter().count()` on a `VecDeque`
-  --> $DIR/iter_count.rs:73:5
+  --> $DIR/iter_count.rs:74:5
    |
 LL |     vec_deque.into_iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()`
 
 error: called `.into_iter().count()` on a `HashSet`
-  --> $DIR/iter_count.rs:74:5
+  --> $DIR/iter_count.rs:75:5
    |
 LL |     hash_set.into_iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()`
 
 error: called `.into_iter().count()` on a `HashMap`
-  --> $DIR/iter_count.rs:75:5
+  --> $DIR/iter_count.rs:76:5
    |
 LL |     hash_map.into_iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()`
 
 error: called `.into_iter().count()` on a `BTreeMap`
-  --> $DIR/iter_count.rs:76:5
+  --> $DIR/iter_count.rs:77:5
    |
 LL |     b_tree_map.into_iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()`
 
 error: called `.into_iter().count()` on a `BTreeSet`
-  --> $DIR/iter_count.rs:77:5
+  --> $DIR/iter_count.rs:78:5
    |
 LL |     b_tree_set.into_iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_set.len()`
 
 error: called `.into_iter().count()` on a `LinkedList`
-  --> $DIR/iter_count.rs:78:5
+  --> $DIR/iter_count.rs:79:5
    |
 LL |     linked_list.into_iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()`
 
 error: called `.into_iter().count()` on a `BinaryHeap`
-  --> $DIR/iter_count.rs:79:5
+  --> $DIR/iter_count.rs:80:5
    |
 LL |     binary_heap.into_iter().count();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `binary_heap.len()`
index b9d66347c27487b9857e99e2be575796273ac6b7..1e938e72b57775356d326a9f0bac9dcae6b57525 100644 (file)
@@ -1,5 +1,3 @@
-// edition:2018
-
 #![warn(clippy::len_without_is_empty)]
 #![allow(dead_code, unused)]
 
index 3282709bcd6717f664ef135c6132b38e9ab3a389..a1f48f7610b44857edf7f6f8f9e6dbbc520c1a0d 100644 (file)
@@ -1,5 +1,5 @@
 error: struct `PubOne` has a public `len` method, but no `is_empty` method
-  --> $DIR/len_without_is_empty.rs:9:5
+  --> $DIR/len_without_is_empty.rs:7:5
    |
 LL |     pub fn len(&self) -> isize {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     pub fn len(&self) -> isize {
    = note: `-D clippy::len-without-is-empty` implied by `-D warnings`
 
 error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` method
-  --> $DIR/len_without_is_empty.rs:57:1
+  --> $DIR/len_without_is_empty.rs:55:1
    |
 LL | / pub trait PubTraitsToo {
 LL | |     fn len(&self) -> isize;
@@ -15,45 +15,45 @@ LL | | }
    | |_^
 
 error: struct `HasIsEmpty` has a public `len` method, but a private `is_empty` method
-  --> $DIR/len_without_is_empty.rs:70:5
+  --> $DIR/len_without_is_empty.rs:68:5
    |
 LL |     pub fn len(&self) -> isize {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `is_empty` defined here
-  --> $DIR/len_without_is_empty.rs:74:5
+  --> $DIR/len_without_is_empty.rs:72:5
    |
 LL |     fn is_empty(&self) -> bool {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: struct `HasWrongIsEmpty` has a public `len` method, but the `is_empty` method has an unexpected signature
-  --> $DIR/len_without_is_empty.rs:82:5
+  --> $DIR/len_without_is_empty.rs:80:5
    |
 LL |     pub fn len(&self) -> isize {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `is_empty` defined here
-  --> $DIR/len_without_is_empty.rs:86:5
+  --> $DIR/len_without_is_empty.rs:84:5
    |
 LL |     pub fn is_empty(&self, x: u32) -> bool {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: expected signature: `(&self) -> bool`
 
 error: struct `MismatchedSelf` has a public `len` method, but the `is_empty` method has an unexpected signature
-  --> $DIR/len_without_is_empty.rs:94:5
+  --> $DIR/len_without_is_empty.rs:92:5
    |
 LL |     pub fn len(self) -> isize {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `is_empty` defined here
-  --> $DIR/len_without_is_empty.rs:98:5
+  --> $DIR/len_without_is_empty.rs:96:5
    |
 LL |     pub fn is_empty(&self) -> bool {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: expected signature: `(self) -> bool`
 
 error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_empty` method
-  --> $DIR/len_without_is_empty.rs:173:1
+  --> $DIR/len_without_is_empty.rs:171:1
    |
 LL | / pub trait DependsOnFoo: Foo {
 LL | |     fn len(&mut self) -> usize;
@@ -61,33 +61,33 @@ LL | | }
    | |_^
 
 error: struct `OptionalLen3` has a public `len` method, but the `is_empty` method has an unexpected signature
-  --> $DIR/len_without_is_empty.rs:218:5
+  --> $DIR/len_without_is_empty.rs:216:5
    |
 LL |     pub fn len(&self) -> usize {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `is_empty` defined here
-  --> $DIR/len_without_is_empty.rs:223:5
+  --> $DIR/len_without_is_empty.rs:221:5
    |
 LL |     pub fn is_empty(&self) -> Option<bool> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: expected signature: `(&self) -> bool`
 
 error: struct `ResultLen` has a public `len` method, but the `is_empty` method has an unexpected signature
-  --> $DIR/len_without_is_empty.rs:230:5
+  --> $DIR/len_without_is_empty.rs:228:5
    |
 LL |     pub fn len(&self) -> Result<usize, ()> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `is_empty` defined here
-  --> $DIR/len_without_is_empty.rs:235:5
+  --> $DIR/len_without_is_empty.rs:233:5
    |
 LL |     pub fn is_empty(&self) -> Option<bool> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: expected signature: `(&self) -> bool` or `(&self) -> Result<bool>
 
 error: this returns a `Result<_, ()>`
-  --> $DIR/len_without_is_empty.rs:230:5
+  --> $DIR/len_without_is_empty.rs:228:5
    |
 LL |     pub fn len(&self) -> Result<usize, ()> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -96,7 +96,7 @@ LL |     pub fn len(&self) -> Result<usize, ()> {
    = help: use a custom `Error` type instead
 
 error: this returns a `Result<_, ()>`
-  --> $DIR/len_without_is_empty.rs:242:5
+  --> $DIR/len_without_is_empty.rs:240:5
    |
 LL |     pub fn len(&self) -> Result<usize, ()> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +104,7 @@ LL |     pub fn len(&self) -> Result<usize, ()> {
    = help: use a custom `Error` type instead
 
 error: this returns a `Result<_, ()>`
-  --> $DIR/len_without_is_empty.rs:246:5
+  --> $DIR/len_without_is_empty.rs:244:5
    |
 LL |     pub fn is_empty(&self) -> Result<bool, ()> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,7 +112,7 @@ LL |     pub fn is_empty(&self) -> Result<bool, ()> {
    = help: use a custom `Error` type instead
 
 error: this returns a `Result<_, ()>`
-  --> $DIR/len_without_is_empty.rs:253:5
+  --> $DIR/len_without_is_empty.rs:251:5
    |
 LL |     pub fn len(&self) -> Result<usize, ()> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index a72a74b9131d8bb21fb3b2431fd344c2d069706c..e60ce8492fc7716f70f3f490086d03d76904f07f 100644 (file)
@@ -2,7 +2,8 @@
 
 #![warn(clippy::mixed_case_hex_literals)]
 #![warn(clippy::zero_prefixed_literal)]
-#![allow(clippy::unseparated_literal_suffix)]
+#![warn(clippy::unseparated_literal_suffix)]
+#![warn(clippy::separated_literal_suffix)]
 #![allow(dead_code)]
 
 fn main() {
index 99542e20f785fea9f916c59976b20850fcd8edc7..365b240747352d76bc06b3e802e04f0049dabec6 100644 (file)
@@ -1,25 +1,65 @@
+error: integer type suffix should not be separated by an underscore
+  --> $DIR/literals.rs:12:15
+   |
+LL |     let ok4 = 0xab_cd_i32;
+   |               ^^^^^^^^^^^ help: remove the underscore: `0xab_cdi32`
+   |
+   = note: `-D clippy::separated-literal-suffix` implied by `-D warnings`
+
+error: integer type suffix should not be separated by an underscore
+  --> $DIR/literals.rs:13:15
+   |
+LL |     let ok5 = 0xAB_CD_u32;
+   |               ^^^^^^^^^^^ help: remove the underscore: `0xAB_CDu32`
+
+error: integer type suffix should not be separated by an underscore
+  --> $DIR/literals.rs:14:15
+   |
+LL |     let ok5 = 0xAB_CD_isize;
+   |               ^^^^^^^^^^^^^ help: remove the underscore: `0xAB_CDisize`
+
 error: inconsistent casing in hexadecimal literal
-  --> $DIR/literals.rs:14:17
+  --> $DIR/literals.rs:15:17
    |
 LL |     let fail1 = 0xabCD;
    |                 ^^^^^^
    |
    = note: `-D clippy::mixed-case-hex-literals` implied by `-D warnings`
 
+error: integer type suffix should not be separated by an underscore
+  --> $DIR/literals.rs:16:17
+   |
+LL |     let fail2 = 0xabCD_u32;
+   |                 ^^^^^^^^^^ help: remove the underscore: `0xabCDu32`
+
 error: inconsistent casing in hexadecimal literal
-  --> $DIR/literals.rs:15:17
+  --> $DIR/literals.rs:16:17
    |
 LL |     let fail2 = 0xabCD_u32;
    |                 ^^^^^^^^^^
 
+error: integer type suffix should not be separated by an underscore
+  --> $DIR/literals.rs:17:17
+   |
+LL |     let fail2 = 0xabCD_isize;
+   |                 ^^^^^^^^^^^^ help: remove the underscore: `0xabCDisize`
+
 error: inconsistent casing in hexadecimal literal
-  --> $DIR/literals.rs:16:17
+  --> $DIR/literals.rs:17:17
    |
 LL |     let fail2 = 0xabCD_isize;
    |                 ^^^^^^^^^^^^
 
+error: integer type suffix should be separated by an underscore
+  --> $DIR/literals.rs:18:27
+   |
+LL |     let fail_multi_zero = 000_123usize;
+   |                           ^^^^^^^^^^^^ help: add an underscore: `000_123_usize`
+   |
+   = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
+
 error: this is a decimal constant
-  --> $DIR/literals.rs:17:27
+  --> $DIR/literals.rs:18:27
    |
 LL |     let fail_multi_zero = 000_123usize;
    |                           ^^^^^^^^^^^^
@@ -34,8 +74,14 @@ help: if you mean to use an octal constant, use `0o`
 LL |     let fail_multi_zero = 0o123usize;
    |                           ~~~~~~~~~~
 
+error: integer type suffix should not be separated by an underscore
+  --> $DIR/literals.rs:21:16
+   |
+LL |     let ok10 = 0_i64;
+   |                ^^^^^ help: remove the underscore: `0i64`
+
 error: this is a decimal constant
-  --> $DIR/literals.rs:21:17
+  --> $DIR/literals.rs:22:17
    |
 LL |     let fail8 = 0123;
    |                 ^^^^
@@ -49,8 +95,14 @@ help: if you mean to use an octal constant, use `0o`
 LL |     let fail8 = 0o123;
    |                 ~~~~~
 
+error: integer type suffix should not be separated by an underscore
+  --> $DIR/literals.rs:31:16
+   |
+LL |     let ok17 = 0x123_4567_8901_usize;
+   |                ^^^^^^^^^^^^^^^^^^^^^ help: remove the underscore: `0x123_4567_8901usize`
+
 error: digits grouped inconsistently by underscores
-  --> $DIR/literals.rs:33:18
+  --> $DIR/literals.rs:34:18
    |
 LL |     let fail19 = 12_3456_21;
    |                  ^^^^^^^^^^ help: consider: `12_345_621`
@@ -58,19 +110,19 @@ LL |     let fail19 = 12_3456_21;
    = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings`
 
 error: digits grouped inconsistently by underscores
-  --> $DIR/literals.rs:34:18
+  --> $DIR/literals.rs:35:18
    |
 LL |     let fail22 = 3__4___23;
    |                  ^^^^^^^^^ help: consider: `3_423`
 
 error: digits grouped inconsistently by underscores
-  --> $DIR/literals.rs:35:18
+  --> $DIR/literals.rs:36:18
    |
 LL |     let fail23 = 3__16___23;
    |                  ^^^^^^^^^^ help: consider: `31_623`
 
 error: digits of hex or binary literal not grouped by four
-  --> $DIR/literals.rs:37:18
+  --> $DIR/literals.rs:38:18
    |
 LL |     let fail24 = 0xAB_ABC_AB;
    |                  ^^^^^^^^^^^ help: consider: `0x0ABA_BCAB`
@@ -78,10 +130,10 @@ LL |     let fail24 = 0xAB_ABC_AB;
    = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
 
 error: digits of hex or binary literal not grouped by four
-  --> $DIR/literals.rs:38:18
+  --> $DIR/literals.rs:39:18
    |
 LL |     let fail25 = 0b01_100_101;
    |                  ^^^^^^^^^^^^ help: consider: `0b0110_0101`
 
-error: aborting due to 10 previous errors
+error: aborting due to 18 previous errors
 
index 70d49d9f2c4ae1edd8497e9133f3598369431148..9171558f3a2d74d1f79d2c9b62d6a3282db33b82 100644 (file)
@@ -1,4 +1,3 @@
-// compile-flags: --edition 2018
 // aux-build:macro_rules.rs
 // aux-build:macro_use_helper.rs
 // aux-build:proc_macro_derive.rs
index 68370023861145dc15a29d4a6696138e06910d05..cd01fd43f6d325eefb79e07d1bc71753ef1a164c 100644 (file)
@@ -1,4 +1,3 @@
-// compile-flags: --edition 2018
 // aux-build:macro_rules.rs
 // aux-build:macro_use_helper.rs
 // aux-build:proc_macro_derive.rs
index 49314b7506d336187642b16deee4aad13d34f342..f8c86c8d9179f8af918b684eb9294c18ea4a7008 100644 (file)
@@ -1,5 +1,5 @@
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:19:5
+  --> $DIR/macro_use_imports.rs:18:5
    |
 LL |     #[macro_use]
    |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};`
@@ -7,22 +7,22 @@ LL |     #[macro_use]
    = note: `-D clippy::macro-use-imports` implied by `-D warnings`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:25:5
+  --> $DIR/macro_use_imports.rs:20:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:21:5
+  --> $DIR/macro_use_imports.rs:22:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:23:5
+  --> $DIR/macro_use_imports.rs:24:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
new file mode 100644 (file)
index 0000000..11fe06c
--- /dev/null
@@ -0,0 +1,43 @@
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
+// run-rustfix
+#![warn(clippy::manual_assert)]
+
+fn main() {
+    let a = vec![1, 2, 3];
+    let c = Some(2);
+    if !a.is_empty()
+        && a.len() == 3
+        && c != None
+        && !a.is_empty()
+        && a.len() == 3
+        && !a.is_empty()
+        && a.len() == 3
+        && !a.is_empty()
+        && a.len() == 3
+    {
+        panic!("qaqaq{:?}", a);
+    }
+    assert!(a.is_empty(), "qaqaq{:?}", a);
+    assert!(a.is_empty(), "qwqwq");
+    if a.len() == 3 {
+        println!("qwq");
+        println!("qwq");
+        println!("qwq");
+    }
+    if let Some(b) = c {
+        panic!("orz {}", b);
+    }
+    if a.len() == 3 {
+        panic!("qaqaq");
+    } else {
+        println!("qwq");
+    }
+    let b = vec![1, 2, 3];
+    assert!(!b.is_empty(), "panic1");
+    assert!(!(b.is_empty() && a.is_empty()), "panic2");
+    assert!(!(a.is_empty() && !b.is_empty()), "panic3");
+    assert!(!(b.is_empty() || a.is_empty()), "panic4");
+    assert!(!(a.is_empty() || !b.is_empty()), "panic5");
+}
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
new file mode 100644 (file)
index 0000000..03c0347
--- /dev/null
@@ -0,0 +1,60 @@
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:22:5
+   |
+LL | /     if !a.is_empty() {
+LL | |         panic!("qaqaq{:?}", a);
+LL | |     }
+   | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
+   |
+   = note: `-D clippy::manual-assert` implied by `-D warnings`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:25:5
+   |
+LL | /     if !a.is_empty() {
+LL | |         panic!("qwqwq");
+LL | |     }
+   | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:42:5
+   |
+LL | /     if b.is_empty() {
+LL | |         panic!("panic1");
+LL | |     }
+   | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:45:5
+   |
+LL | /     if b.is_empty() && a.is_empty() {
+LL | |         panic!("panic2");
+LL | |     }
+   | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:48:5
+   |
+LL | /     if a.is_empty() && !b.is_empty() {
+LL | |         panic!("panic3");
+LL | |     }
+   | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:51:5
+   |
+LL | /     if b.is_empty() || a.is_empty() {
+LL | |         panic!("panic4");
+LL | |     }
+   | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:54:5
+   |
+LL | /     if a.is_empty() || !b.is_empty() {
+LL | |         panic!("panic5");
+LL | |     }
+   | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
new file mode 100644 (file)
index 0000000..11fe06c
--- /dev/null
@@ -0,0 +1,43 @@
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
+// run-rustfix
+#![warn(clippy::manual_assert)]
+
+fn main() {
+    let a = vec![1, 2, 3];
+    let c = Some(2);
+    if !a.is_empty()
+        && a.len() == 3
+        && c != None
+        && !a.is_empty()
+        && a.len() == 3
+        && !a.is_empty()
+        && a.len() == 3
+        && !a.is_empty()
+        && a.len() == 3
+    {
+        panic!("qaqaq{:?}", a);
+    }
+    assert!(a.is_empty(), "qaqaq{:?}", a);
+    assert!(a.is_empty(), "qwqwq");
+    if a.len() == 3 {
+        println!("qwq");
+        println!("qwq");
+        println!("qwq");
+    }
+    if let Some(b) = c {
+        panic!("orz {}", b);
+    }
+    if a.len() == 3 {
+        panic!("qaqaq");
+    } else {
+        println!("qwq");
+    }
+    let b = vec![1, 2, 3];
+    assert!(!b.is_empty(), "panic1");
+    assert!(!(b.is_empty() && a.is_empty()), "panic2");
+    assert!(!(a.is_empty() && !b.is_empty()), "panic3");
+    assert!(!(b.is_empty() || a.is_empty()), "panic4");
+    assert!(!(a.is_empty() || !b.is_empty()), "panic5");
+}
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
new file mode 100644 (file)
index 0000000..03c0347
--- /dev/null
@@ -0,0 +1,60 @@
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:22:5
+   |
+LL | /     if !a.is_empty() {
+LL | |         panic!("qaqaq{:?}", a);
+LL | |     }
+   | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
+   |
+   = note: `-D clippy::manual-assert` implied by `-D warnings`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:25:5
+   |
+LL | /     if !a.is_empty() {
+LL | |         panic!("qwqwq");
+LL | |     }
+   | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:42:5
+   |
+LL | /     if b.is_empty() {
+LL | |         panic!("panic1");
+LL | |     }
+   | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:45:5
+   |
+LL | /     if b.is_empty() && a.is_empty() {
+LL | |         panic!("panic2");
+LL | |     }
+   | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:48:5
+   |
+LL | /     if a.is_empty() && !b.is_empty() {
+LL | |         panic!("panic3");
+LL | |     }
+   | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:51:5
+   |
+LL | /     if b.is_empty() || a.is_empty() {
+LL | |         panic!("panic4");
+LL | |     }
+   | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:54:5
+   |
+LL | /     if a.is_empty() || !b.is_empty() {
+LL | |         panic!("panic5");
+LL | |     }
+   | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_assert.fixed b/src/tools/clippy/tests/ui/manual_assert.fixed
new file mode 100644 (file)
index 0000000..11fe06c
--- /dev/null
@@ -0,0 +1,43 @@
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
+// run-rustfix
+#![warn(clippy::manual_assert)]
+
+fn main() {
+    let a = vec![1, 2, 3];
+    let c = Some(2);
+    if !a.is_empty()
+        && a.len() == 3
+        && c != None
+        && !a.is_empty()
+        && a.len() == 3
+        && !a.is_empty()
+        && a.len() == 3
+        && !a.is_empty()
+        && a.len() == 3
+    {
+        panic!("qaqaq{:?}", a);
+    }
+    assert!(a.is_empty(), "qaqaq{:?}", a);
+    assert!(a.is_empty(), "qwqwq");
+    if a.len() == 3 {
+        println!("qwq");
+        println!("qwq");
+        println!("qwq");
+    }
+    if let Some(b) = c {
+        panic!("orz {}", b);
+    }
+    if a.len() == 3 {
+        panic!("qaqaq");
+    } else {
+        println!("qwq");
+    }
+    let b = vec![1, 2, 3];
+    assert!(!b.is_empty(), "panic1");
+    assert!(!(b.is_empty() && a.is_empty()), "panic2");
+    assert!(!(a.is_empty() && !b.is_empty()), "panic3");
+    assert!(!(b.is_empty() || a.is_empty()), "panic4");
+    assert!(!(a.is_empty() || !b.is_empty()), "panic5");
+}
diff --git a/src/tools/clippy/tests/ui/manual_assert.rs b/src/tools/clippy/tests/ui/manual_assert.rs
new file mode 100644 (file)
index 0000000..8713426
--- /dev/null
@@ -0,0 +1,57 @@
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
+// run-rustfix
+#![warn(clippy::manual_assert)]
+
+fn main() {
+    let a = vec![1, 2, 3];
+    let c = Some(2);
+    if !a.is_empty()
+        && a.len() == 3
+        && c != None
+        && !a.is_empty()
+        && a.len() == 3
+        && !a.is_empty()
+        && a.len() == 3
+        && !a.is_empty()
+        && a.len() == 3
+    {
+        panic!("qaqaq{:?}", a);
+    }
+    if !a.is_empty() {
+        panic!("qaqaq{:?}", a);
+    }
+    if !a.is_empty() {
+        panic!("qwqwq");
+    }
+    if a.len() == 3 {
+        println!("qwq");
+        println!("qwq");
+        println!("qwq");
+    }
+    if let Some(b) = c {
+        panic!("orz {}", b);
+    }
+    if a.len() == 3 {
+        panic!("qaqaq");
+    } else {
+        println!("qwq");
+    }
+    let b = vec![1, 2, 3];
+    if b.is_empty() {
+        panic!("panic1");
+    }
+    if b.is_empty() && a.is_empty() {
+        panic!("panic2");
+    }
+    if a.is_empty() && !b.is_empty() {
+        panic!("panic3");
+    }
+    if b.is_empty() || a.is_empty() {
+        panic!("panic4");
+    }
+    if a.is_empty() || !b.is_empty() {
+        panic!("panic5");
+    }
+}
index 5184f6fdb88b3991850aead57bf02ea0a75b46cf..136cc96be70cafa57951fc7edd89c784892803b1 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-// edition:2018
 #![warn(clippy::manual_async_fn)]
 #![allow(unused)]
 
index 68c0e591f0b6eed6b4ffd5eeb1b8bd0fde47bae1..ddc453ffdb7500958c5e26cbf62a65a4859640f7 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-// edition:2018
 #![warn(clippy::manual_async_fn)]
 #![allow(unused)]
 
index 51f1a52b6dd65154d3b50d0a56bedfb8d24c37c9..7435f46074c8167287b383f5cee7f67c3e5afb0f 100644 (file)
@@ -1,5 +1,5 @@
 error: this function can be simplified using the `async fn` syntax
-  --> $DIR/manual_async_fn.rs:8:1
+  --> $DIR/manual_async_fn.rs:7:1
    |
 LL | fn fut() -> impl Future<Output = i32> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | fn fut() -> impl Future<Output = i32> { 42 }
    |                                       ~~~~~~
 
 error: this function can be simplified using the `async fn` syntax
-  --> $DIR/manual_async_fn.rs:13:1
+  --> $DIR/manual_async_fn.rs:12:1
    |
 LL | fn fut2() ->impl Future<Output = i32> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -30,7 +30,7 @@ LL | fn fut2() ->impl Future<Output = i32> { 42 }
    |                                       ~~~~~~
 
 error: this function can be simplified using the `async fn` syntax
-  --> $DIR/manual_async_fn.rs:18:1
+  --> $DIR/manual_async_fn.rs:17:1
    |
 LL | fn fut3()-> impl Future<Output = i32> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL | fn fut3()-> impl Future<Output = i32> { 42 }
    |                                       ~~~~~~
 
 error: this function can be simplified using the `async fn` syntax
-  --> $DIR/manual_async_fn.rs:22:1
+  --> $DIR/manual_async_fn.rs:21:1
    |
 LL | fn empty_fut() -> impl Future<Output = ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL | fn empty_fut() -> impl Future<Output = ()> {}
    |                                            ~~
 
 error: this function can be simplified using the `async fn` syntax
-  --> $DIR/manual_async_fn.rs:27:1
+  --> $DIR/manual_async_fn.rs:26:1
    |
 LL | fn empty_fut2() ->impl Future<Output = ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -75,7 +75,7 @@ LL | fn empty_fut2() ->impl Future<Output = ()> {}
    |                                            ~~
 
 error: this function can be simplified using the `async fn` syntax
-  --> $DIR/manual_async_fn.rs:32:1
+  --> $DIR/manual_async_fn.rs:31:1
    |
 LL | fn empty_fut3()-> impl Future<Output = ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL | fn empty_fut3()-> impl Future<Output = ()> {}
    |                                            ~~
 
 error: this function can be simplified using the `async fn` syntax
-  --> $DIR/manual_async_fn.rs:36:1
+  --> $DIR/manual_async_fn.rs:35:1
    |
 LL | fn core_fut() -> impl core::future::Future<Output = i32> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -105,7 +105,7 @@ LL | fn core_fut() -> impl core::future::Future<Output = i32> { 42 }
    |                                                          ~~~~~~
 
 error: this function can be simplified using the `async fn` syntax
-  --> $DIR/manual_async_fn.rs:58:5
+  --> $DIR/manual_async_fn.rs:57:5
    |
 LL |     fn inh_fut() -> impl Future<Output = i32> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -125,7 +125,7 @@ LL +             let c = 21;
  ...
 
 error: this function can be simplified using the `async fn` syntax
-  --> $DIR/manual_async_fn.rs:93:1
+  --> $DIR/manual_async_fn.rs:92:1
    |
 LL | fn elided(_: &i32) -> impl Future<Output = i32> + '_ {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -140,7 +140,7 @@ LL | fn elided(_: &i32) -> impl Future<Output = i32> + '_ { 42 }
    |                                                      ~~~~~~
 
 error: this function can be simplified using the `async fn` syntax
-  --> $DIR/manual_async_fn.rs:102:1
+  --> $DIR/manual_async_fn.rs:101:1
    |
 LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 40d01df6379a696496028454027d8acaba84f1c8..294d79abc0459fe481a9125f07b1fd8faf67ac69 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 // run-rustfix
 
 #![warn(clippy::manual_map)]
index cfef0c5cc4ec66207834005b7b151d666737c0fa..d11bf5ecb825ae28a1ae76ba6f1594199e37dfc8 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 // run-rustfix
 
 #![warn(clippy::manual_map)]
index cdc2c0e62a9b9434838946240bbbc1f44e3a7f5c..0036b8151ded0514259d03687784e3597716b977 100644 (file)
@@ -1,5 +1,5 @@
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:15:5
+  --> $DIR/manual_map_option.rs:14:5
    |
 LL | /     match Some(0) {
 LL | |         Some(_) => Some(2),
@@ -10,7 +10,7 @@ LL | |     };
    = note: `-D clippy::manual-map` implied by `-D warnings`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:20:5
+  --> $DIR/manual_map_option.rs:19:5
    |
 LL | /     match Some(0) {
 LL | |         Some(x) => Some(x + 1),
@@ -19,7 +19,7 @@ LL | |     };
    | |_____^ help: try this: `Some(0).map(|x| x + 1)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:25:5
+  --> $DIR/manual_map_option.rs:24:5
    |
 LL | /     match Some("") {
 LL | |         Some(x) => Some(x.is_empty()),
@@ -28,7 +28,7 @@ LL | |     };
    | |_____^ help: try this: `Some("").map(|x| x.is_empty())`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:30:5
+  --> $DIR/manual_map_option.rs:29:5
    |
 LL | /     if let Some(x) = Some(0) {
 LL | |         Some(!x)
@@ -38,7 +38,7 @@ LL | |     };
    | |_____^ help: try this: `Some(0).map(|x| !x)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:37:5
+  --> $DIR/manual_map_option.rs:36:5
    |
 LL | /     match Some(0) {
 LL | |         Some(x) => { Some(std::convert::identity(x)) }
@@ -47,7 +47,7 @@ LL | |     };
    | |_____^ help: try this: `Some(0).map(std::convert::identity)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:42:5
+  --> $DIR/manual_map_option.rs:41:5
    |
 LL | /     match Some(&String::new()) {
 LL | |         Some(x) => Some(str::len(x)),
@@ -56,7 +56,7 @@ LL | |     };
    | |_____^ help: try this: `Some(&String::new()).map(|x| str::len(x))`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:52:5
+  --> $DIR/manual_map_option.rs:51:5
    |
 LL | /     match &Some([0, 1]) {
 LL | |         Some(x) => Some(x[0]),
@@ -65,7 +65,7 @@ LL | |     };
    | |_____^ help: try this: `Some([0, 1]).as_ref().map(|x| x[0])`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:57:5
+  --> $DIR/manual_map_option.rs:56:5
    |
 LL | /     match &Some(0) {
 LL | |         &Some(x) => Some(x * 2),
@@ -74,7 +74,7 @@ LL | |     };
    | |_____^ help: try this: `Some(0).map(|x| x * 2)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:62:5
+  --> $DIR/manual_map_option.rs:61:5
    |
 LL | /     match Some(String::new()) {
 LL | |         Some(ref x) => Some(x.is_empty()),
@@ -83,7 +83,7 @@ LL | |     };
    | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:67:5
+  --> $DIR/manual_map_option.rs:66:5
    |
 LL | /     match &&Some(String::new()) {
 LL | |         Some(x) => Some(x.len()),
@@ -92,7 +92,7 @@ LL | |     };
    | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:72:5
+  --> $DIR/manual_map_option.rs:71:5
    |
 LL | /     match &&Some(0) {
 LL | |         &&Some(x) => Some(x + x),
@@ -101,7 +101,7 @@ LL | |     };
    | |_____^ help: try this: `Some(0).map(|x| x + x)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:85:9
+  --> $DIR/manual_map_option.rs:84:9
    |
 LL | /         match &mut Some(String::new()) {
 LL | |             Some(x) => Some(x.push_str("")),
@@ -110,7 +110,7 @@ LL | |         };
    | |_________^ help: try this: `Some(String::new()).as_mut().map(|x| x.push_str(""))`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:91:5
+  --> $DIR/manual_map_option.rs:90:5
    |
 LL | /     match &mut Some(String::new()) {
 LL | |         Some(ref x) => Some(x.len()),
@@ -119,7 +119,7 @@ LL | |     };
    | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:96:5
+  --> $DIR/manual_map_option.rs:95:5
    |
 LL | /     match &mut &Some(String::new()) {
 LL | |         Some(x) => Some(x.is_empty()),
@@ -128,7 +128,7 @@ LL | |     };
    | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:101:5
+  --> $DIR/manual_map_option.rs:100:5
    |
 LL | /     match Some((0, 1, 2)) {
 LL | |         Some((x, y, z)) => Some(x + y + z),
@@ -137,7 +137,7 @@ LL | |     };
    | |_____^ help: try this: `Some((0, 1, 2)).map(|(x, y, z)| x + y + z)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:106:5
+  --> $DIR/manual_map_option.rs:105:5
    |
 LL | /     match Some([1, 2, 3]) {
 LL | |         Some([first, ..]) => Some(first),
@@ -146,7 +146,7 @@ LL | |     };
    | |_____^ help: try this: `Some([1, 2, 3]).map(|[first, ..]| first)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:111:5
+  --> $DIR/manual_map_option.rs:110:5
    |
 LL | /     match &Some((String::new(), "test")) {
 LL | |         Some((x, y)) => Some((y, x)),
@@ -155,7 +155,7 @@ LL | |     };
    | |_____^ help: try this: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:169:5
+  --> $DIR/manual_map_option.rs:168:5
    |
 LL | /     match Some(0) {
 LL | |         Some(x) => Some(vec![x]),
@@ -164,7 +164,7 @@ LL | |     };
    | |_____^ help: try this: `Some(0).map(|x| vec![x])`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:174:5
+  --> $DIR/manual_map_option.rs:173:5
    |
 LL | /     match option_env!("") {
 LL | |         Some(x) => Some(String::from(x)),
@@ -173,7 +173,7 @@ LL | |     };
    | |_____^ help: try this: `option_env!("").map(String::from)`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:194:12
+  --> $DIR/manual_map_option.rs:193:12
    |
 LL |       } else if let Some(x) = Some(0) {
    |  ____________^
@@ -184,7 +184,7 @@ LL | |     };
    | |_____^ help: try this: `{ Some(0).map(|x| x + 1) }`
 
 error: manual implementation of `Option::map`
-  --> $DIR/manual_map_option.rs:202:12
+  --> $DIR/manual_map_option.rs:201:12
    |
 LL |       } else if let Some(x) = Some(0) {
    |  ____________^
index 3717f962745fb4da9a0e3097731343000be21a8b..05d6c56f2aca0a5dd63a3d635468800d0431a5e3 100644 (file)
@@ -74,10 +74,10 @@ fn result_unwrap_or() {
     let a = Ok::<i32, &str>(1);
     a.unwrap_or(42);
 
-    // int case, suggestion must surround Result expr with parenthesis
+    // int case, suggestion must surround Result expr with parentheses
     (Ok(1) as Result<i32, &str>).unwrap_or(42);
 
-    // method call case, suggestion must not surround Result expr `s.method()` with parenthesis
+    // method call case, suggestion must not surround Result expr `s.method()` with parentheses
     struct S {}
     impl S {
         fn method(self) -> Option<i32> {
index 989adde1f5bbb7518e8c41a22e24df5fa0cbe82b..09f62c69b71de15b832c836a03c21829a78d501f 100644 (file)
@@ -95,13 +95,13 @@ fn result_unwrap_or() {
         Err(_) => 42,
     };
 
-    // int case, suggestion must surround Result expr with parenthesis
+    // int case, suggestion must surround Result expr with parentheses
     match Ok(1) as Result<i32, &str> {
         Ok(i) => i,
         Err(_) => 42,
     };
 
-    // method call case, suggestion must not surround Result expr `s.method()` with parenthesis
+    // method call case, suggestion must not surround Result expr `s.method()` with parentheses
     struct S {}
     impl S {
         fn method(self) -> Option<i32> {
index 366ef36c367bfb3f031f42968dc77f170c3c1ec5..d7cedf9f9f1596dfabb659099e2922281b410f93 100644 (file)
@@ -110,23 +110,6 @@ LL | |             _ => false,
 LL | |         };
    | |_________^ help: try this: `matches!(&val, &Some(ref _a))`
 
-error: you don't need to add `&` to both the expression and the patterns
-  --> $DIR/match_expr_like_matches_macro.rs:166:20
-   |
-LL |           let _res = match &val {
-   |  ____________________^
-LL | |             &Some(ref _a) => true,
-LL | |             _ => false,
-LL | |         };
-   | |_________^
-   |
-   = note: `-D clippy::match-ref-pats` implied by `-D warnings`
-help: try
-   |
-LL ~         let _res = match val {
-LL ~             Some(ref _a) => true,
-   |
-
 error: match expression looks like `matches!` macro
   --> $DIR/match_expr_like_matches_macro.rs:178:20
    |
@@ -137,21 +120,5 @@ LL | |             _ => false,
 LL | |         };
    | |_________^ help: try this: `matches!(&val, &Some(ref _a))`
 
-error: you don't need to add `&` to both the expression and the patterns
-  --> $DIR/match_expr_like_matches_macro.rs:178:20
-   |
-LL |           let _res = match &val {
-   |  ____________________^
-LL | |             &Some(ref _a) => true,
-LL | |             _ => false,
-LL | |         };
-   | |_________^
-   |
-help: try
-   |
-LL ~         let _res = match val {
-LL ~             Some(ref _a) => true,
-   |
-
-error: aborting due to 14 previous errors
+error: aborting due to 12 previous errors
 
index 846d665d1d864d86dd9396dc23a379271252cb8e..845986a4eadabeee40414a90d26162cbb4ba5007 100644 (file)
@@ -10,98 +10,102 @@ fn overlapping() {
     const FOO: u64 = 2;
 
     match 42 {
-        0..=10 => println!("0 ... 10"),
-        0..=11 => println!("0 ... 11"),
+        0..=10 => println!("0..=10"),
+        0..=11 => println!("0..=11"),
         _ => (),
     }
 
     match 42 {
-        0..=5 => println!("0 ... 5"),
-        6..=7 => println!("6 ... 7"),
-        FOO..=11 => println!("0 ... 11"),
+        0..=5 => println!("0..=5"),
+        6..=7 => println!("6..=7"),
+        FOO..=11 => println!("FOO..=11"),
         _ => (),
     }
 
     match 42 {
         2 => println!("2"),
-        0..=5 => println!("0 ... 5"),
+        0..=5 => println!("0..=5"),
         _ => (),
     }
 
     match 42 {
         2 => println!("2"),
-        0..=2 => println!("0 ... 2"),
+        0..=2 => println!("0..=2"),
         _ => (),
     }
 
     match 42 {
-        0..=10 => println!("0 ... 10"),
-        11..=50 => println!("11 ... 50"),
+        0..=10 => println!("0..=10"),
+        11..=50 => println!("11..=50"),
         _ => (),
     }
 
     match 42 {
         2 => println!("2"),
-        0..2 => println!("0 .. 2"),
+        0..2 => println!("0..2"),
         _ => (),
     }
 
     match 42 {
-        0..10 => println!("0 .. 10"),
-        10..50 => println!("10 .. 50"),
+        0..10 => println!("0..10"),
+        10..50 => println!("10..50"),
         _ => (),
     }
 
     match 42 {
-        0..11 => println!("0 .. 11"),
-        0..=11 => println!("0 ... 11"),
+        0..11 => println!("0..11"),
+        0..=11 => println!("0..=11"),
         _ => (),
     }
 
     match 42 {
-        5..7 => println!("5 .. 7"),
-        0..10 => println!("0 .. 10"),
+        5..7 => println!("5..7"),
+        0..10 => println!("0..10"),
         _ => (),
     }
 
     match 42 {
-        5..10 => println!("5 .. 10"),
-        0..=10 => println!("0 ... 10"),
+        5..10 => println!("5..10"),
+        0..=10 => println!("0..=10"),
         _ => (),
     }
 
     match 42 {
-        0..14 => println!("0 .. 14"),
-        5..10 => println!("5 .. 10"),
+        0..14 => println!("0..14"),
+        5..10 => println!("5..10"),
         _ => (),
     }
 
     match 42 {
-        5..14 => println!("5 .. 14"),
-        0..=10 => println!("0 ... 10"),
+        5..14 => println!("5..14"),
+        0..=10 => println!("0..=10"),
         _ => (),
     }
 
     match 42 {
-        0..7 => println!("0 .. 7"),
-        0..=10 => println!("0 ... 10"),
+        0..7 => println!("0..7"),
+        0..=10 => println!("0..=10"),
         _ => (),
     }
 
-    /*
-    // FIXME(JohnTitor): uncomment this once rustfmt knows half-open patterns
     match 42 {
-        0.. => println!("0 .. 42"),
-        3.. => println!("3 .. 42"),
+        3.. => println!("3.."),
+        0.. => println!("0.."),
         _ => (),
     }
 
     match 42 {
-        ..=23 => println!("0 ... 23"),
-        ..26 => println!("0 .. 26"),
+        ..=23 => println!("..=23"),
+        ..26 => println!("..26"),
+        _ => (),
+    }
+
+    // Issue #7829
+    match 0 {
+        -1..=1 => (),
+        -2..=2 => (),
         _ => (),
     }
-    */
 
     if let None = Some(42) {
         // nothing
index 359fa49f51be73735e65231454cc6bda7fbbbe89..c2b3f173c2b80bc7102261d8db7d7862e643d875 100644 (file)
@@ -1,63 +1,75 @@
 error: some ranges overlap
   --> $DIR/match_overlapping_arm.rs:13:9
    |
-LL |         0..=10 => println!("0 ... 10"),
+LL |         0..=10 => println!("0..=10"),
    |         ^^^^^^
    |
    = note: `-D clippy::match-overlapping-arm` implied by `-D warnings`
 note: overlaps with this
   --> $DIR/match_overlapping_arm.rs:14:9
    |
-LL |         0..=11 => println!("0 ... 11"),
+LL |         0..=11 => println!("0..=11"),
    |         ^^^^^^
 
 error: some ranges overlap
   --> $DIR/match_overlapping_arm.rs:19:9
    |
-LL |         0..=5 => println!("0 ... 5"),
+LL |         0..=5 => println!("0..=5"),
    |         ^^^^^
    |
 note: overlaps with this
   --> $DIR/match_overlapping_arm.rs:21:9
    |
-LL |         FOO..=11 => println!("0 ... 11"),
+LL |         FOO..=11 => println!("FOO..=11"),
    |         ^^^^^^^^
 
 error: some ranges overlap
   --> $DIR/match_overlapping_arm.rs:56:9
    |
-LL |         0..11 => println!("0 .. 11"),
+LL |         0..11 => println!("0..11"),
    |         ^^^^^
    |
 note: overlaps with this
   --> $DIR/match_overlapping_arm.rs:57:9
    |
-LL |         0..=11 => println!("0 ... 11"),
+LL |         0..=11 => println!("0..=11"),
    |         ^^^^^^
 
 error: some ranges overlap
   --> $DIR/match_overlapping_arm.rs:81:9
    |
-LL |         0..=10 => println!("0 ... 10"),
+LL |         0..=10 => println!("0..=10"),
    |         ^^^^^^
    |
 note: overlaps with this
   --> $DIR/match_overlapping_arm.rs:80:9
    |
-LL |         5..14 => println!("5 .. 14"),
+LL |         5..14 => println!("5..14"),
    |         ^^^^^
 
 error: some ranges overlap
   --> $DIR/match_overlapping_arm.rs:86:9
    |
-LL |         0..7 => println!("0 .. 7"),
+LL |         0..7 => println!("0..7"),
    |         ^^^^
    |
 note: overlaps with this
   --> $DIR/match_overlapping_arm.rs:87:9
    |
-LL |         0..=10 => println!("0 ... 10"),
+LL |         0..=10 => println!("0..=10"),
    |         ^^^^^^
 
-error: aborting due to 5 previous errors
+error: some ranges overlap
+  --> $DIR/match_overlapping_arm.rs:98:9
+   |
+LL |         ..=23 => println!("..=23"),
+   |         ^^^^^
+   |
+note: overlaps with this
+  --> $DIR/match_overlapping_arm.rs:99:9
+   |
+LL |         ..26 => println!("..26"),
+   |         ^^^^
+
+error: aborting due to 6 previous errors
 
index 6cbb4d32b0d71287c8e35a8e648d9436cbb0aef5..7e3674ab8c9f2c633094cce82c11d3351ebb8cb8 100644 (file)
@@ -1,5 +1,5 @@
 #![warn(clippy::match_ref_pats)]
-#![allow(clippy::equatable_if_let)]
+#![allow(clippy::equatable_if_let, clippy::enum_variant_names)]
 
 fn ref_pats() {
     {
@@ -72,4 +72,46 @@ fn ice_3719() {
     }
 }
 
+mod issue_7740 {
+    macro_rules! foobar_variant(
+        ($idx:expr) => (FooBar::get($idx).unwrap())
+    );
+
+    enum FooBar {
+        Foo,
+        Bar,
+        FooBar,
+        BarFoo,
+    }
+
+    impl FooBar {
+        fn get(idx: u8) -> Option<&'static Self> {
+            match idx {
+                0 => Some(&FooBar::Foo),
+                1 => Some(&FooBar::Bar),
+                2 => Some(&FooBar::FooBar),
+                3 => Some(&FooBar::BarFoo),
+                _ => None,
+            }
+        }
+    }
+
+    fn issue_7740() {
+        // Issue #7740
+        match foobar_variant!(0) {
+            &FooBar::Foo => println!("Foo"),
+            &FooBar::Bar => println!("Bar"),
+            &FooBar::FooBar => println!("FooBar"),
+            _ => println!("Wild"),
+        }
+
+        // This shouldn't trigger
+        if let &FooBar::BarFoo = foobar_variant!(3) {
+            println!("BarFoo");
+        } else {
+            println!("Wild");
+        }
+    }
+}
+
 fn main() {}
index 072aff445e97f2b330a4fdc56e58bff33fa5a1b1..901820077e20e974b651c9a68ef26df9b364cf59 100644 (file)
@@ -15,21 +15,6 @@ LL ~             Some(v) => println!("{:?}", v),
 LL ~             None => println!("none"),
    |
 
-error: you don't need to add `&` to all patterns
-  --> $DIR/match_ref_pats.rs:18:5
-   |
-LL | /     match tup {
-LL | |         &(v, 1) => println!("{}", v),
-LL | |         _ => println!("none"),
-LL | |     }
-   | |_____^
-   |
-help: instead of prefixing all patterns with `&`, you can dereference the expression
-   |
-LL ~     match *tup {
-LL ~         (v, 1) => println!("{}", v),
-   |
-
 error: you don't need to add `&` to both the expression and the patterns
   --> $DIR/match_ref_pats.rs:24:5
    |
@@ -54,52 +39,30 @@ LL |     if let &None = a {
    |
    = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
-error: you don't need to add `&` to all patterns
-  --> $DIR/match_ref_pats.rs:36:5
-   |
-LL | /     if let &None = a {
-LL | |         println!("none");
-LL | |     }
-   | |_____^
-   |
-help: instead of prefixing all patterns with `&`, you can dereference the expression
-   |
-LL |     if let None = *a {
-   |            ~~~~   ~~
-
 error: redundant pattern matching, consider using `is_none()`
   --> $DIR/match_ref_pats.rs:41:12
    |
 LL |     if let &None = &b {
    |     -------^^^^^----- help: try this: `if b.is_none()`
 
-error: you don't need to add `&` to both the expression and the patterns
-  --> $DIR/match_ref_pats.rs:41:5
-   |
-LL | /     if let &None = &b {
-LL | |         println!("none");
-LL | |     }
-   | |_____^
-   |
-help: try
-   |
-LL |     if let None = b {
-   |            ~~~~   ~
-
 error: you don't need to add `&` to all patterns
-  --> $DIR/match_ref_pats.rs:68:9
+  --> $DIR/match_ref_pats.rs:101:9
    |
-LL | /         match foo_variant!(0) {
-LL | |             &Foo::A => println!("A"),
+LL | /         match foobar_variant!(0) {
+LL | |             &FooBar::Foo => println!("Foo"),
+LL | |             &FooBar::Bar => println!("Bar"),
+LL | |             &FooBar::FooBar => println!("FooBar"),
 LL | |             _ => println!("Wild"),
 LL | |         }
    | |_________^
    |
 help: instead of prefixing all patterns with `&`, you can dereference the expression
    |
-LL ~         match *foo_variant!(0) {
-LL ~             Foo::A => println!("A"),
+LL ~         match *foobar_variant!(0) {
+LL ~             FooBar::Foo => println!("Foo"),
+LL ~             FooBar::Bar => println!("Bar"),
+LL ~             FooBar::FooBar => println!("FooBar"),
    |
 
-error: aborting due to 8 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_str_case_mismatch.rs b/src/tools/clippy/tests/ui/match_str_case_mismatch.rs
new file mode 100644 (file)
index 0000000..ac555c8
--- /dev/null
@@ -0,0 +1,184 @@
+#![warn(clippy::match_str_case_mismatch)]
+
+// Valid
+
+fn as_str_match() {
+    let var = "BAR";
+
+    match var.to_ascii_lowercase().as_str() {
+        "foo" => {},
+        "bar" => {},
+        _ => {},
+    }
+}
+
+fn non_alphabetic() {
+    let var = "~!@#$%^&*()-_=+FOO";
+
+    match var.to_ascii_lowercase().as_str() {
+        "1234567890" => {},
+        "~!@#$%^&*()-_=+foo" => {},
+        "\n\r\t\x7F" => {},
+        _ => {},
+    }
+}
+
+fn unicode_cased() {
+    let var = "ВОДЫ";
+
+    match var.to_lowercase().as_str() {
+        "水" => {},
+        "νερό" => {},
+        "воды" => {},
+        "물" => {},
+        _ => {},
+    }
+}
+
+fn titlecase() {
+    let var = "BarDz";
+
+    match var.to_lowercase().as_str() {
+        "foolj" => {},
+        "bardz" => {},
+        _ => {},
+    }
+}
+
+fn no_case_equivalent() {
+    let var = "barʁ";
+
+    match var.to_uppercase().as_str() {
+        "FOOɕ" => {},
+        "BARʁ" => {},
+        _ => {},
+    }
+}
+
+fn addrof_unary_match() {
+    let var = "BAR";
+
+    match &*var.to_ascii_lowercase() {
+        "foo" => {},
+        "bar" => {},
+        _ => {},
+    }
+}
+
+fn alternating_chain() {
+    let var = "BAR";
+
+    match &*var
+        .to_ascii_lowercase()
+        .to_uppercase()
+        .to_lowercase()
+        .to_ascii_uppercase()
+    {
+        "FOO" => {},
+        "BAR" => {},
+        _ => {},
+    }
+}
+
+fn unrelated_method() {
+    struct Item {
+        a: String,
+    }
+
+    impl Item {
+        #[allow(clippy::wrong_self_convention)]
+        fn to_lowercase(self) -> String {
+            self.a
+        }
+    }
+
+    let item = Item { a: String::from("BAR") };
+
+    match &*item.to_lowercase() {
+        "FOO" => {},
+        "BAR" => {},
+        _ => {},
+    }
+}
+
+// Invalid
+
+fn as_str_match_mismatch() {
+    let var = "BAR";
+
+    match var.to_ascii_lowercase().as_str() {
+        "foo" => {},
+        "Bar" => {},
+        _ => {},
+    }
+}
+
+fn non_alphabetic_mismatch() {
+    let var = "~!@#$%^&*()-_=+FOO";
+
+    match var.to_ascii_lowercase().as_str() {
+        "1234567890" => {},
+        "~!@#$%^&*()-_=+Foo" => {},
+        "\n\r\t\x7F" => {},
+        _ => {},
+    }
+}
+
+fn unicode_cased_mismatch() {
+    let var = "ВОДЫ";
+
+    match var.to_lowercase().as_str() {
+        "水" => {},
+        "νερό" => {},
+        "Воды" => {},
+        "물" => {},
+        _ => {},
+    }
+}
+
+fn titlecase_mismatch() {
+    let var = "BarDz";
+
+    match var.to_lowercase().as_str() {
+        "foolj" => {},
+        "barDz" => {},
+        _ => {},
+    }
+}
+
+fn no_case_equivalent_mismatch() {
+    let var = "barʁ";
+
+    match var.to_uppercase().as_str() {
+        "FOOɕ" => {},
+        "bARʁ" => {},
+        _ => {},
+    }
+}
+
+fn addrof_unary_match_mismatch() {
+    let var = "BAR";
+
+    match &*var.to_ascii_lowercase() {
+        "foo" => {},
+        "Bar" => {},
+        _ => {},
+    }
+}
+
+fn alternating_chain_mismatch() {
+    let var = "BAR";
+
+    match &*var
+        .to_ascii_lowercase()
+        .to_uppercase()
+        .to_lowercase()
+        .to_ascii_uppercase()
+    {
+        "FOO" => {},
+        "bAR" => {},
+        _ => {},
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr
new file mode 100644 (file)
index 0000000..92baa40
--- /dev/null
@@ -0,0 +1,80 @@
+error: this `match` arm has a differing case than its expression
+  --> $DIR/match_str_case_mismatch.rs:111:9
+   |
+LL |         "Bar" => {},
+   |         ^^^^^
+   |
+   = note: `-D clippy::match-str-case-mismatch` implied by `-D warnings`
+help: consider changing the case of this arm to respect `to_ascii_lowercase`
+   |
+LL |         "bar" => {},
+   |         ~~~~~
+
+error: this `match` arm has a differing case than its expression
+  --> $DIR/match_str_case_mismatch.rs:121:9
+   |
+LL |         "~!@#$%^&*()-_=+Foo" => {},
+   |         ^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the case of this arm to respect `to_ascii_lowercase`
+   |
+LL |         "~!@#$%^&*()-_=+foo" => {},
+   |         ~~~~~~~~~~~~~~~~~~~~
+
+error: this `match` arm has a differing case than its expression
+  --> $DIR/match_str_case_mismatch.rs:133:9
+   |
+LL |         "Воды" => {},
+   |         ^^^^^^
+   |
+help: consider changing the case of this arm to respect `to_lowercase`
+   |
+LL |         "воды" => {},
+   |         ~~~~~~
+
+error: this `match` arm has a differing case than its expression
+  --> $DIR/match_str_case_mismatch.rs:144:9
+   |
+LL |         "barDz" => {},
+   |         ^^^^^^
+   |
+help: consider changing the case of this arm to respect `to_lowercase`
+   |
+LL |         "bardz" => {},
+   |         ~~~~~~
+
+error: this `match` arm has a differing case than its expression
+  --> $DIR/match_str_case_mismatch.rs:154:9
+   |
+LL |         "bARʁ" => {},
+   |         ^^^^^^
+   |
+help: consider changing the case of this arm to respect `to_uppercase`
+   |
+LL |         "BARʁ" => {},
+   |         ~~~~~~
+
+error: this `match` arm has a differing case than its expression
+  --> $DIR/match_str_case_mismatch.rs:164:9
+   |
+LL |         "Bar" => {},
+   |         ^^^^^
+   |
+help: consider changing the case of this arm to respect `to_ascii_lowercase`
+   |
+LL |         "bar" => {},
+   |         ~~~~~
+
+error: this `match` arm has a differing case than its expression
+  --> $DIR/match_str_case_mismatch.rs:179:9
+   |
+LL |         "bAR" => {},
+   |         ^^^^^
+   |
+help: consider changing the case of this arm to respect `to_ascii_uppercase`
+   |
+LL |         "BAR" => {},
+   |         ~~~~~
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.edition2018.stderr b/src/tools/clippy/tests/ui/match_wild_err_arm.edition2018.stderr
new file mode 100644 (file)
index 0000000..2a40120
--- /dev/null
@@ -0,0 +1,35 @@
+error: `Err(_)` matches all errors
+  --> $DIR/match_wild_err_arm.rs:14:9
+   |
+LL |         Err(_) => panic!("err"),
+   |         ^^^^^^
+   |
+   = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
+   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_)` matches all errors
+  --> $DIR/match_wild_err_arm.rs:20:9
+   |
+LL |         Err(_) => panic!(),
+   |         ^^^^^^
+   |
+   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_)` matches all errors
+  --> $DIR/match_wild_err_arm.rs:26:9
+   |
+LL |         Err(_) => {
+   |         ^^^^^^
+   |
+   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_e)` matches all errors
+  --> $DIR/match_wild_err_arm.rs:34:9
+   |
+LL |         Err(_e) => panic!(),
+   |         ^^^^^^^
+   |
+   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr b/src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr
new file mode 100644 (file)
index 0000000..2a40120
--- /dev/null
@@ -0,0 +1,35 @@
+error: `Err(_)` matches all errors
+  --> $DIR/match_wild_err_arm.rs:14:9
+   |
+LL |         Err(_) => panic!("err"),
+   |         ^^^^^^
+   |
+   = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
+   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_)` matches all errors
+  --> $DIR/match_wild_err_arm.rs:20:9
+   |
+LL |         Err(_) => panic!(),
+   |         ^^^^^^
+   |
+   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_)` matches all errors
+  --> $DIR/match_wild_err_arm.rs:26:9
+   |
+LL |         Err(_) => {
+   |         ^^^^^^
+   |
+   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_e)` matches all errors
+  --> $DIR/match_wild_err_arm.rs:34:9
+   |
+LL |         Err(_e) => panic!(),
+   |         ^^^^^^^
+   |
+   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: aborting due to 4 previous errors
+
index 823be65efe065703b8481ced833636d15b245373..0a86144b95d5bcc59b148e298783caa02d017217 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
 #![feature(exclusive_range_pattern)]
 #![allow(clippy::match_same_arms)]
 #![warn(clippy::match_wild_err_arm)]
diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.stderr b/src/tools/clippy/tests/ui/match_wild_err_arm.stderr
deleted file mode 100644 (file)
index 6a2a029..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-error: `Err(_)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:11:9
-   |
-LL |         Err(_) => panic!("err"),
-   |         ^^^^^^
-   |
-   = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
-
-error: `Err(_)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:17:9
-   |
-LL |         Err(_) => panic!(),
-   |         ^^^^^^
-   |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
-
-error: `Err(_)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:23:9
-   |
-LL |         Err(_) => {
-   |         ^^^^^^
-   |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
-
-error: `Err(_e)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:31:9
-   |
-LL |         Err(_e) => panic!(),
-   |         ^^^^^^^
-   |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
-
-error: aborting due to 4 previous errors
-
index c441b35b9920390c89edfc6ac504716cf25eae2f..977ce54327b3d984a4f61fca7c2967b734a3ce57 100644 (file)
@@ -1,5 +1,4 @@
 // aux-build:option_helpers.rs
-// edition:2018
 
 #![warn(clippy::all, clippy::pedantic)]
 #![allow(
index 4643e09e2702835ac9803b6050b49f1ba7267171..b63672dd6fdbb546dac805e74727f9bf8982851f 100644 (file)
@@ -1,5 +1,5 @@
 error: methods called `new` usually return `Self`
-  --> $DIR/methods.rs:105:5
+  --> $DIR/methods.rs:104:5
    |
 LL | /     fn new() -> i32 {
 LL | |         0
@@ -9,7 +9,7 @@ LL | |     }
    = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
 
 error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
-  --> $DIR/methods.rs:126:13
+  --> $DIR/methods.rs:125:13
    |
 LL |       let _ = v.iter().filter(|&x| {
    |  _____________^
index a9bf7140a1e594ae61cf64f9a000ee6716b669b3..148531c285d3d310ed9011992604cf8a5d4c4b43 100644 (file)
@@ -3,7 +3,6 @@
 // injected intrinsics by the compiler.
 #![allow(dead_code)]
 #![feature(global_asm)]
-
 //! Some garbage docs for the crate here
 #![doc = "More garbage"]
 
@@ -90,10 +89,10 @@ fn also_undocumented2() {}
 }
 /// dox
 pub mod public_interface {
-    pub use internal_impl::documented as foo;
-    pub use internal_impl::globbed::*;
-    pub use internal_impl::undocumented1 as bar;
-    pub use internal_impl::{documented, undocumented2};
+    pub use crate::internal_impl::documented as foo;
+    pub use crate::internal_impl::globbed::*;
+    pub use crate::internal_impl::undocumented1 as bar;
+    pub use crate::internal_impl::{documented, undocumented2};
 }
 
 fn main() {}
index a876dc078ebff96f25c8e34efad90156b896a70a..7a3a448c9d6c2730e407e220b73297e57e576119 100644 (file)
@@ -1,5 +1,5 @@
 error: missing documentation for a type alias
-  --> $DIR/missing-doc.rs:10:1
+  --> $DIR/missing-doc.rs:9:1
    |
 LL | type Typedef = String;
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -7,37 +7,37 @@ LL | type Typedef = String;
    = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
 
 error: missing documentation for a type alias
-  --> $DIR/missing-doc.rs:11:1
+  --> $DIR/missing-doc.rs:10:1
    |
 LL | pub type PubTypedef = String;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing-doc.rs:13:1
+  --> $DIR/missing-doc.rs:12:1
    |
 LL | mod module_no_dox {}
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing-doc.rs:14:1
+  --> $DIR/missing-doc.rs:13:1
    |
 LL | pub mod pub_module_no_dox {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:18:1
+  --> $DIR/missing-doc.rs:17:1
    |
 LL | pub fn foo2() {}
    | ^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:19:1
+  --> $DIR/missing-doc.rs:18:1
    |
 LL | fn foo3() {}
    | ^^^^^^^^^^^^
 
 error: missing documentation for an enum
-  --> $DIR/missing-doc.rs:33:1
+  --> $DIR/missing-doc.rs:32:1
    |
 LL | / enum Baz {
 LL | |     BazA { a: isize, b: isize },
@@ -46,31 +46,31 @@ LL | | }
    | |_^
 
 error: missing documentation for a variant
-  --> $DIR/missing-doc.rs:34:5
+  --> $DIR/missing-doc.rs:33:5
    |
 LL |     BazA { a: isize, b: isize },
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:34:12
+  --> $DIR/missing-doc.rs:33:12
    |
 LL |     BazA { a: isize, b: isize },
    |            ^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:34:22
+  --> $DIR/missing-doc.rs:33:22
    |
 LL |     BazA { a: isize, b: isize },
    |                      ^^^^^^^^
 
 error: missing documentation for a variant
-  --> $DIR/missing-doc.rs:35:5
+  --> $DIR/missing-doc.rs:34:5
    |
 LL |     BarB,
    |     ^^^^
 
 error: missing documentation for an enum
-  --> $DIR/missing-doc.rs:38:1
+  --> $DIR/missing-doc.rs:37:1
    |
 LL | / pub enum PubBaz {
 LL | |     PubBazA { a: isize },
@@ -78,43 +78,43 @@ LL | | }
    | |_^
 
 error: missing documentation for a variant
-  --> $DIR/missing-doc.rs:39:5
+  --> $DIR/missing-doc.rs:38:5
    |
 LL |     PubBazA { a: isize },
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:39:15
+  --> $DIR/missing-doc.rs:38:15
    |
 LL |     PubBazA { a: isize },
    |               ^^^^^^^^
 
 error: missing documentation for a constant
-  --> $DIR/missing-doc.rs:59:1
+  --> $DIR/missing-doc.rs:58:1
    |
 LL | const FOO: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a constant
-  --> $DIR/missing-doc.rs:66:1
+  --> $DIR/missing-doc.rs:65:1
    |
 LL | pub const FOO4: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-  --> $DIR/missing-doc.rs:68:1
+  --> $DIR/missing-doc.rs:67:1
    |
 LL | static BAR: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-  --> $DIR/missing-doc.rs:75:1
+  --> $DIR/missing-doc.rs:74:1
    |
 LL | pub static BAR4: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing-doc.rs:77:1
+  --> $DIR/missing-doc.rs:76:1
    |
 LL | / mod internal_impl {
 LL | |     /// dox
@@ -126,31 +126,31 @@ LL | | }
    | |_^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:80:5
+  --> $DIR/missing-doc.rs:79:5
    |
 LL |     pub fn undocumented1() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:81:5
+  --> $DIR/missing-doc.rs:80:5
    |
 LL |     pub fn undocumented2() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:82:5
+  --> $DIR/missing-doc.rs:81:5
    |
 LL |     fn undocumented3() {}
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:87:9
+  --> $DIR/missing-doc.rs:86:9
    |
 LL |         pub fn also_undocumented1() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:88:9
+  --> $DIR/missing-doc.rs:87:9
    |
 LL |         fn also_undocumented2() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
index 2e1379a58a67bbd2a32f1676fa684445e194cda9..7dc44529206d551a423dbfea3762038b3b610074 100644 (file)
@@ -1,6 +1,5 @@
 #![warn(clippy::missing_panics_doc)]
 #![allow(clippy::option_map_unit_fn)]
-
 fn main() {}
 
 /// This needs to be documented
index b863063b626dbe68183eda66c717ef6156b78881..60282939ef0334008f00c7d78ea12693c2b22595 100644 (file)
@@ -1,5 +1,5 @@
 error: docs for function which may panic missing `# Panics` section
-  --> $DIR/missing_panics_doc.rs:7:1
+  --> $DIR/missing_panics_doc.rs:6:1
    |
 LL | / pub fn unwrap() {
 LL | |     let result = Err("Hi");
@@ -9,13 +9,13 @@ LL | | }
    |
    = note: `-D clippy::missing-panics-doc` implied by `-D warnings`
 note: first possible panic found here
-  --> $DIR/missing_panics_doc.rs:9:5
+  --> $DIR/missing_panics_doc.rs:8:5
    |
 LL |     result.unwrap()
    |     ^^^^^^^^^^^^^^^
 
 error: docs for function which may panic missing `# Panics` section
-  --> $DIR/missing_panics_doc.rs:13:1
+  --> $DIR/missing_panics_doc.rs:12:1
    |
 LL | / pub fn panic() {
 LL | |     panic!("This function panics")
@@ -23,14 +23,14 @@ LL | | }
    | |_^
    |
 note: first possible panic found here
-  --> $DIR/missing_panics_doc.rs:14:5
+  --> $DIR/missing_panics_doc.rs:13:5
    |
 LL |     panic!("This function panics")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = 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:18:1
+  --> $DIR/missing_panics_doc.rs:17:1
    |
 LL | / pub fn todo() {
 LL | |     todo!()
@@ -38,14 +38,14 @@ LL | | }
    | |_^
    |
 note: first possible panic found here
-  --> $DIR/missing_panics_doc.rs:19:5
+  --> $DIR/missing_panics_doc.rs:18:5
    |
 LL |     todo!()
    |     ^^^^^^^
    = note: this error originates in the macro `$crate::panic::panic_2015` (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:23:1
+  --> $DIR/missing_panics_doc.rs:22:1
    |
 LL | / pub fn inner_body(opt: Option<u32>) {
 LL | |     opt.map(|x| {
@@ -57,14 +57,14 @@ LL | | }
    | |_^
    |
 note: first possible panic found here
-  --> $DIR/missing_panics_doc.rs:26:13
+  --> $DIR/missing_panics_doc.rs:25:13
    |
 LL |             panic!()
    |             ^^^^^^^^
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = 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:32:1
+  --> $DIR/missing_panics_doc.rs:31:1
    |
 LL | / pub fn unreachable_and_panic() {
 LL | |     if true { unreachable!() } else { panic!() }
@@ -72,14 +72,14 @@ LL | | }
    | |_^
    |
 note: first possible panic found here
-  --> $DIR/missing_panics_doc.rs:33:39
+  --> $DIR/missing_panics_doc.rs:32:39
    |
 LL |     if true { unreachable!() } else { panic!() }
    |                                       ^^^^^^^^
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = 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:37:1
+  --> $DIR/missing_panics_doc.rs:36:1
    |
 LL | / pub fn assert_eq() {
 LL | |     let x = 0;
@@ -88,14 +88,14 @@ LL | | }
    | |_^
    |
 note: first possible panic found here
-  --> $DIR/missing_panics_doc.rs:39:5
+  --> $DIR/missing_panics_doc.rs:38:5
    |
 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:43:1
+  --> $DIR/missing_panics_doc.rs:42:1
    |
 LL | / pub fn assert_ne() {
 LL | |     let x = 0;
@@ -104,7 +104,7 @@ LL | | }
    | |_^
    |
 note: first possible panic found here
-  --> $DIR/missing_panics_doc.rs:45:5
+  --> $DIR/missing_panics_doc.rs:44:5
    |
 LL |     assert_ne!(x, 0);
    |     ^^^^^^^^^^^^^^^^
index 8965cef66deddc899b5e1779a7f8814ebf61849d..be854d94183329d547df961f1690f32d10d01139 100644 (file)
@@ -1,6 +1,11 @@
+// aux-build:macro_rules.rs
+
 #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
 #![warn(clippy::mut_mut)]
 
+#[macro_use]
+extern crate macro_rules;
+
 fn fun(x: &mut &mut u32) -> bool {
     **x > 0
 }
@@ -47,3 +52,8 @@ fn issue939() {
         println!(":{}", arg);
     }
 }
+
+fn issue6922() {
+    // do not lint from an external macro
+    mut_mut!();
+}
index 0fed6953cb85c295fc022a50e9d13a97c2772ded..6820a85aa54337f2cad40936ed7d0f6bad95358b 100644 (file)
@@ -1,5 +1,5 @@
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:4:11
+  --> $DIR/mut_mut.rs:9:11
    |
 LL | fn fun(x: &mut &mut u32) -> bool {
    |           ^^^^^^^^^^^^^
@@ -7,13 +7,13 @@ LL | fn fun(x: &mut &mut u32) -> bool {
    = note: `-D clippy::mut-mut` implied by `-D warnings`
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:20:17
+  --> $DIR/mut_mut.rs:25:17
    |
 LL |     let mut x = &mut &mut 1u32;
    |                 ^^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:14:9
+  --> $DIR/mut_mut.rs:19:9
    |
 LL |         &mut $p
    |         ^^^^^^^
@@ -24,37 +24,37 @@ LL |     let mut z = mut_ptr!(&mut 3u32);
    = note: this error originates in the macro `mut_ptr` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this expression mutably borrows a mutable reference. Consider reborrowing
-  --> $DIR/mut_mut.rs:22:21
+  --> $DIR/mut_mut.rs:27:21
    |
 LL |         let mut y = &mut x;
    |                     ^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:26:32
+  --> $DIR/mut_mut.rs:31:32
    |
 LL |         let y: &mut &mut u32 = &mut &mut 2;
    |                                ^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:26:16
+  --> $DIR/mut_mut.rs:31:16
    |
 LL |         let y: &mut &mut u32 = &mut &mut 2;
    |                ^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:31:37
+  --> $DIR/mut_mut.rs:36:37
    |
 LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
    |                                     ^^^^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:31:16
+  --> $DIR/mut_mut.rs:36:16
    |
 LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
    |                ^^^^^^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:31:21
+  --> $DIR/mut_mut.rs:36:21
    |
 LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
    |                     ^^^^^^^^^^^^^
index 7a8137778b44607cd397c03b04205f43e27aeb84..04b6283da3c3b88d8a5b16c44edfd5d53133dbe6 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 // FIXME: run-rustfix waiting on multi-span suggestions
 
 #![warn(clippy::needless_borrow)]
index 365ecd68d8ff2e9cabc8e0635670712e744d17b1..db3b52b8850e1cfd252e3eda54933f1abe4f8b60 100644 (file)
@@ -1,5 +1,5 @@
 error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow_pat.rs:60:14
+  --> $DIR/needless_borrow_pat.rs:59:14
    |
 LL |         Some(ref x) => x,
    |              ^^^^^ help: try this: `x`
@@ -7,7 +7,7 @@ LL |         Some(ref x) => x,
    = note: `-D clippy::needless-borrow` implied by `-D warnings`
 
 error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow_pat.rs:66:14
+  --> $DIR/needless_borrow_pat.rs:65:14
    |
 LL |         Some(ref x) => *x,
    |              ^^^^^
@@ -18,7 +18,7 @@ LL |         Some(x) => x,
    |              ~     ~
 
 error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow_pat.rs:72:14
+  --> $DIR/needless_borrow_pat.rs:71:14
    |
 LL |         Some(ref x) => {
    |              ^^^^^
@@ -31,19 +31,19 @@ LL ~             f1(x);
    |
 
 error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow_pat.rs:82:14
+  --> $DIR/needless_borrow_pat.rs:81:14
    |
 LL |         Some(ref x) => m1!(x),
    |              ^^^^^ help: try this: `x`
 
 error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow_pat.rs:87:15
+  --> $DIR/needless_borrow_pat.rs:86:15
    |
 LL |     let _ = |&ref x: &&String| {
    |               ^^^^^ help: try this: `x`
 
 error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow_pat.rs:92:10
+  --> $DIR/needless_borrow_pat.rs:91:10
    |
 LL |     let (ref y,) = (&x,);
    |          ^^^^^
@@ -55,13 +55,13 @@ LL ~     let _: &String = y;
    |
 
 error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow_pat.rs:102:14
+  --> $DIR/needless_borrow_pat.rs:101:14
    |
 LL |         Some(ref x) => x.0,
    |              ^^^^^ help: try this: `x`
 
 error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow_pat.rs:112:14
+  --> $DIR/needless_borrow_pat.rs:111:14
    |
 LL |         E::A(ref x) | E::B(ref x) => *x,
    |              ^^^^^         ^^^^^
@@ -72,13 +72,13 @@ LL |         E::A(x) | E::B(x) => x,
    |              ~         ~     ~
 
 error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow_pat.rs:118:21
+  --> $DIR/needless_borrow_pat.rs:117:21
    |
 LL |         if let Some(ref x) = Some(&String::new());
    |                     ^^^^^ help: try this: `x`
 
 error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow_pat.rs:126:12
+  --> $DIR/needless_borrow_pat.rs:125:12
    |
 LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
    |            ^^^^^
@@ -91,13 +91,13 @@ LL ~     x
    |
 
 error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow_pat.rs:133:11
+  --> $DIR/needless_borrow_pat.rs:132:11
    |
 LL |     fn f(&ref x: &&String) {
    |           ^^^^^ help: try this: `x`
 
 error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow_pat.rs:141:11
+  --> $DIR/needless_borrow_pat.rs:140:11
    |
 LL |     fn f(&ref x: &&String) {
    |           ^^^^^
index 1d77382bf2cd1132549232dd03fe41af93de9389..b07c4a2381031f2f4c617c4e355e904c8243f9a6 100644 (file)
@@ -27,6 +27,11 @@ fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 {
     x
 }
 
+// No error; multiple input refs
+async fn func<'a>(args: &[&'a str]) -> Option<&'a str> {
+    args.get(0).cloned()
+}
+
 // No error; static involved.
 fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 {
     x
index 33a6de1618d12c1a509df271c43b8f57e11d9282..4114e6f1832fc694ddbffecd65819900de31df43 100644 (file)
@@ -19,133 +19,133 @@ LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:45:1
+  --> $DIR/needless_lifetimes.rs:50:1
    |
 LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:50:1
+  --> $DIR/needless_lifetimes.rs:55:1
    |
 LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:62:1
+  --> $DIR/needless_lifetimes.rs:67:1
    |
 LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:86:1
+  --> $DIR/needless_lifetimes.rs:91:1
    |
 LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:116:5
+  --> $DIR/needless_lifetimes.rs:121:5
    |
 LL |     fn self_and_out<'s>(&'s self) -> &'s u8 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:125:5
+  --> $DIR/needless_lifetimes.rs:130:5
    |
 LL |     fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:144:1
+  --> $DIR/needless_lifetimes.rs:149:1
    |
 LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:174:1
+  --> $DIR/needless_lifetimes.rs:179:1
    |
 LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:180:1
+  --> $DIR/needless_lifetimes.rs:185:1
    |
 LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:199:1
+  --> $DIR/needless_lifetimes.rs:204:1
    |
 LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:207:1
+  --> $DIR/needless_lifetimes.rs:212:1
    |
 LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:243:1
+  --> $DIR/needless_lifetimes.rs:248:1
    |
 LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:250:9
+  --> $DIR/needless_lifetimes.rs:255:9
    |
 LL |         fn needless_lt<'a>(x: &'a u8) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:254:9
+  --> $DIR/needless_lifetimes.rs:259:9
    |
 LL |         fn needless_lt<'a>(_x: &'a u8) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:267:9
+  --> $DIR/needless_lifetimes.rs:272:9
    |
 LL |         fn baz<'a>(&'a self) -> impl Foo + 'a {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:296:5
+  --> $DIR/needless_lifetimes.rs:301:5
    |
 LL |     fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:299:5
+  --> $DIR/needless_lifetimes.rs:304:5
    |
 LL |     fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:308:5
+  --> $DIR/needless_lifetimes.rs:313:5
    |
 LL |     fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:320:5
+  --> $DIR/needless_lifetimes.rs:325:5
    |
 LL |     fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:335:5
+  --> $DIR/needless_lifetimes.rs:340:5
    |
 LL |     fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:348:5
+  --> $DIR/needless_lifetimes.rs:353:5
    |
 LL |     fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:351:5
+  --> $DIR/needless_lifetimes.rs:356:5
    |
 LL |     fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 9c999e12b4cbc4c6d5a3afed29e97cffa3638623..812ce7163cd50ab215cd7130493b1e816d71ccf4 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-// edition:2018
 
 #![feature(let_else)]
 #![allow(unused)]
index da7dcf4f0a9ea377596a830996947f6d5afa60fb..c42567b517c9115819b3446d5c5281c0da273884 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-// edition:2018
 
 #![feature(let_else)]
 #![allow(unused)]
index 2e802cff1e686917ddef5a3c5e1ba7421c617ec4..74dda971fdabb632633f4a125ba15d6e2d5ad1a3 100644 (file)
@@ -1,5 +1,5 @@
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:25:5
+  --> $DIR/needless_return.rs:24:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^^ help: remove `return`: `true`
@@ -7,187 +7,187 @@ LL |     return true;
    = note: `-D clippy::needless-return` implied by `-D warnings`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:29:5
+  --> $DIR/needless_return.rs:28:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:34:9
+  --> $DIR/needless_return.rs:33:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:36:9
+  --> $DIR/needless_return.rs:35:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^^ help: remove `return`: `false`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:42:17
+  --> $DIR/needless_return.rs:41:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^ help: remove `return`: `false`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:44:13
+  --> $DIR/needless_return.rs:43:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:51:9
+  --> $DIR/needless_return.rs:50:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:53:16
+  --> $DIR/needless_return.rs:52:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:61:5
+  --> $DIR/needless_return.rs:60:5
    |
 LL |     return;
    |     ^^^^^^^ help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:66:9
+  --> $DIR/needless_return.rs:65:9
    |
 LL |         return;
    |         ^^^^^^^ help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:68:9
+  --> $DIR/needless_return.rs:67:9
    |
 LL |         return;
    |         ^^^^^^^ help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:75:14
+  --> $DIR/needless_return.rs:74:14
    |
 LL |         _ => return,
    |              ^^^^^^ help: replace `return` with an empty block: `{}`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:90:9
+  --> $DIR/needless_return.rs:89:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:92:9
+  --> $DIR/needless_return.rs:91:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:113:32
+  --> $DIR/needless_return.rs:112:32
    |
 LL |         bar.unwrap_or_else(|_| return)
    |                                ^^^^^^ help: replace `return` with an empty block: `{}`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:118:13
+  --> $DIR/needless_return.rs:117:13
    |
 LL |             return;
    |             ^^^^^^^ help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:120:20
+  --> $DIR/needless_return.rs:119:20
    |
 LL |         let _ = || return;
    |                    ^^^^^^ help: replace `return` with an empty block: `{}`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:126:32
+  --> $DIR/needless_return.rs:125:32
    |
 LL |         res.unwrap_or_else(|_| return Foo)
    |                                ^^^^^^^^^^ help: remove `return`: `Foo`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:135:5
+  --> $DIR/needless_return.rs:134:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:139:5
+  --> $DIR/needless_return.rs:138:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:144:9
+  --> $DIR/needless_return.rs:143:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:146:9
+  --> $DIR/needless_return.rs:145:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^^ help: remove `return`: `false`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:152:17
+  --> $DIR/needless_return.rs:151:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^ help: remove `return`: `false`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:154:13
+  --> $DIR/needless_return.rs:153:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:161:9
+  --> $DIR/needless_return.rs:160:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:163:16
+  --> $DIR/needless_return.rs:162:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:171:5
+  --> $DIR/needless_return.rs:170:5
    |
 LL |     return;
    |     ^^^^^^^ help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:176:9
+  --> $DIR/needless_return.rs:175:9
    |
 LL |         return;
    |         ^^^^^^^ help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:178:9
+  --> $DIR/needless_return.rs:177:9
    |
 LL |         return;
    |         ^^^^^^^ help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:185:14
+  --> $DIR/needless_return.rs:184:14
    |
 LL |         _ => return,
    |              ^^^^^^ help: replace `return` with an empty block: `{}`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:200:9
+  --> $DIR/needless_return.rs:199:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:202:9
+  --> $DIR/needless_return.rs:201:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
index 7ec845adfaacf6d290e4d4be2011f3b0917d2621..7bcc4cad0d363a78153e36456b0e128eaeef8e45 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(box_syntax)]
-#![warn(clippy::no_effect)]
+#![warn(clippy::no_effect_underscore_binding)]
 #![allow(dead_code)]
 #![allow(path_statements)]
 #![allow(clippy::deref_addrof)]
@@ -90,6 +90,10 @@ fn main() {
     || x += 5;
     let s: String = "foo".into();
     FooString { s: s };
+    let _unused = 1;
+    let _penguin = || println!("Some helpful closure");
+    let _duck = Struct { field: 0 };
+    let _cat = [2, 4, 6, 8][2];
 
     #[allow(clippy::no_effect)]
     0;
@@ -97,6 +101,8 @@ fn main() {
     // Do not warn
     get_number();
     unsafe { unsafe_fn() };
+    let _used = get_struct();
+    let _x = vec![1];
     DropUnit;
     DropStruct { field: 0 };
     DropTuple(0);
index 6b24675ac2d42a8a934a85989394ca2920c44895..a5dbc9fef455a4e71028acbfcfa78c4577dda5e5 100644 (file)
@@ -156,5 +156,31 @@ error: statement with no effect
 LL |     FooString { s: s };
    |     ^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 26 previous errors
+error: binding to `_` prefixed variable with no side-effect
+  --> $DIR/no_effect.rs:93:5
+   |
+LL |     let _unused = 1;
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings`
+
+error: binding to `_` prefixed variable with no side-effect
+  --> $DIR/no_effect.rs:94:5
+   |
+LL |     let _penguin = || println!("Some helpful closure");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: binding to `_` prefixed variable with no side-effect
+  --> $DIR/no_effect.rs:95:5
+   |
+LL |     let _duck = Struct { field: 0 };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: binding to `_` prefixed variable with no side-effect
+  --> $DIR/no_effect.rs:96:5
+   |
+LL |     let _cat = [2, 4, 6, 8][2];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 30 previous errors
 
index 58415b4aede260b668dbd3db7a0f9a56bc56ecd8..961f6f409ddd2202916bfe14c17111d208359592 100644 (file)
@@ -15,8 +15,8 @@ struct InstSplit {
 impl MaybeInst {
     fn fill(&mut self) {
         let filled = match *self {
-            MaybeInst::Split1(goto1) => panic!(1),
-            MaybeInst::Split2(goto2) => panic!(2),
+            MaybeInst::Split1(goto1) => panic!("1"),
+            MaybeInst::Split2(goto2) => panic!("2"),
             _ => unimplemented!(),
         };
         unimplemented!()
index 1d39bce935db8cdb0dfedba0f9e6424613bc2249..bb93cbbd5e1904d196e29c39d453db59db8c04ff 100644 (file)
@@ -50,10 +50,10 @@ LL |     let _ = a == b && c == 5 && a == b;
    |
 help: try
    |
-LL |     let _ = a == b && c == 5;
-   |             ~~~~~~~~~~~~~~~~
 LL |     let _ = !(a != b || c != 5);
    |             ~~~~~~~~~~~~~~~~~~~
+LL |     let _ = a == b && c == 5;
+   |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
   --> $DIR/nonminimal_bool.rs:28:13
@@ -63,10 +63,10 @@ LL |     let _ = a == b || c == 5 || a == b;
    |
 help: try
    |
-LL |     let _ = a == b || c == 5;
-   |             ~~~~~~~~~~~~~~~~
 LL |     let _ = !(a != b && c != 5);
    |             ~~~~~~~~~~~~~~~~~~~
+LL |     let _ = a == b || c == 5;
+   |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
   --> $DIR/nonminimal_bool.rs:29:13
@@ -76,10 +76,10 @@ LL |     let _ = a == b && c == 5 && b == a;
    |
 help: try
    |
-LL |     let _ = a == b && c == 5;
-   |             ~~~~~~~~~~~~~~~~
 LL |     let _ = !(a != b || c != 5);
    |             ~~~~~~~~~~~~~~~~~~~
+LL |     let _ = a == b && c == 5;
+   |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
   --> $DIR/nonminimal_bool.rs:30:13
@@ -89,10 +89,10 @@ LL |     let _ = a != b || !(a != b || c == d);
    |
 help: try
    |
-LL |     let _ = a != b || c != d;
-   |             ~~~~~~~~~~~~~~~~
 LL |     let _ = !(a == b && c == d);
    |             ~~~~~~~~~~~~~~~~~~~
+LL |     let _ = a != b || c != d;
+   |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
   --> $DIR/nonminimal_bool.rs:31:13
@@ -102,10 +102,10 @@ LL |     let _ = a != b && !(a != b && c == d);
    |
 help: try
    |
-LL |     let _ = a != b && c != d;
-   |             ~~~~~~~~~~~~~~~~
 LL |     let _ = !(a == b || c == d);
    |             ~~~~~~~~~~~~~~~~~~~
+LL |     let _ = a != b && c != d;
+   |             ~~~~~~~~~~~~~~~~
 
 error: aborting due to 12 previous errors
 
index a3ebe5d0703846bd09a131d94a0008700eba1b9c..9cb6a9d1ecc9bc9e91c0cf071c748ab45a962711 100644 (file)
@@ -1,8 +1,6 @@
-// edition:2018
 // run-rustfix
 #![warn(clippy::option_if_let_else)]
-#![allow(clippy::redundant_closure)]
-#![allow(clippy::ref_option_ref, clippy::equatable_if_let)]
+#![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
     string.map_or((false, "hello"), |x| (true, x))
index b11df3db60f57edfa56913f4af239b343259ecfa..b3ba5eb870a693e65053cf50bbc1c914520fbe4a 100644 (file)
@@ -1,8 +1,6 @@
-// edition:2018
 // run-rustfix
 #![warn(clippy::option_if_let_else)]
-#![allow(clippy::redundant_closure)]
-#![allow(clippy::ref_option_ref, clippy::equatable_if_let)]
+#![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
     if let Some(x) = string {
index ed748ee8b39e4422c034f9a96982316dbb256745..685bb48ea37bc05baf1945d6a66b7c12f69c0934 100644 (file)
@@ -1,5 +1,5 @@
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:8:5
+  --> $DIR/option_if_let_else.rs:6:5
    |
 LL | /     if let Some(x) = string {
 LL | |         (true, x)
@@ -11,19 +11,19 @@ LL | |     }
    = note: `-D clippy::option-if-let-else` implied by `-D warnings`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:26:13
+  --> $DIR/option_if_let_else.rs:24:13
    |
 LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:27:13
+  --> $DIR/option_if_let_else.rs:25:13
    |
 LL |     let _ = if let Some(s) = &num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:28:13
+  --> $DIR/option_if_let_else.rs:26:13
    |
 LL |       let _ = if let Some(s) = &mut num {
    |  _____________^
@@ -43,13 +43,13 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:34:13
+  --> $DIR/option_if_let_else.rs:32:13
    |
 LL |     let _ = if let Some(ref s) = num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:35:13
+  --> $DIR/option_if_let_else.rs:33:13
    |
 LL |       let _ = if let Some(mut s) = num {
    |  _____________^
@@ -69,7 +69,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:41:13
+  --> $DIR/option_if_let_else.rs:39:13
    |
 LL |       let _ = if let Some(ref mut s) = num {
    |  _____________^
@@ -89,7 +89,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:50:5
+  --> $DIR/option_if_let_else.rs:48:5
    |
 LL | /     if let Some(x) = arg {
 LL | |         let y = x * x;
@@ -108,7 +108,7 @@ LL +     })
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:63:13
+  --> $DIR/option_if_let_else.rs:61:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -120,7 +120,7 @@ LL | |     };
    | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:72:13
+  --> $DIR/option_if_let_else.rs:70:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -143,13 +143,13 @@ LL ~     }, |x| x * x * x * x);
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:101:13
+  --> $DIR/option_if_let_else.rs:99:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:110:13
+  --> $DIR/option_if_let_else.rs:108:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -171,13 +171,13 @@ LL ~         });
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:138:13
+  --> $DIR/option_if_let_else.rs:136:13
    |
 LL |     let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or_else(|| s.len(), |x| s.len() + x)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:142:13
+  --> $DIR/option_if_let_else.rs:140:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
index 3d3c19a1be5199e70c2a08f6c439aaca2e8a9645..e75eb1b6eadd85ca225d830e3cb8ffe96bf584fa 100644 (file)
@@ -1,6 +1,5 @@
 #![warn(clippy::panic_in_result_fn)]
 #![allow(clippy::unnecessary_wraps)]
-
 struct A;
 
 impl A {
index f56c2d03c664fb2d98448f7127c92acabb6b2bdc..78d09b8b2108a134b0c91a4c37e5bbd238de6387 100644 (file)
@@ -1,5 +1,5 @@
 error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
-  --> $DIR/panic_in_result_fn.rs:7:5
+  --> $DIR/panic_in_result_fn.rs:6:5
    |
 LL | /     fn result_with_panic() -> Result<bool, String> // should emit lint
 LL | |     {
@@ -10,14 +10,14 @@ LL | |     }
    = note: `-D clippy::panic-in-result-fn` implied by `-D warnings`
    = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
 note: return Err() instead of panicking
-  --> $DIR/panic_in_result_fn.rs:9:9
+  --> $DIR/panic_in_result_fn.rs:8:9
    |
 LL |         panic!("error");
    |         ^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = 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:12:5
+  --> $DIR/panic_in_result_fn.rs:11:5
    |
 LL | /     fn result_with_unimplemented() -> Result<bool, String> // should emit lint
 LL | |     {
@@ -27,14 +27,14 @@ LL | |     }
    |
    = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
 note: return Err() instead of panicking
-  --> $DIR/panic_in_result_fn.rs:14:9
+  --> $DIR/panic_in_result_fn.rs:13:9
    |
 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:17:5
+  --> $DIR/panic_in_result_fn.rs:16:5
    |
 LL | /     fn result_with_unreachable() -> Result<bool, String> // should emit lint
 LL | |     {
@@ -44,14 +44,14 @@ LL | |     }
    |
    = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
 note: return Err() instead of panicking
-  --> $DIR/panic_in_result_fn.rs:19:9
+  --> $DIR/panic_in_result_fn.rs:18:9
    |
 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:22:5
+  --> $DIR/panic_in_result_fn.rs:21:5
    |
 LL | /     fn result_with_todo() -> Result<bool, String> // should emit lint
 LL | |     {
@@ -61,14 +61,14 @@ LL | |     }
    |
    = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
 note: return Err() instead of panicking
-  --> $DIR/panic_in_result_fn.rs:24:9
+  --> $DIR/panic_in_result_fn.rs:23:9
    |
 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:53:1
+  --> $DIR/panic_in_result_fn.rs:52:1
    |
 LL | / fn function_result_with_panic() -> Result<bool, String> // should emit lint
 LL | | {
@@ -78,14 +78,14 @@ LL | | }
    |
    = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
 note: return Err() instead of panicking
-  --> $DIR/panic_in_result_fn.rs:55:5
+  --> $DIR/panic_in_result_fn.rs:54:5
    |
 LL |     panic!("error");
    |     ^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = 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:68:1
+  --> $DIR/panic_in_result_fn.rs:67:1
    |
 LL | / fn main() -> Result<(), String> {
 LL | |     todo!("finish main method");
@@ -95,7 +95,7 @@ LL | | }
    |
    = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
 note: return Err() instead of panicking
-  --> $DIR/panic_in_result_fn.rs:69:5
+  --> $DIR/panic_in_result_fn.rs:68:5
    |
 LL |     todo!("finish main method");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 99e6d2aad8dd6b46ac5229da0866d36218688f0a..67bfef06a05e8cdd3e7b73c19fbc629d5e6fbf3e 100644 (file)
@@ -1,9 +1,4 @@
-#![allow(
-    unused,
-    clippy::many_single_char_names,
-    clippy::redundant_clone,
-    clippy::if_then_panic
-)]
+#![allow(unused, clippy::many_single_char_names, clippy::redundant_clone)]
 #![warn(clippy::ptr_arg)]
 
 use std::borrow::Cow;
@@ -160,3 +155,7 @@ fn foo_str(str: &PathBuf) {
         let _ = str.clone().clone();
     }
 }
+
+// No error for types behind an alias (#7699)
+type A = Vec<u8>;
+fn aliased(a: &A) {}
index 42183447ead737cf34275a3fe9be5edf01a406c4..64594eb870c2c5067b413095f6eabdeded968ebc 100644 (file)
@@ -1,5 +1,5 @@
 error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
-  --> $DIR/ptr_arg.rs:12:14
+  --> $DIR/ptr_arg.rs:7:14
    |
 LL | fn do_vec(x: &Vec<i64>) {
    |              ^^^^^^^^^ help: change this to: `&[i64]`
@@ -7,25 +7,25 @@ LL | fn do_vec(x: &Vec<i64>) {
    = note: `-D clippy::ptr-arg` implied by `-D warnings`
 
 error: writing `&String` instead of `&str` involves a new object where a slice will do
-  --> $DIR/ptr_arg.rs:21:14
+  --> $DIR/ptr_arg.rs:16:14
    |
 LL | fn do_str(x: &String) {
    |              ^^^^^^^ help: change this to: `&str`
 
 error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-  --> $DIR/ptr_arg.rs:30:15
+  --> $DIR/ptr_arg.rs:25:15
    |
 LL | fn do_path(x: &PathBuf) {
    |               ^^^^^^^^ help: change this to: `&Path`
 
 error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
-  --> $DIR/ptr_arg.rs:43:18
+  --> $DIR/ptr_arg.rs:38:18
    |
 LL |     fn do_vec(x: &Vec<i64>);
    |                  ^^^^^^^^^ help: change this to: `&[i64]`
 
 error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
-  --> $DIR/ptr_arg.rs:56:14
+  --> $DIR/ptr_arg.rs:51:14
    |
 LL | fn cloned(x: &Vec<u8>) -> Vec<u8> {
    |              ^^^^^^^^
@@ -44,7 +44,7 @@ LL |     x.to_owned()
    |
 
 error: writing `&String` instead of `&str` involves a new object where a slice will do
-  --> $DIR/ptr_arg.rs:65:18
+  --> $DIR/ptr_arg.rs:60:18
    |
 LL | fn str_cloned(x: &String) -> String {
    |                  ^^^^^^^
@@ -67,7 +67,7 @@ LL |     x.to_string()
    |
 
 error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-  --> $DIR/ptr_arg.rs:73:19
+  --> $DIR/ptr_arg.rs:68:19
    |
 LL | fn path_cloned(x: &PathBuf) -> PathBuf {
    |                   ^^^^^^^^
@@ -90,7 +90,7 @@ LL |     x.to_path_buf()
    |
 
 error: writing `&String` instead of `&str` involves a new object where a slice will do
-  --> $DIR/ptr_arg.rs:81:44
+  --> $DIR/ptr_arg.rs:76:44
    |
 LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) {
    |                                            ^^^^^^^
@@ -109,13 +109,13 @@ LL |     let c = y;
    |             ~
 
 error: using a reference to `Cow` is not recommended
-  --> $DIR/ptr_arg.rs:95:25
+  --> $DIR/ptr_arg.rs:90:25
    |
 LL | fn test_cow_with_ref(c: &Cow<[i32]>) {}
    |                         ^^^^^^^^^^^ help: change this to: `&[i32]`
 
 error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
-  --> $DIR/ptr_arg.rs:148:21
+  --> $DIR/ptr_arg.rs:143:21
    |
 LL |     fn foo_vec(vec: &Vec<u8>) {
    |                     ^^^^^^^^
@@ -134,7 +134,7 @@ LL |         let _ = vec.to_owned().clone();
    |                 ~~~~~~~~~~~~~~
 
 error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-  --> $DIR/ptr_arg.rs:153:23
+  --> $DIR/ptr_arg.rs:148:23
    |
 LL |     fn foo_path(path: &PathBuf) {
    |                       ^^^^^^^^
@@ -153,7 +153,7 @@ LL |         let _ = path.to_path_buf().clone();
    |                 ~~~~~~~~~~~~~~~~~~
 
 error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-  --> $DIR/ptr_arg.rs:158:21
+  --> $DIR/ptr_arg.rs:153:21
    |
 LL |     fn foo_str(str: &PathBuf) {
    |                     ^^^^^^^^
index 0b5746cb52270ed7e59d4126b7664151d1d39e95..e93469e5f556bd55737c0628961e540e7caf5be1 100644 (file)
@@ -104,6 +104,38 @@ fn func() -> Option<i32> {
     Some(0)
 }
 
+fn func_returning_result() -> Result<i32, i32> {
+    Ok(1)
+}
+
+fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
+    let _ = x?;
+
+    x?;
+
+    // No warning
+    let y = if let Ok(x) = x {
+        x
+    } else {
+        return Err(0);
+    };
+
+    // issue #7859
+    // no warning
+    let _ = if let Ok(x) = func_returning_result() {
+        x
+    } else {
+        return Err(0);
+    };
+
+    // no warning
+    if func_returning_result().is_err() {
+        return func_returning_result();
+    }
+
+    Ok(y)
+}
+
 fn main() {
     some_func(Some(42));
     some_func(None);
@@ -123,4 +155,6 @@ fn main() {
     returns_something_similar_to_option(so);
 
     func();
+
+    let _ = result_func(Ok(42));
 }
index 0f0825c9334679d185e9bc711dc86f05df0466d8..dd179e9bee8f87d57c6623617d0b646fb154c684 100644 (file)
@@ -134,6 +134,40 @@ fn f() -> Option<String> {
     Some(0)
 }
 
+fn func_returning_result() -> Result<i32, i32> {
+    Ok(1)
+}
+
+fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
+    let _ = if let Ok(x) = x { x } else { return x };
+
+    if x.is_err() {
+        return x;
+    }
+
+    // No warning
+    let y = if let Ok(x) = x {
+        x
+    } else {
+        return Err(0);
+    };
+
+    // issue #7859
+    // no warning
+    let _ = if let Ok(x) = func_returning_result() {
+        x
+    } else {
+        return Err(0);
+    };
+
+    // no warning
+    if func_returning_result().is_err() {
+        return func_returning_result();
+    }
+
+    Ok(y)
+}
+
 fn main() {
     some_func(Some(42));
     some_func(None);
@@ -153,4 +187,6 @@ fn main() {
     returns_something_similar_to_option(so);
 
     func();
+
+    let _ = result_func(Ok(42));
 }
index 6f330cfa385dddeaab2c9473fb9c684f381aea27..8d782b71dd6a47ae8368b0d8f8c7ba89b13b34b6 100644 (file)
@@ -100,5 +100,19 @@ LL | |         return None;
 LL | |     }
    | |_____^ help: replace it with: `f()?;`
 
-error: aborting due to 11 previous errors
+error: this if-let-else may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:142:13
+   |
+LL |     let _ = if let Ok(x) = x { x } else { return x };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?`
+
+error: this block may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:144:5
+   |
+LL | /     if x.is_err() {
+LL | |         return x;
+LL | |     }
+   | |_____^ help: replace it with: `x?;`
+
+error: aborting due to 13 previous errors
 
index 2d711082746e73aab40867f0bcc2285137e5aca2..16b40dcd902869d7184cb1d6b384139166d04380 100644 (file)
@@ -196,7 +196,7 @@ fn clone_then_move_cloned() {
     fn foo<F: Fn()>(_: &Alpha, _: F) {}
     let x = Alpha;
     // ok, data is moved while the clone is in use.
-    foo(&x.clone(), move || {
+    foo(&x, move || {
         let _ = x;
     });
 
index fbc90493ae94b85986e8381ef82e395fbc202e9e..9f59017b26199cad1ae2acb9fe1b96c8048ac363 100644 (file)
@@ -167,5 +167,17 @@ note: cloned value is neither consumed nor mutated
 LL |     let y = x.clone().join("matthias");
    |             ^^^^^^^^^
 
-error: aborting due to 14 previous errors
+error: redundant clone
+  --> $DIR/redundant_clone.rs:199:11
+   |
+LL |     foo(&x.clone(), move || {
+   |           ^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:199:10
+   |
+LL |     foo(&x.clone(), move || {
+   |          ^
+
+error: aborting due to 15 previous errors
 
index cd6db8ddc8864fd2a08de85ed9de26c8c31fd553..fe742a4c2f4c5acd69d1300242eb59bb0de67aa2 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 // FIXME: run-rustfix waiting on multi-span suggestions
 
 #![warn(clippy::ref_binding_to_reference)]
index eb36cd516a246a9e4f581b7079efb0bacc8cc09d..c5856e15fa987b3a4c19737019941430373606ce 100644 (file)
@@ -1,5 +1,5 @@
 error: this pattern creates a reference to a reference
-  --> $DIR/ref_binding_to_reference.rs:31:14
+  --> $DIR/ref_binding_to_reference.rs:30:14
    |
 LL |         Some(ref x) => x,
    |              ^^^^^
@@ -11,7 +11,7 @@ LL |         Some(x) => &x,
    |              ~     ~~
 
 error: this pattern creates a reference to a reference
-  --> $DIR/ref_binding_to_reference.rs:37:14
+  --> $DIR/ref_binding_to_reference.rs:36:14
    |
 LL |         Some(ref x) => {
    |              ^^^^^
@@ -25,7 +25,7 @@ LL ~             &x
    |
 
 error: this pattern creates a reference to a reference
-  --> $DIR/ref_binding_to_reference.rs:47:14
+  --> $DIR/ref_binding_to_reference.rs:46:14
    |
 LL |         Some(ref x) => m2!(x),
    |              ^^^^^
@@ -36,7 +36,7 @@ LL |         Some(x) => m2!(&x),
    |              ~         ~~
 
 error: this pattern creates a reference to a reference
-  --> $DIR/ref_binding_to_reference.rs:52:15
+  --> $DIR/ref_binding_to_reference.rs:51:15
    |
 LL |     let _ = |&ref x: &&String| {
    |               ^^^^^
@@ -48,7 +48,7 @@ LL ~         let _: &&String = &x;
    |
 
 error: this pattern creates a reference to a reference
-  --> $DIR/ref_binding_to_reference.rs:58:12
+  --> $DIR/ref_binding_to_reference.rs:57:12
    |
 LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
    |            ^^^^^
@@ -61,7 +61,7 @@ LL ~     x
    |
 
 error: this pattern creates a reference to a reference
-  --> $DIR/ref_binding_to_reference.rs:65:11
+  --> $DIR/ref_binding_to_reference.rs:64:11
    |
 LL |     fn f(&ref x: &&String) {
    |           ^^^^^
@@ -73,7 +73,7 @@ LL ~         let _: &&String = &x;
    |
 
 error: this pattern creates a reference to a reference
-  --> $DIR/ref_binding_to_reference.rs:73:11
+  --> $DIR/ref_binding_to_reference.rs:72:11
    |
 LL |     fn f(&ref x: &&String) {
    |           ^^^^^
index a66c2e587c8736111e067f1b2dd8a41d583840a5..cc295b509bc51973cd1bf3f03d591bee3bc732e3 100644 (file)
@@ -6,15 +6,58 @@
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::new_without_default)]
 #![allow(clippy::redundant_static_lifetimes)]
+#![allow(clippy::bind_instead_of_map)]
+#![allow(clippy::box_collection)]
+#![allow(clippy::blocks_in_if_conditions)]
+#![allow(clippy::map_unwrap_or)]
+#![allow(clippy::unwrap_used)]
+#![allow(clippy::expect_used)]
+#![allow(clippy::for_loops_over_fallibles)]
+#![allow(clippy::useless_conversion)]
+#![allow(clippy::invisible_characters)]
+#![allow(clippy::single_char_add_str)]
+#![allow(clippy::match_result_ok)]
+// uplifted lints
+#![allow(invalid_value)]
+#![allow(array_into_iter)]
+#![allow(unused_labels)]
+#![allow(drop_bounds)]
+#![allow(temporary_cstring_as_ptr)]
+#![allow(non_fmt_panics)]
+#![allow(unknown_lints)]
+#![allow(invalid_atomic_ordering)]
+#![allow(enum_intrinsics_non_enums)]
 // warn for the old lint name here, to test if the renaming worked
+#![warn(clippy::module_name_repetitions)]
+#![warn(clippy::new_without_default)]
+#![warn(clippy::redundant_static_lifetimes)]
 #![warn(clippy::cognitive_complexity)]
+#![warn(clippy::bind_instead_of_map)]
+#![warn(clippy::box_collection)]
+#![warn(clippy::blocks_in_if_conditions)]
+#![warn(clippy::blocks_in_if_conditions)]
+#![warn(clippy::map_unwrap_or)]
+#![warn(clippy::map_unwrap_or)]
+#![warn(clippy::map_unwrap_or)]
+#![warn(clippy::unwrap_used)]
+#![warn(clippy::unwrap_used)]
+#![warn(clippy::expect_used)]
+#![warn(clippy::expect_used)]
+#![warn(clippy::for_loops_over_fallibles)]
+#![warn(clippy::for_loops_over_fallibles)]
+#![warn(clippy::useless_conversion)]
+#![warn(clippy::invisible_characters)]
+#![warn(clippy::single_char_add_str)]
+#![warn(clippy::match_result_ok)]
+// uplifted lints
+#![warn(invalid_value)]
+#![warn(array_into_iter)]
+#![warn(unused_labels)]
+#![warn(drop_bounds)]
+#![warn(temporary_cstring_as_ptr)]
+#![warn(non_fmt_panics)]
+#![warn(unknown_lints)]
+#![warn(invalid_atomic_ordering)]
 #![warn(enum_intrinsics_non_enums)]
 
-#[warn(clippy::module_name_repetitions)]
 fn main() {}
-
-#[warn(clippy::new_without_default)]
-struct Foo;
-
-#[warn(clippy::redundant_static_lifetimes)]
-fn foo() {}
index fa81201a2daf305fd675ddf65668882cdb842419..377075c02464a85becebae4817f176745f490ea0 100644 (file)
@@ -6,15 +6,58 @@
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::new_without_default)]
 #![allow(clippy::redundant_static_lifetimes)]
+#![allow(clippy::bind_instead_of_map)]
+#![allow(clippy::box_collection)]
+#![allow(clippy::blocks_in_if_conditions)]
+#![allow(clippy::map_unwrap_or)]
+#![allow(clippy::unwrap_used)]
+#![allow(clippy::expect_used)]
+#![allow(clippy::for_loops_over_fallibles)]
+#![allow(clippy::useless_conversion)]
+#![allow(clippy::invisible_characters)]
+#![allow(clippy::single_char_add_str)]
+#![allow(clippy::match_result_ok)]
+// uplifted lints
+#![allow(invalid_value)]
+#![allow(array_into_iter)]
+#![allow(unused_labels)]
+#![allow(drop_bounds)]
+#![allow(temporary_cstring_as_ptr)]
+#![allow(non_fmt_panics)]
+#![allow(unknown_lints)]
+#![allow(invalid_atomic_ordering)]
+#![allow(enum_intrinsics_non_enums)]
 // warn for the old lint name here, to test if the renaming worked
+#![warn(clippy::stutter)]
+#![warn(clippy::new_without_default_derive)]
+#![warn(clippy::const_static_lifetime)]
 #![warn(clippy::cyclomatic_complexity)]
+#![warn(clippy::option_and_then_some)]
+#![warn(clippy::box_vec)]
+#![warn(clippy::block_in_if_condition_expr)]
+#![warn(clippy::block_in_if_condition_stmt)]
+#![warn(clippy::option_map_unwrap_or)]
+#![warn(clippy::option_map_unwrap_or_else)]
+#![warn(clippy::result_map_unwrap_or_else)]
+#![warn(clippy::option_unwrap_used)]
+#![warn(clippy::result_unwrap_used)]
+#![warn(clippy::option_expect_used)]
+#![warn(clippy::result_expect_used)]
+#![warn(clippy::for_loop_over_option)]
+#![warn(clippy::for_loop_over_result)]
+#![warn(clippy::identity_conversion)]
+#![warn(clippy::zero_width_space)]
+#![warn(clippy::single_char_push_str)]
+#![warn(clippy::if_let_some_result)]
+// uplifted lints
+#![warn(clippy::invalid_ref)]
+#![warn(clippy::into_iter_on_array)]
+#![warn(clippy::unused_label)]
+#![warn(clippy::drop_bounds)]
+#![warn(clippy::temporary_cstring_as_ptr)]
+#![warn(clippy::panic_params)]
+#![warn(clippy::unknown_clippy_lints)]
+#![warn(clippy::invalid_atomic_ordering)]
 #![warn(clippy::mem_discriminant_non_enum)]
 
-#[warn(clippy::stutter)]
 fn main() {}
-
-#[warn(clippy::new_without_default_derive)]
-struct Foo;
-
-#[warn(clippy::const_static_lifetime)]
-fn foo() {}
index 05c7854074c60cd3ba9291173c7c70421cf17ccf..d720f10d117c097ad2df27ae1ac45e9b63e971ee 100644 (file)
+error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
+  --> $DIR/rename.rs:31:9
+   |
+LL | #![warn(clippy::stutter)]
+   |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
+   |
+   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+
+error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
+  --> $DIR/rename.rs:32:9
+   |
+LL | #![warn(clippy::new_without_default_derive)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
+
+error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
+  --> $DIR/rename.rs:33:9
+   |
+LL | #![warn(clippy::const_static_lifetime)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
+
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:10:9
+  --> $DIR/rename.rs:34:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
+
+error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
+  --> $DIR/rename.rs:35:9
    |
-   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+LL | #![warn(clippy::option_and_then_some)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
-error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:11:9
+error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
+  --> $DIR/rename.rs:36:9
    |
-LL | #![warn(clippy::mem_discriminant_non_enum)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
+LL | #![warn(clippy::box_vec)]
+   |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
-error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:13:8
+error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
+  --> $DIR/rename.rs:37:9
    |
-LL | #[warn(clippy::stutter)]
-   |        ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
+LL | #![warn(clippy::block_in_if_condition_expr)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
-error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:16:8
+error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
+  --> $DIR/rename.rs:38:9
    |
-LL | #[warn(clippy::new_without_default_derive)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
+LL | #![warn(clippy::block_in_if_condition_stmt)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
-error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:19:8
+error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
+  --> $DIR/rename.rs:39:9
+   |
+LL | #![warn(clippy::option_map_unwrap_or)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+
+error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
+  --> $DIR/rename.rs:40:9
+   |
+LL | #![warn(clippy::option_map_unwrap_or_else)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+
+error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
+  --> $DIR/rename.rs:41:9
+   |
+LL | #![warn(clippy::result_map_unwrap_or_else)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+
+error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
+  --> $DIR/rename.rs:42:9
+   |
+LL | #![warn(clippy::option_unwrap_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
+
+error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
+  --> $DIR/rename.rs:43:9
+   |
+LL | #![warn(clippy::result_unwrap_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
+
+error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
+  --> $DIR/rename.rs:44:9
+   |
+LL | #![warn(clippy::option_expect_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
+
+error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
+  --> $DIR/rename.rs:45:9
+   |
+LL | #![warn(clippy::result_expect_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
+
+error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
+  --> $DIR/rename.rs:46:9
+   |
+LL | #![warn(clippy::for_loop_over_option)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
+
+error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
+  --> $DIR/rename.rs:47:9
+   |
+LL | #![warn(clippy::for_loop_over_result)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
+
+error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
+  --> $DIR/rename.rs:48:9
+   |
+LL | #![warn(clippy::identity_conversion)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
+
+error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
+  --> $DIR/rename.rs:49:9
+   |
+LL | #![warn(clippy::zero_width_space)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
+
+error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
+  --> $DIR/rename.rs:50:9
+   |
+LL | #![warn(clippy::single_char_push_str)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
+
+error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
+  --> $DIR/rename.rs:51:9
+   |
+LL | #![warn(clippy::if_let_some_result)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
+
+error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
+  --> $DIR/rename.rs:53:9
+   |
+LL | #![warn(clippy::invalid_ref)]
+   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
+
+error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
+  --> $DIR/rename.rs:54:9
+   |
+LL | #![warn(clippy::into_iter_on_array)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
+
+error: lint `clippy::unused_label` has been renamed to `unused_labels`
+  --> $DIR/rename.rs:55:9
+   |
+LL | #![warn(clippy::unused_label)]
+   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
+
+error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
+  --> $DIR/rename.rs:56:9
+   |
+LL | #![warn(clippy::drop_bounds)]
+   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
+
+error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
+  --> $DIR/rename.rs:57:9
+   |
+LL | #![warn(clippy::temporary_cstring_as_ptr)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
+
+error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
+  --> $DIR/rename.rs:58:9
+   |
+LL | #![warn(clippy::panic_params)]
+   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
+
+error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
+  --> $DIR/rename.rs:59:9
+   |
+LL | #![warn(clippy::unknown_clippy_lints)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
+
+error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
+  --> $DIR/rename.rs:60:9
+   |
+LL | #![warn(clippy::invalid_atomic_ordering)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
+
+error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
+  --> $DIR/rename.rs:61:9
    |
-LL | #[warn(clippy::const_static_lifetime)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
+LL | #![warn(clippy::mem_discriminant_non_enum)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
-error: aborting due to 5 previous errors
+error: aborting due to 30 previous errors
 
index 9644a23296831bf1a67092feecba921180aa3ba7..7a45f1b18d4af2c8d920676b4f96b755083867d1 100644 (file)
@@ -98,3 +98,15 @@ fn unsafe_checks() {
     let mut s = MaybeUninit::<String>::uninit();
     let _d = || unsafe { ptr::drop_in_place(s.as_mut_ptr()) };
 }
+
+// Issue #7768
+#[rustfmt::skip]
+fn macro_with_semicolon() {
+    macro_rules! repro {
+        () => {
+            while false {
+            }
+        };
+    }
+    repro!();
+}
index 02e838456d0b574559f34404e79f22ffa158100e..55caef59f7f683f5509412a2065391fb211f4c03 100644 (file)
@@ -17,6 +17,11 @@ fn shadow_reuse() -> Option<()> {
     let x = foo(x);
     let x = || x;
     let x = Some(1).map(|_| x)?;
+    let y = 1;
+    let y = match y {
+        1 => 2,
+        _ => 3,
+    };
     None
 }
 
index 8b60e072c9342c9c763dc6b8de1740cef3f99dac..feed6e1ba8b8660ff2f73dc71a956fb135c62235 100644 (file)
@@ -47,7 +47,7 @@ note: previous binding is here
 LL |     let x = &mut x;
    |         ^
 
-error: `x` is shadowed by `x.0` which reuses the original value
+error: `x` is shadowed
   --> $DIR/shadow.rs:13:9
    |
 LL |     let x = x.0;
@@ -60,7 +60,7 @@ note: previous binding is here
 LL |     let x = ([[0]], ());
    |         ^
 
-error: `x` is shadowed by `x[0]` which reuses the original value
+error: `x` is shadowed
   --> $DIR/shadow.rs:14:9
    |
 LL |     let x = x[0];
@@ -72,7 +72,7 @@ note: previous binding is here
 LL |     let x = x.0;
    |         ^
 
-error: `x` is shadowed by `x` which reuses the original value
+error: `x` is shadowed
   --> $DIR/shadow.rs:15:10
    |
 LL |     let [x] = x;
@@ -84,7 +84,7 @@ note: previous binding is here
 LL |     let x = x[0];
    |         ^
 
-error: `x` is shadowed by `Some(x)` which reuses the original value
+error: `x` is shadowed
   --> $DIR/shadow.rs:16:9
    |
 LL |     let x = Some(x);
@@ -96,7 +96,7 @@ note: previous binding is here
 LL |     let [x] = x;
    |          ^
 
-error: `x` is shadowed by `foo(x)` which reuses the original value
+error: `x` is shadowed
   --> $DIR/shadow.rs:17:9
    |
 LL |     let x = foo(x);
@@ -108,7 +108,7 @@ note: previous binding is here
 LL |     let x = Some(x);
    |         ^
 
-error: `x` is shadowed by `|| x` which reuses the original value
+error: `x` is shadowed
   --> $DIR/shadow.rs:18:9
    |
 LL |     let x = || x;
@@ -120,7 +120,7 @@ note: previous binding is here
 LL |     let x = foo(x);
    |         ^
 
-error: `x` is shadowed by `Some(1).map(|_| x)?` which reuses the original value
+error: `x` is shadowed
   --> $DIR/shadow.rs:19:9
    |
 LL |     let x = Some(1).map(|_| x)?;
@@ -132,102 +132,114 @@ note: previous binding is here
 LL |     let x = || x;
    |         ^
 
+error: `y` is shadowed
+  --> $DIR/shadow.rs:21:9
+   |
+LL |     let y = match y {
+   |         ^
+   |
+note: previous binding is here
+  --> $DIR/shadow.rs:20:9
+   |
+LL |     let y = 1;
+   |         ^
+
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:25:9
+  --> $DIR/shadow.rs:30:9
    |
 LL |     let x = 2;
    |         ^
    |
    = note: `-D clippy::shadow-unrelated` implied by `-D warnings`
 note: previous binding is here
-  --> $DIR/shadow.rs:24:9
+  --> $DIR/shadow.rs:29:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:30:13
+  --> $DIR/shadow.rs:35:13
    |
 LL |         let x = 1;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:29:10
+  --> $DIR/shadow.rs:34:10
    |
 LL |     fn f(x: u32) {
    |          ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:35:14
+  --> $DIR/shadow.rs:40:14
    |
 LL |         Some(x) => {
    |              ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:32:9
+  --> $DIR/shadow.rs:37:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:36:17
+  --> $DIR/shadow.rs:41:17
    |
 LL |             let x = 1;
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:35:14
+  --> $DIR/shadow.rs:40:14
    |
 LL |         Some(x) => {
    |              ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:40:17
+  --> $DIR/shadow.rs:45:17
    |
 LL |     if let Some(x) = Some(1) {}
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:32:9
+  --> $DIR/shadow.rs:37:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:41:20
+  --> $DIR/shadow.rs:46:20
    |
 LL |     while let Some(x) = Some(1) {}
    |                    ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:32:9
+  --> $DIR/shadow.rs:37:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:42:15
+  --> $DIR/shadow.rs:47:15
    |
 LL |     let _ = |[x]: [u32; 1]| {
    |               ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:32:9
+  --> $DIR/shadow.rs:37:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:43:13
+  --> $DIR/shadow.rs:48:13
    |
 LL |         let x = 1;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:42:15
+  --> $DIR/shadow.rs:47:15
    |
 LL |     let _ = |[x]: [u32; 1]| {
    |               ^
 
-error: aborting due to 19 previous errors
+error: aborting due to 20 previous errors
 
index a7f8f54f2be04cb98667127b87d3db75c50e1301..d7e8d02bd1998fbab6b24867d1ec325556a6e72f 100644 (file)
@@ -1,5 +1,3 @@
-// edition:2018
-
 #![warn(clippy::all, clippy::pedantic)]
 #![allow(
     clippy::missing_errors_doc,
index 69a3390b03b0b2cac0988e1f35dc1796e0bcd41d..ea962f943173aed4359f392e9ee99de13e9b8ec4 100644 (file)
@@ -1,5 +1,3 @@
-// edition:2018
-
 #![warn(clippy::all, clippy::pedantic)]
 #![allow(
     clippy::missing_errors_doc,
index 86c63946516ce84453725eff5a31b58cb1ac246c..bf8b47d5626d283095c5df5db7ed86cccc2ffb40 100644 (file)
@@ -1,5 +1,5 @@
 error: method `add` can be confused for the standard trait method `std::ops::Add::add`
-  --> $DIR/method_list_1.rs:26:5
+  --> $DIR/method_list_1.rs:24:5
    |
 LL | /     pub fn add(self, other: T) -> T {
 LL | |         unimplemented!()
@@ -10,7 +10,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name
 
 error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut`
-  --> $DIR/method_list_1.rs:30:5
+  --> $DIR/method_list_1.rs:28:5
    |
 LL | /     pub fn as_mut(&mut self) -> &mut T {
 LL | |         unimplemented!()
@@ -20,7 +20,7 @@ LL | |     }
    = help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name
 
 error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref`
-  --> $DIR/method_list_1.rs:34:5
+  --> $DIR/method_list_1.rs:32:5
    |
 LL | /     pub fn as_ref(&self) -> &T {
 LL | |         unimplemented!()
@@ -30,7 +30,7 @@ LL | |     }
    = help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name
 
 error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand`
-  --> $DIR/method_list_1.rs:38:5
+  --> $DIR/method_list_1.rs:36:5
    |
 LL | /     pub fn bitand(self, rhs: T) -> T {
 LL | |         unimplemented!()
@@ -40,7 +40,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name
 
 error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor`
-  --> $DIR/method_list_1.rs:42:5
+  --> $DIR/method_list_1.rs:40:5
    |
 LL | /     pub fn bitor(self, rhs: Self) -> Self {
 LL | |         unimplemented!()
@@ -50,7 +50,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name
 
 error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor`
-  --> $DIR/method_list_1.rs:46:5
+  --> $DIR/method_list_1.rs:44:5
    |
 LL | /     pub fn bitxor(self, rhs: Self) -> Self {
 LL | |         unimplemented!()
@@ -60,7 +60,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name
 
 error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow`
-  --> $DIR/method_list_1.rs:50:5
+  --> $DIR/method_list_1.rs:48:5
    |
 LL | /     pub fn borrow(&self) -> &str {
 LL | |         unimplemented!()
@@ -70,7 +70,7 @@ LL | |     }
    = help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name
 
 error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut`
-  --> $DIR/method_list_1.rs:54:5
+  --> $DIR/method_list_1.rs:52:5
    |
 LL | /     pub fn borrow_mut(&mut self) -> &mut str {
 LL | |         unimplemented!()
@@ -80,7 +80,7 @@ LL | |     }
    = help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name
 
 error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone`
-  --> $DIR/method_list_1.rs:58:5
+  --> $DIR/method_list_1.rs:56:5
    |
 LL | /     pub fn clone(&self) -> Self {
 LL | |         unimplemented!()
@@ -90,7 +90,7 @@ LL | |     }
    = help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name
 
 error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp`
-  --> $DIR/method_list_1.rs:62:5
+  --> $DIR/method_list_1.rs:60:5
    |
 LL | /     pub fn cmp(&self, other: &Self) -> Self {
 LL | |         unimplemented!()
@@ -100,7 +100,7 @@ LL | |     }
    = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name
 
 error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref`
-  --> $DIR/method_list_1.rs:70:5
+  --> $DIR/method_list_1.rs:68:5
    |
 LL | /     pub fn deref(&self) -> &Self {
 LL | |         unimplemented!()
@@ -110,7 +110,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name
 
 error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut`
-  --> $DIR/method_list_1.rs:74:5
+  --> $DIR/method_list_1.rs:72:5
    |
 LL | /     pub fn deref_mut(&mut self) -> &mut Self {
 LL | |         unimplemented!()
@@ -120,7 +120,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name
 
 error: method `div` can be confused for the standard trait method `std::ops::Div::div`
-  --> $DIR/method_list_1.rs:78:5
+  --> $DIR/method_list_1.rs:76:5
    |
 LL | /     pub fn div(self, rhs: Self) -> Self {
 LL | |         unimplemented!()
@@ -130,7 +130,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name
 
 error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop`
-  --> $DIR/method_list_1.rs:82:5
+  --> $DIR/method_list_1.rs:80:5
    |
 LL | /     pub fn drop(&mut self) {
 LL | |         unimplemented!()
index 2cdc1a06fe689dab34e495eee9466253e7836c8d..b663568806d218dd9e8ac3bb6d2206acad140550 100644 (file)
@@ -1,5 +1,3 @@
-// edition:2018
-
 #![warn(clippy::all, clippy::pedantic)]
 #![allow(
     clippy::missing_errors_doc,
index 0142e2991081c79ae4099788ea6c85ed02535428..426fe3b1adc9de12e9ba88e9f51a034407d6d007 100644 (file)
@@ -1,5 +1,5 @@
 error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq`
-  --> $DIR/method_list_2.rs:27:5
+  --> $DIR/method_list_2.rs:25:5
    |
 LL | /     pub fn eq(&self, other: &Self) -> bool {
 LL | |         unimplemented!()
@@ -10,7 +10,7 @@ LL | |     }
    = help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name
 
 error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter`
-  --> $DIR/method_list_2.rs:31:5
+  --> $DIR/method_list_2.rs:29:5
    |
 LL | /     pub fn from_iter<T>(iter: T) -> Self {
 LL | |         unimplemented!()
@@ -20,7 +20,7 @@ LL | |     }
    = help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name
 
 error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
-  --> $DIR/method_list_2.rs:35:5
+  --> $DIR/method_list_2.rs:33:5
    |
 LL | /     pub fn from_str(s: &str) -> Result<Self, Self> {
 LL | |         unimplemented!()
@@ -30,7 +30,7 @@ LL | |     }
    = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
 
 error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash`
-  --> $DIR/method_list_2.rs:39:5
+  --> $DIR/method_list_2.rs:37:5
    |
 LL | /     pub fn hash(&self, state: &mut T) {
 LL | |         unimplemented!()
@@ -40,7 +40,7 @@ LL | |     }
    = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
 
 error: method `index` can be confused for the standard trait method `std::ops::Index::index`
-  --> $DIR/method_list_2.rs:43:5
+  --> $DIR/method_list_2.rs:41:5
    |
 LL | /     pub fn index(&self, index: usize) -> &Self {
 LL | |         unimplemented!()
@@ -50,7 +50,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name
 
 error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut`
-  --> $DIR/method_list_2.rs:47:5
+  --> $DIR/method_list_2.rs:45:5
    |
 LL | /     pub fn index_mut(&mut self, index: usize) -> &mut Self {
 LL | |         unimplemented!()
@@ -60,7 +60,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name
 
 error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`
-  --> $DIR/method_list_2.rs:51:5
+  --> $DIR/method_list_2.rs:49:5
    |
 LL | /     pub fn into_iter(self) -> Self {
 LL | |         unimplemented!()
@@ -70,7 +70,7 @@ LL | |     }
    = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name
 
 error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul`
-  --> $DIR/method_list_2.rs:55:5
+  --> $DIR/method_list_2.rs:53:5
    |
 LL | /     pub fn mul(self, rhs: Self) -> Self {
 LL | |         unimplemented!()
@@ -80,7 +80,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name
 
 error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg`
-  --> $DIR/method_list_2.rs:59:5
+  --> $DIR/method_list_2.rs:57:5
    |
 LL | /     pub fn neg(self) -> Self {
 LL | |         unimplemented!()
@@ -90,7 +90,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name
 
 error: method `next` can be confused for the standard trait method `std::iter::Iterator::next`
-  --> $DIR/method_list_2.rs:63:5
+  --> $DIR/method_list_2.rs:61:5
    |
 LL | /     pub fn next(&mut self) -> Option<Self> {
 LL | |         unimplemented!()
@@ -100,7 +100,7 @@ LL | |     }
    = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name
 
 error: method `not` can be confused for the standard trait method `std::ops::Not::not`
-  --> $DIR/method_list_2.rs:67:5
+  --> $DIR/method_list_2.rs:65:5
    |
 LL | /     pub fn not(self) -> Self {
 LL | |         unimplemented!()
@@ -110,7 +110,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name
 
 error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem`
-  --> $DIR/method_list_2.rs:71:5
+  --> $DIR/method_list_2.rs:69:5
    |
 LL | /     pub fn rem(self, rhs: Self) -> Self {
 LL | |         unimplemented!()
@@ -120,7 +120,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name
 
 error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl`
-  --> $DIR/method_list_2.rs:75:5
+  --> $DIR/method_list_2.rs:73:5
    |
 LL | /     pub fn shl(self, rhs: Self) -> Self {
 LL | |         unimplemented!()
@@ -130,7 +130,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name
 
 error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr`
-  --> $DIR/method_list_2.rs:79:5
+  --> $DIR/method_list_2.rs:77:5
    |
 LL | /     pub fn shr(self, rhs: Self) -> Self {
 LL | |         unimplemented!()
@@ -140,7 +140,7 @@ LL | |     }
    = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name
 
 error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub`
-  --> $DIR/method_list_2.rs:83:5
+  --> $DIR/method_list_2.rs:81:5
    |
 LL | /     pub fn sub(self, rhs: Self) -> Self {
 LL | |         unimplemented!()
index f66b445b7b6a35249600338185df6d6bb7774bb6..4c40739d6f553874865157ad7c9cb06a1051ea0a 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-// edition:2018
 #![warn(clippy::single_component_path_imports)]
 #![allow(unused_imports)]
 
index 09d4865859584ed792063e9e6bb510a1b679c012..9280bab3c71b5cae19b6d4f7e57b47bb7a5a478f 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-// edition:2018
 #![warn(clippy::single_component_path_imports)]
 #![allow(unused_imports)]
 
index 7005fa8f125d36255c12bf6c8b93cf6644f64eba..509c88ac256a8c0dc99ecdbcac0a8dd6fe97529f 100644 (file)
@@ -1,5 +1,5 @@
 error: this import is redundant
-  --> $DIR/single_component_path_imports.rs:24:5
+  --> $DIR/single_component_path_imports.rs:23:5
    |
 LL |     use regex;
    |     ^^^^^^^^^^ help: remove it entirely
@@ -7,7 +7,7 @@ LL |     use regex;
    = note: `-D clippy::single-component-path-imports` implied by `-D warnings`
 
 error: this import is redundant
-  --> $DIR/single_component_path_imports.rs:6:1
+  --> $DIR/single_component_path_imports.rs:5:1
    |
 LL | use regex;
    | ^^^^^^^^^^ help: remove it entirely
index 05863f9a2bf488c06722209622ceae63cce12de7..e43f5d381aaa1087a928a49d86529693a74fdba9 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-// edition:2018
 #![warn(clippy::single_component_path_imports)]
 #![allow(unused_imports)]
 
index 633deea348b81d415778fc372cae9a720c5c5ffc..3c65ca3054c6919eb859317608a43151ea71eb5c 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-// edition:2018
 #![warn(clippy::single_component_path_imports)]
 #![allow(unused_imports)]
 
index 239efb393b1ab4ac058a959ebe323044cad662f1..37d5176129ff30a2d06733b35c2b2c9b5404574f 100644 (file)
@@ -1,5 +1,5 @@
 error: this import is redundant
-  --> $DIR/single_component_path_imports_macro.rs:16:1
+  --> $DIR/single_component_path_imports_macro.rs:15:1
    |
 LL | use m2; // fail
    | ^^^^^^^ help: remove it entirely
index 94117061b270da718a68172b91b920c1c18c434b..c75beb747861882c0a158a46a92b67ca5af5af6e 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 #![warn(clippy::single_component_path_imports)]
 #![allow(unused_imports)]
 
index 0c3256c1ce43a71ea37159b4a65991603e493a59..cf990be1b9ff1cea7a0efe5c9509652b1a1ec271 100644 (file)
@@ -1,5 +1,5 @@
 error: this import is redundant
-  --> $DIR/single_component_path_imports_nested_first.rs:14:10
+  --> $DIR/single_component_path_imports_nested_first.rs:13:10
    |
 LL |     use {regex, serde};
    |          ^^^^^
@@ -8,7 +8,7 @@ LL |     use {regex, serde};
    = help: remove this import
 
 error: this import is redundant
-  --> $DIR/single_component_path_imports_nested_first.rs:14:17
+  --> $DIR/single_component_path_imports_nested_first.rs:13:17
    |
 LL |     use {regex, serde};
    |                 ^^^^^
@@ -16,7 +16,7 @@ LL |     use {regex, serde};
    = help: remove this import
 
 error: this import is redundant
-  --> $DIR/single_component_path_imports_nested_first.rs:5:1
+  --> $DIR/single_component_path_imports_nested_first.rs:4:1
    |
 LL | use regex;
    | ^^^^^^^^^^ help: remove it entirely
index 94319ade0ac4b9672ad2064bab6844db2e634887..48e8e530261bea39d8b1586d2f60cde8233ee65a 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 #![warn(clippy::single_component_path_imports)]
 #![allow(unused_imports)]
 
index c7437b234566a95f08dd4794f7cecc2af1430adf..4fb0cf40b6e00d40bb2c0345a28457af33695442 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 #![warn(clippy::single_component_path_imports)]
 #![allow(unused_imports)]
 
diff --git a/src/tools/clippy/tests/ui/string_slice.rs b/src/tools/clippy/tests/ui/string_slice.rs
new file mode 100644 (file)
index 0000000..be4dfc8
--- /dev/null
@@ -0,0 +1,10 @@
+#[warn(clippy::string_slice)]
+#[allow(clippy::no_effect)]
+
+fn main() {
+    &"Ölkanne"[1..];
+    let m = "Mötörhead";
+    &m[2..5];
+    let s = String::from(m);
+    &s[0..2];
+}
diff --git a/src/tools/clippy/tests/ui/string_slice.stderr b/src/tools/clippy/tests/ui/string_slice.stderr
new file mode 100644 (file)
index 0000000..55040bf
--- /dev/null
@@ -0,0 +1,22 @@
+error: indexing into a string may panic if the index is within a UTF-8 character
+  --> $DIR/string_slice.rs:5:6
+   |
+LL |     &"Ölkanne"[1..];
+   |      ^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::string-slice` implied by `-D warnings`
+
+error: indexing into a string may panic if the index is within a UTF-8 character
+  --> $DIR/string_slice.rs:7:6
+   |
+LL |     &m[2..5];
+   |      ^^^^^^^
+
+error: indexing into a string may panic if the index is within a UTF-8 character
+  --> $DIR/string_slice.rs:9:6
+   |
+LL |     &s[0..2];
+   |      ^^^^^^^
+
+error: aborting due to 3 previous errors
+
index eb8105c6b6da0f28a50ee521f4550e065a96de55..3ccdcd1117b5a5d47dcf87f95b30acbdba631e13 100644 (file)
@@ -1,5 +1,5 @@
 #![warn(clippy::to_string_in_display)]
-#![allow(clippy::inherent_to_string_shadow_display)]
+#![allow(clippy::inherent_to_string_shadow_display, clippy::to_string_in_format_args)]
 
 use std::fmt;
 
diff --git a/src/tools/clippy/tests/ui/trailing_empty_array.rs b/src/tools/clippy/tests/ui/trailing_empty_array.rs
new file mode 100644 (file)
index 0000000..501c9eb
--- /dev/null
@@ -0,0 +1,186 @@
+#![warn(clippy::trailing_empty_array)]
+#![feature(const_generics_defaults)]
+
+// Do lint:
+
+struct RarelyUseful {
+    field: i32,
+    last: [usize; 0],
+}
+
+struct OnlyField {
+    first_and_last: [usize; 0],
+}
+
+struct GenericArrayType<T> {
+    field: i32,
+    last: [T; 0],
+}
+
+#[must_use]
+struct OnlyAnotherAttribute {
+    field: i32,
+    last: [usize; 0],
+}
+
+#[derive(Debug)]
+struct OnlyADeriveAttribute {
+    field: i32,
+    last: [usize; 0],
+}
+
+const ZERO: usize = 0;
+struct ZeroSizedWithConst {
+    field: i32,
+    last: [usize; ZERO],
+}
+
+#[allow(clippy::eq_op)]
+const fn compute_zero() -> usize {
+    (4 + 6) - (2 * 5)
+}
+struct ZeroSizedWithConstFunction {
+    field: i32,
+    last: [usize; compute_zero()],
+}
+
+const fn compute_zero_from_arg(x: usize) -> usize {
+    x - 1
+}
+struct ZeroSizedWithConstFunction2 {
+    field: i32,
+    last: [usize; compute_zero_from_arg(1)],
+}
+
+struct ZeroSizedArrayWrapper([usize; 0]);
+
+struct TupleStruct(i32, [usize; 0]);
+
+struct LotsOfFields {
+    f1: u32,
+    f2: u32,
+    f3: u32,
+    f4: u32,
+    f5: u32,
+    f6: u32,
+    f7: u32,
+    f8: u32,
+    f9: u32,
+    f10: u32,
+    f11: u32,
+    f12: u32,
+    f13: u32,
+    f14: u32,
+    f15: u32,
+    f16: u32,
+    last: [usize; 0],
+}
+
+// Don't lint
+
+#[repr(C)]
+struct GoodReason {
+    field: i32,
+    last: [usize; 0],
+}
+
+#[repr(C)]
+struct OnlyFieldWithReprC {
+    first_and_last: [usize; 0],
+}
+
+struct NonZeroSizedArray {
+    field: i32,
+    last: [usize; 1],
+}
+
+struct NotLastField {
+    f1: u32,
+    zero_sized: [usize; 0],
+    last: i32,
+}
+
+const ONE: usize = 1;
+struct NonZeroSizedWithConst {
+    field: i32,
+    last: [usize; ONE],
+}
+
+#[derive(Debug)]
+#[repr(C)]
+struct AlsoADeriveAttribute {
+    field: i32,
+    last: [usize; 0],
+}
+
+#[must_use]
+#[repr(C)]
+struct AlsoAnotherAttribute {
+    field: i32,
+    last: [usize; 0],
+}
+
+#[repr(packed)]
+struct ReprPacked {
+    field: i32,
+    last: [usize; 0],
+}
+
+#[repr(C, packed)]
+struct ReprCPacked {
+    field: i32,
+    last: [usize; 0],
+}
+
+#[repr(align(64))]
+struct ReprAlign {
+    field: i32,
+    last: [usize; 0],
+}
+#[repr(C, align(64))]
+struct ReprCAlign {
+    field: i32,
+    last: [usize; 0],
+}
+
+// NOTE: because of https://doc.rust-lang.org/stable/reference/type-layout.html#primitive-representation-of-enums-with-fields and I'm not sure when in the compilation pipeline that would happen
+#[repr(C)]
+enum DontLintAnonymousStructsFromDesuraging {
+    A(u32),
+    B(f32, [u64; 0]),
+    C { x: u32, y: [u64; 0] },
+}
+
+#[repr(C)]
+struct TupleStructReprC(i32, [usize; 0]);
+
+type NamedTuple = (i32, [usize; 0]);
+
+#[rustfmt::skip] // [rustfmt#4995](https://github.com/rust-lang/rustfmt/issues/4995)
+struct ConstParamZeroDefault<const N: usize = 0> {
+    field: i32,
+    last: [usize; N],
+}
+
+struct ConstParamNoDefault<const N: usize> {
+    field: i32,
+    last: [usize; N],
+}
+
+#[rustfmt::skip] 
+struct ConstParamNonZeroDefault<const N: usize = 1> {
+    field: i32,
+    last: [usize; N],
+}
+
+struct TwoGenericParams<T, const N: usize> {
+    field: i32,
+    last: [T; N],
+}
+
+type A = ConstParamZeroDefault;
+type B = ConstParamZeroDefault<0>;
+type C = ConstParamNoDefault<0>;
+type D = ConstParamNonZeroDefault<0>;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/trailing_empty_array.stderr b/src/tools/clippy/tests/ui/trailing_empty_array.stderr
new file mode 100644 (file)
index 0000000..d88aa05
--- /dev/null
@@ -0,0 +1,120 @@
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+  --> $DIR/trailing_empty_array.rs:6:1
+   |
+LL | / struct RarelyUseful {
+LL | |     field: i32,
+LL | |     last: [usize; 0],
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::trailing-empty-array` implied by `-D warnings`
+   = help: consider annotating `RarelyUseful` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+  --> $DIR/trailing_empty_array.rs:11:1
+   |
+LL | / struct OnlyField {
+LL | |     first_and_last: [usize; 0],
+LL | | }
+   | |_^
+   |
+   = help: consider annotating `OnlyField` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+  --> $DIR/trailing_empty_array.rs:15:1
+   |
+LL | / struct GenericArrayType<T> {
+LL | |     field: i32,
+LL | |     last: [T; 0],
+LL | | }
+   | |_^
+   |
+   = help: consider annotating `GenericArrayType` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+  --> $DIR/trailing_empty_array.rs:21:1
+   |
+LL | / struct OnlyAnotherAttribute {
+LL | |     field: i32,
+LL | |     last: [usize; 0],
+LL | | }
+   | |_^
+   |
+   = help: consider annotating `OnlyAnotherAttribute` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+  --> $DIR/trailing_empty_array.rs:27:1
+   |
+LL | / struct OnlyADeriveAttribute {
+LL | |     field: i32,
+LL | |     last: [usize; 0],
+LL | | }
+   | |_^
+   |
+   = help: consider annotating `OnlyADeriveAttribute` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+  --> $DIR/trailing_empty_array.rs:33:1
+   |
+LL | / struct ZeroSizedWithConst {
+LL | |     field: i32,
+LL | |     last: [usize; ZERO],
+LL | | }
+   | |_^
+   |
+   = help: consider annotating `ZeroSizedWithConst` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+  --> $DIR/trailing_empty_array.rs:42:1
+   |
+LL | / struct ZeroSizedWithConstFunction {
+LL | |     field: i32,
+LL | |     last: [usize; compute_zero()],
+LL | | }
+   | |_^
+   |
+   = help: consider annotating `ZeroSizedWithConstFunction` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+  --> $DIR/trailing_empty_array.rs:50:1
+   |
+LL | / struct ZeroSizedWithConstFunction2 {
+LL | |     field: i32,
+LL | |     last: [usize; compute_zero_from_arg(1)],
+LL | | }
+   | |_^
+   |
+   = help: consider annotating `ZeroSizedWithConstFunction2` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+  --> $DIR/trailing_empty_array.rs:55:1
+   |
+LL | struct ZeroSizedArrayWrapper([usize; 0]);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider annotating `ZeroSizedArrayWrapper` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+  --> $DIR/trailing_empty_array.rs:57:1
+   |
+LL | struct TupleStruct(i32, [usize; 0]);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider annotating `TupleStruct` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+  --> $DIR/trailing_empty_array.rs:59:1
+   |
+LL | / struct LotsOfFields {
+LL | |     f1: u32,
+LL | |     f2: u32,
+LL | |     f3: u32,
+...  |
+LL | |     last: [usize; 0],
+LL | | }
+   | |_^
+   |
+   = help: consider annotating `LotsOfFields` with `#[repr(C)]` or another `repr` attribute
+
+error: aborting due to 11 previous errors
+
index bce4c81b78aa104709dd0a238f923a2f44de6451..6a7037d8f3826e962594836a03ee0ed9ffce9a7f 100644 (file)
@@ -103,6 +103,33 @@ const fn from_bits_64(v: u64) -> f64 {
     }
 }
 
+mod num_to_bytes {
+    fn test() {
+        unsafe {
+            let _: [u8; 1] = std::mem::transmute(0u8);
+            let _: [u8; 4] = std::mem::transmute(0u32);
+            let _: [u8; 16] = std::mem::transmute(0u128);
+            let _: [u8; 1] = std::mem::transmute(0i8);
+            let _: [u8; 4] = std::mem::transmute(0i32);
+            let _: [u8; 16] = std::mem::transmute(0i128);
+            let _: [u8; 4] = std::mem::transmute(0.0f32);
+            let _: [u8; 8] = std::mem::transmute(0.0f64);
+        }
+    }
+    const fn test_const() {
+        unsafe {
+            let _: [u8; 1] = std::mem::transmute(0u8);
+            let _: [u8; 4] = std::mem::transmute(0u32);
+            let _: [u8; 16] = std::mem::transmute(0u128);
+            let _: [u8; 1] = std::mem::transmute(0i8);
+            let _: [u8; 4] = std::mem::transmute(0i32);
+            let _: [u8; 16] = std::mem::transmute(0i128);
+            let _: [u8; 4] = std::mem::transmute(0.0f32);
+            let _: [u8; 8] = std::mem::transmute(0.0f64);
+        }
+    }
+}
+
 fn bytes_to_str(b: &[u8], mb: &mut [u8]) {
     let _: &str = unsafe { std::mem::transmute(b) };
     let _: &mut str = unsafe { std::mem::transmute(mb) };
index e31accb982af39e3d502d9cdb94f94d2633bccee..86537153e322897de816064f7b80041c88418c0d 100644 (file)
@@ -140,8 +140,94 @@ error: transmute from a `i64` to a `f64`
 LL |         let _: f64 = unsafe { std::mem::transmute(0_i64) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
 
+error: transmute from a `u8` to a `[u8; 1]`
+  --> $DIR/transmute.rs:109:30
+   |
+LL |             let _: [u8; 1] = std::mem::transmute(0u8);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
+   |
+   = note: `-D clippy::transmute-num-to-bytes` implied by `-D warnings`
+
+error: transmute from a `u32` to a `[u8; 4]`
+  --> $DIR/transmute.rs:110:30
+   |
+LL |             let _: [u8; 4] = std::mem::transmute(0u32);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
+
+error: transmute from a `u128` to a `[u8; 16]`
+  --> $DIR/transmute.rs:111:31
+   |
+LL |             let _: [u8; 16] = std::mem::transmute(0u128);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
+
+error: transmute from a `i8` to a `[u8; 1]`
+  --> $DIR/transmute.rs:112:30
+   |
+LL |             let _: [u8; 1] = std::mem::transmute(0i8);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
+
+error: transmute from a `i32` to a `[u8; 4]`
+  --> $DIR/transmute.rs:113:30
+   |
+LL |             let _: [u8; 4] = std::mem::transmute(0i32);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
+
+error: transmute from a `i128` to a `[u8; 16]`
+  --> $DIR/transmute.rs:114:31
+   |
+LL |             let _: [u8; 16] = std::mem::transmute(0i128);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
+
+error: transmute from a `f32` to a `[u8; 4]`
+  --> $DIR/transmute.rs:115:30
+   |
+LL |             let _: [u8; 4] = std::mem::transmute(0.0f32);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
+
+error: transmute from a `f64` to a `[u8; 8]`
+  --> $DIR/transmute.rs:116:30
+   |
+LL |             let _: [u8; 8] = std::mem::transmute(0.0f64);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
+
+error: transmute from a `u8` to a `[u8; 1]`
+  --> $DIR/transmute.rs:121:30
+   |
+LL |             let _: [u8; 1] = std::mem::transmute(0u8);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
+
+error: transmute from a `u32` to a `[u8; 4]`
+  --> $DIR/transmute.rs:122:30
+   |
+LL |             let _: [u8; 4] = std::mem::transmute(0u32);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
+
+error: transmute from a `u128` to a `[u8; 16]`
+  --> $DIR/transmute.rs:123:31
+   |
+LL |             let _: [u8; 16] = std::mem::transmute(0u128);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
+
+error: transmute from a `i8` to a `[u8; 1]`
+  --> $DIR/transmute.rs:124:30
+   |
+LL |             let _: [u8; 1] = std::mem::transmute(0i8);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
+
+error: transmute from a `i32` to a `[u8; 4]`
+  --> $DIR/transmute.rs:125:30
+   |
+LL |             let _: [u8; 4] = std::mem::transmute(0i32);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
+
+error: transmute from a `i128` to a `[u8; 16]`
+  --> $DIR/transmute.rs:126:31
+   |
+LL |             let _: [u8; 16] = std::mem::transmute(0i128);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
+
 error: transmute from a `&[u8]` to a `&str`
-  --> $DIR/transmute.rs:107:28
+  --> $DIR/transmute.rs:134:28
    |
 LL |     let _: &str = unsafe { std::mem::transmute(b) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()`
@@ -149,10 +235,10 @@ LL |     let _: &str = unsafe { std::mem::transmute(b) };
    = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings`
 
 error: transmute from a `&mut [u8]` to a `&mut str`
-  --> $DIR/transmute.rs:108:32
+  --> $DIR/transmute.rs:135:32
    |
 LL |     let _: &mut str = unsafe { std::mem::transmute(mb) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
 
-error: aborting due to 24 previous errors
+error: aborting due to 38 previous errors
 
diff --git a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs
new file mode 100644 (file)
index 0000000..5257732
--- /dev/null
@@ -0,0 +1,287 @@
+#![warn(clippy::undocumented_unsafe_blocks)]
+
+// Valid comments
+
+fn nested_local() {
+    let _ = {
+        let _ = {
+            // Safety:
+            let _ = unsafe {};
+        };
+    };
+}
+
+fn deep_nest() {
+    let _ = {
+        let _ = {
+            // Safety:
+            let _ = unsafe {};
+
+            // Safety:
+            unsafe {};
+
+            let _ = {
+                let _ = {
+                    let _ = {
+                        let _ = {
+                            let _ = {
+                                // Safety:
+                                let _ = unsafe {};
+
+                                // Safety:
+                                unsafe {};
+                            };
+                        };
+                    };
+
+                    // Safety:
+                    unsafe {};
+                };
+            };
+        };
+
+        // Safety:
+        unsafe {};
+    };
+
+    // Safety:
+    unsafe {};
+}
+
+fn local_tuple_expression() {
+    // Safety:
+    let _ = (42, unsafe {});
+}
+
+fn line_comment() {
+    // Safety:
+    unsafe {}
+}
+
+fn line_comment_newlines() {
+    // Safety:
+
+    unsafe {}
+}
+
+fn line_comment_empty() {
+    // Safety:
+    //
+    //
+    //
+    unsafe {}
+}
+
+fn line_comment_with_extras() {
+    // This is a description
+    // Safety:
+    unsafe {}
+}
+
+fn block_comment() {
+    /* Safety: */
+    unsafe {}
+}
+
+fn block_comment_newlines() {
+    /* Safety: */
+
+    unsafe {}
+}
+
+#[rustfmt::skip]
+fn inline_block_comment() {
+    /* Safety: */unsafe {}
+}
+
+fn block_comment_with_extras() {
+    /* This is a description
+     * Safety:
+     */
+    unsafe {}
+}
+
+fn block_comment_terminator_same_line() {
+    /* This is a description
+     * Safety: */
+    unsafe {}
+}
+
+fn buried_safety() {
+    // Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
+    // incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
+    // ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
+    // reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
+    // occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
+    // laborum. Safety:
+    // Tellus elementum sagittis vitae et leo duis ut diam quam. Sit amet nulla facilisi
+    // morbi tempus iaculis urna. Amet luctus venenatis lectus magna. At quis risus sed vulputate odio
+    // ut. Luctus venenatis lectus magna fringilla urna. Tortor id aliquet lectus proin nibh nisl
+    // condimentum id venenatis. Vulputate dignissim suspendisse in est ante in nibh mauris cursus.
+    unsafe {}
+}
+
+fn safety_with_prepended_text() {
+    // This is a test. Safety:
+    unsafe {}
+}
+
+fn local_line_comment() {
+    // Safety:
+    let _ = unsafe {};
+}
+
+fn local_block_comment() {
+    /* Safety: */
+    let _ = unsafe {};
+}
+
+fn comment_array() {
+    // Safety:
+    let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
+}
+
+fn comment_tuple() {
+    // Safety:
+    let _ = (42, unsafe {}, "test", unsafe {});
+}
+
+fn comment_unary() {
+    // Safety:
+    let _ = *unsafe { &42 };
+}
+
+#[allow(clippy::match_single_binding)]
+fn comment_match() {
+    // Safety:
+    let _ = match unsafe {} {
+        _ => {},
+    };
+}
+
+fn comment_addr_of() {
+    // Safety:
+    let _ = &unsafe {};
+}
+
+fn comment_repeat() {
+    // Safety:
+    let _ = [unsafe {}; 5];
+}
+
+fn comment_macro_call() {
+    macro_rules! t {
+        ($b:expr) => {
+            $b
+        };
+    }
+
+    t!(
+        // Safety:
+        unsafe {}
+    );
+}
+
+fn comment_macro_def() {
+    macro_rules! t {
+        () => {
+            // Safety:
+            unsafe {}
+        };
+    }
+
+    t!();
+}
+
+fn non_ascii_comment() {
+    // ॐ᧻໒ Safety: ௵∰
+    unsafe {};
+}
+
+fn local_commented_block() {
+    let _ =
+        // Safety:
+        unsafe {};
+}
+
+fn local_nest() {
+    // Safety:
+    let _ = [(42, unsafe {}, unsafe {}), (52, unsafe {}, unsafe {})];
+}
+
+// Invalid comments
+
+fn no_comment() {
+    unsafe {}
+}
+
+fn no_comment_array() {
+    let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
+}
+
+fn no_comment_tuple() {
+    let _ = (42, unsafe {}, "test", unsafe {});
+}
+
+fn no_comment_unary() {
+    let _ = *unsafe { &42 };
+}
+
+#[allow(clippy::match_single_binding)]
+fn no_comment_match() {
+    let _ = match unsafe {} {
+        _ => {},
+    };
+}
+
+fn no_comment_addr_of() {
+    let _ = &unsafe {};
+}
+
+fn no_comment_repeat() {
+    let _ = [unsafe {}; 5];
+}
+
+fn local_no_comment() {
+    let _ = unsafe {};
+}
+
+fn no_comment_macro_call() {
+    macro_rules! t {
+        ($b:expr) => {
+            $b
+        };
+    }
+
+    t!(unsafe {});
+}
+
+fn no_comment_macro_def() {
+    macro_rules! t {
+        () => {
+            unsafe {}
+        };
+    }
+
+    t!();
+}
+
+fn trailing_comment() {
+    unsafe {} // Safety:
+}
+
+fn internal_comment() {
+    unsafe {
+        // Safety:
+    }
+}
+
+fn interference() {
+    // Safety
+
+    let _ = 42;
+
+    unsafe {};
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr
new file mode 100644 (file)
index 0000000..613e9ff
--- /dev/null
@@ -0,0 +1,159 @@
+error: unsafe block missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:215:5
+   |
+LL |     unsafe {}
+   |     ^^^^^^^^^
+   |
+   = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
+help: consider adding a safety comment
+   |
+LL ~     // Safety: ...
+LL +     unsafe {}
+   |
+
+error: unsafe block missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:219:5
+   |
+LL |     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider adding a safety comment
+   |
+LL ~     // Safety: ...
+LL +     let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
+   |
+
+error: unsafe block missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:223:5
+   |
+LL |     let _ = (42, unsafe {}, "test", unsafe {});
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider adding a safety comment
+   |
+LL ~     // Safety: ...
+LL +     let _ = (42, unsafe {}, "test", unsafe {});
+   |
+
+error: unsafe block missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:227:5
+   |
+LL |     let _ = *unsafe { &42 };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider adding a safety comment
+   |
+LL ~     // Safety: ...
+LL +     let _ = *unsafe { &42 };
+   |
+
+error: unsafe block missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:232:5
+   |
+LL |     let _ = match unsafe {} {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider adding a safety comment
+   |
+LL ~     // Safety: ...
+LL +     let _ = match unsafe {} {
+   |
+
+error: unsafe block missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:238:5
+   |
+LL |     let _ = &unsafe {};
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+help: consider adding a safety comment
+   |
+LL ~     // Safety: ...
+LL +     let _ = &unsafe {};
+   |
+
+error: unsafe block missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:242:5
+   |
+LL |     let _ = [unsafe {}; 5];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider adding a safety comment
+   |
+LL ~     // Safety: ...
+LL +     let _ = [unsafe {}; 5];
+   |
+
+error: unsafe block missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:246:5
+   |
+LL |     let _ = unsafe {};
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+help: consider adding a safety comment
+   |
+LL ~     // Safety: ...
+LL +     let _ = unsafe {};
+   |
+
+error: unsafe block missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:256:8
+   |
+LL |     t!(unsafe {});
+   |        ^^^^^^^^^
+   |
+help: consider adding a safety comment
+   |
+LL ~     t!(// Safety: ...
+LL ~     unsafe {});
+   |
+
+error: unsafe block in macro expansion missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:262:13
+   |
+LL |             unsafe {}
+   |             ^^^^^^^^^
+...
+LL |     t!();
+   |     ---- in this macro invocation
+   |
+   = help: consider adding a safety comment in the macro definition
+   = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unsafe block missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:270:5
+   |
+LL |     unsafe {} // Safety:
+   |     ^^^^^^^^^
+   |
+help: consider adding a safety comment
+   |
+LL ~     // Safety: ...
+LL ~     unsafe {} // Safety:
+   |
+
+error: unsafe block missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:274:5
+   |
+LL |     unsafe {
+   |     ^^^^^^^^
+   |
+help: consider adding a safety comment
+   |
+LL ~     // Safety: ...
+LL +     unsafe {
+   |
+
+error: unsafe block missing a safety comment
+  --> $DIR/undocumented_unsafe_blocks.rs:284:5
+   |
+LL |     unsafe {};
+   |     ^^^^^^^^^
+   |
+help: consider adding a safety comment
+   |
+LL ~     // Safety: ...
+LL ~     unsafe {};
+   |
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/uninit_vec.rs b/src/tools/clippy/tests/ui/uninit_vec.rs
new file mode 100644 (file)
index 0000000..dc150cf
--- /dev/null
@@ -0,0 +1,94 @@
+#![warn(clippy::uninit_vec)]
+
+use std::mem::MaybeUninit;
+
+#[derive(Default)]
+struct MyVec {
+    vec: Vec<u8>,
+}
+
+fn main() {
+    // with_capacity() -> set_len() should be detected
+    let mut vec: Vec<u8> = Vec::with_capacity(1000);
+    unsafe {
+        vec.set_len(200);
+    }
+
+    // reserve() -> set_len() should be detected
+    vec.reserve(1000);
+    unsafe {
+        vec.set_len(200);
+    }
+
+    // new() -> set_len() should be detected
+    let mut vec: Vec<u8> = Vec::new();
+    unsafe {
+        vec.set_len(200);
+    }
+
+    // default() -> set_len() should be detected
+    let mut vec: Vec<u8> = Default::default();
+    unsafe {
+        vec.set_len(200);
+    }
+
+    let mut vec: Vec<u8> = Vec::default();
+    unsafe {
+        vec.set_len(200);
+    }
+
+    // test when both calls are enclosed in the same unsafe block
+    unsafe {
+        let mut vec: Vec<u8> = Vec::with_capacity(1000);
+        vec.set_len(200);
+
+        vec.reserve(1000);
+        vec.set_len(200);
+    }
+
+    let mut vec: Vec<u8> = Vec::with_capacity(1000);
+    unsafe {
+        // test the case where there are other statements in the following unsafe block
+        vec.set_len(200);
+        assert!(vec.len() == 200);
+    }
+
+    // handle vec stored in the field of a struct
+    let mut my_vec = MyVec::default();
+    my_vec.vec.reserve(1000);
+    unsafe {
+        my_vec.vec.set_len(200);
+    }
+
+    my_vec.vec = Vec::with_capacity(1000);
+    unsafe {
+        my_vec.vec.set_len(200);
+    }
+
+    // Test `#[allow(...)]` attributes on inner unsafe block (shouldn't trigger)
+    let mut vec: Vec<u8> = Vec::with_capacity(1000);
+    #[allow(clippy::uninit_vec)]
+    unsafe {
+        vec.set_len(200);
+    }
+
+    // MaybeUninit-wrapped types should not be detected
+    unsafe {
+        let mut vec: Vec<MaybeUninit<u8>> = Vec::with_capacity(1000);
+        vec.set_len(200);
+
+        let mut vec: Vec<(MaybeUninit<u8>, MaybeUninit<bool>)> = Vec::with_capacity(1000);
+        vec.set_len(200);
+
+        let mut vec: Vec<(MaybeUninit<u8>, [MaybeUninit<bool>; 2])> = Vec::with_capacity(1000);
+        vec.set_len(200);
+    }
+
+    // known false negative
+    let mut vec1: Vec<u8> = Vec::with_capacity(1000);
+    let mut vec2: Vec<u8> = Vec::with_capacity(1000);
+    unsafe {
+        vec1.set_len(200);
+        vec2.set_len(200);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/uninit_vec.stderr b/src/tools/clippy/tests/ui/uninit_vec.stderr
new file mode 100644 (file)
index 0000000..520bfb2
--- /dev/null
@@ -0,0 +1,105 @@
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+  --> $DIR/uninit_vec.rs:12:5
+   |
+LL |     let mut vec: Vec<u8> = Vec::with_capacity(1000);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe {
+LL |         vec.set_len(200);
+   |         ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::uninit-vec` implied by `-D warnings`
+   = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+  --> $DIR/uninit_vec.rs:18:5
+   |
+LL |     vec.reserve(1000);
+   |     ^^^^^^^^^^^^^^^^^^
+LL |     unsafe {
+LL |         vec.set_len(200);
+   |         ^^^^^^^^^^^^^^^^
+   |
+   = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` on empty `Vec` creates out-of-bound values
+  --> $DIR/uninit_vec.rs:24:5
+   |
+LL |     let mut vec: Vec<u8> = Vec::new();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe {
+LL |         vec.set_len(200);
+   |         ^^^^^^^^^^^^^^^^
+
+error: calling `set_len()` on empty `Vec` creates out-of-bound values
+  --> $DIR/uninit_vec.rs:30:5
+   |
+LL |     let mut vec: Vec<u8> = Default::default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe {
+LL |         vec.set_len(200);
+   |         ^^^^^^^^^^^^^^^^
+
+error: calling `set_len()` on empty `Vec` creates out-of-bound values
+  --> $DIR/uninit_vec.rs:35:5
+   |
+LL |     let mut vec: Vec<u8> = Vec::default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe {
+LL |         vec.set_len(200);
+   |         ^^^^^^^^^^^^^^^^
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+  --> $DIR/uninit_vec.rs:49:5
+   |
+LL |     let mut vec: Vec<u8> = Vec::with_capacity(1000);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |         vec.set_len(200);
+   |         ^^^^^^^^^^^^^^^^
+   |
+   = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+  --> $DIR/uninit_vec.rs:58:5
+   |
+LL |     my_vec.vec.reserve(1000);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe {
+LL |         my_vec.vec.set_len(200);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+  --> $DIR/uninit_vec.rs:63:5
+   |
+LL |     my_vec.vec = Vec::with_capacity(1000);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe {
+LL |         my_vec.vec.set_len(200);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+  --> $DIR/uninit_vec.rs:42:9
+   |
+LL |         let mut vec: Vec<u8> = Vec::with_capacity(1000);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         vec.set_len(200);
+   |         ^^^^^^^^^^^^^^^^
+   |
+   = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+  --> $DIR/uninit_vec.rs:45:9
+   |
+LL |         vec.reserve(1000);
+   |         ^^^^^^^^^^^^^^^^^^
+LL |         vec.set_len(200);
+   |         ^^^^^^^^^^^^^^^^
+   |
+   = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unit_hash.rs b/src/tools/clippy/tests/ui/unit_hash.rs
new file mode 100644 (file)
index 0000000..989916c
--- /dev/null
@@ -0,0 +1,27 @@
+#![warn(clippy::unit_hash)]
+
+use std::collections::hash_map::DefaultHasher;
+use std::hash::Hash;
+
+enum Foo {
+    Empty,
+    WithValue(u8),
+}
+
+fn do_nothing() {}
+
+fn main() {
+    let mut state = DefaultHasher::new();
+    let my_enum = Foo::Empty;
+
+    match my_enum {
+        Foo::Empty => ().hash(&mut state),
+        Foo::WithValue(x) => x.hash(&mut state),
+    }
+
+    let res = ();
+    res.hash(&mut state);
+
+    #[allow(clippy::unit_arg)]
+    do_nothing().hash(&mut state);
+}
diff --git a/src/tools/clippy/tests/ui/unit_hash.stderr b/src/tools/clippy/tests/ui/unit_hash.stderr
new file mode 100644 (file)
index 0000000..da27629
--- /dev/null
@@ -0,0 +1,27 @@
+error: this call to `hash` on the unit type will do nothing
+  --> $DIR/unit_hash.rs:18:23
+   |
+LL |         Foo::Empty => ().hash(&mut state),
+   |                       ^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)`
+   |
+   = note: `-D clippy::unit-hash` implied by `-D warnings`
+   = note: the implementation of `Hash` for `()` is a no-op
+
+error: this call to `hash` on the unit type will do nothing
+  --> $DIR/unit_hash.rs:23:5
+   |
+LL |     res.hash(&mut state);
+   |     ^^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)`
+   |
+   = note: the implementation of `Hash` for `()` is a no-op
+
+error: this call to `hash` on the unit type will do nothing
+  --> $DIR/unit_hash.rs:26:5
+   |
+LL |     do_nothing().hash(&mut state);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)`
+   |
+   = note: the implementation of `Hash` for `()` is a no-op
+
+error: aborting due to 3 previous errors
+
index b45b27d8f23b1a92bc006bc64104b97302beda7c..d806d620b176a3efd702bef0b00b0fb4755ce1dd 100644 (file)
@@ -2,6 +2,7 @@
 
 #![allow(clippy::stable_sort_primitive)]
 
+use std::cell::Ref;
 use std::cmp::Reverse;
 
 fn unnecessary_sort_by() {
@@ -33,6 +34,10 @@ fn unnecessary_sort_by() {
     // `Reverse(b)` would borrow in the following cases, don't lint
     vec.sort_by(|a, b| b.cmp(a));
     vec.sort_unstable_by(|a, b| b.cmp(a));
+
+    // No warning if element does not implement `Ord`
+    let mut vec: Vec<Ref<usize>> = Vec::new();
+    vec.sort_unstable_by(|a, b| a.cmp(b));
 }
 
 // Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key`
index be2abe7f7014d785b59ccae8875d550829a3ca23..6ee9c3af455dfbd39c98264d2f9f386b5bc8a85b 100644 (file)
@@ -2,6 +2,7 @@
 
 #![allow(clippy::stable_sort_primitive)]
 
+use std::cell::Ref;
 use std::cmp::Reverse;
 
 fn unnecessary_sort_by() {
@@ -33,6 +34,10 @@ fn id(x: isize) -> isize {
     // `Reverse(b)` would borrow in the following cases, don't lint
     vec.sort_by(|a, b| b.cmp(a));
     vec.sort_unstable_by(|a, b| b.cmp(a));
+
+    // No warning if element does not implement `Ord`
+    let mut vec: Vec<Ref<usize>> = Vec::new();
+    vec.sort_unstable_by(|a, b| a.cmp(b));
 }
 
 // Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key`
index 50607933e18f7b5ed5dc012a362eb03f9d910240..ca9641e880316533eda97e7f6904efccc7297380 100644 (file)
@@ -1,5 +1,5 @@
 error: use Vec::sort here instead
-  --> $DIR/unnecessary_sort_by.rs:14:5
+  --> $DIR/unnecessary_sort_by.rs:15:5
    |
 LL |     vec.sort_by(|a, b| a.cmp(b));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort()`
@@ -7,67 +7,67 @@ LL |     vec.sort_by(|a, b| a.cmp(b));
    = note: `-D clippy::unnecessary-sort-by` implied by `-D warnings`
 
 error: use Vec::sort here instead
-  --> $DIR/unnecessary_sort_by.rs:15:5
+  --> $DIR/unnecessary_sort_by.rs:16:5
    |
 LL |     vec.sort_unstable_by(|a, b| a.cmp(b));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable()`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:16:5
+  --> $DIR/unnecessary_sort_by.rs:17:5
    |
 LL |     vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs()));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (a + 5).abs())`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:17:5
+  --> $DIR/unnecessary_sort_by.rs:18:5
    |
 LL |     vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b)));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| id(-a))`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:20:5
+  --> $DIR/unnecessary_sort_by.rs:21:5
    |
 LL |     vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs()));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|b| Reverse((b + 5).abs()))`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:21:5
+  --> $DIR/unnecessary_sort_by.rs:22:5
    |
 LL |     vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a)));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|b| Reverse(id(-b)))`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:31:5
+  --> $DIR/unnecessary_sort_by.rs:32:5
    |
 LL |     vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (***a).abs())`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:32:5
+  --> $DIR/unnecessary_sort_by.rs:33:5
    |
 LL |     vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| (***a).abs())`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:88:9
+  --> $DIR/unnecessary_sort_by.rs:93:9
    |
 LL |         args.sort_by(|a, b| a.name().cmp(&b.name()));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|a| a.name())`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:89:9
+  --> $DIR/unnecessary_sort_by.rs:94:9
    |
 LL |         args.sort_unstable_by(|a, b| a.name().cmp(&b.name()));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|a| a.name())`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:91:9
+  --> $DIR/unnecessary_sort_by.rs:96:9
    |
 LL |         args.sort_by(|a, b| b.name().cmp(&a.name()));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|b| Reverse(b.name()))`
 
 error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:92:9
+  --> $DIR/unnecessary_sort_by.rs:97:9
    |
 LL |         args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|b| Reverse(b.name()))`
index 4f4203f5fdbf67fd59049f85769d322ae2ff73ba..2a3a506a57b1437310918767ad1fa55ab0987052 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 #![warn(clippy::unused_async)]
 
 async fn foo() -> i32 {
index 8b834d205b176970c8911b5f371c1282de83feb1..cc6096d65d9f351a016e0fcd7423ac12405ba587 100644 (file)
@@ -1,5 +1,5 @@
 error: unused `async` for function with no await statements
-  --> $DIR/unused_async.rs:4:1
+  --> $DIR/unused_async.rs:3:1
    |
 LL | / async fn foo() -> i32 {
 LL | |     4
index dcf818f80763052c6d4fae4d6e282b0b67c438c2..4e33e343ce0e9c414b42abf6d5e73d6b488392c6 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-// edition:2018
 // aux-build:proc_macro_derive.rs
 
 #![warn(clippy::use_self)]
index 9da6fef7a380c792781aceadb6ffbb2258395995..7b621ff9bcabf5be14250e8740311b04516047b8 100644 (file)
@@ -1,5 +1,4 @@
 // run-rustfix
-// edition:2018
 // aux-build:proc_macro_derive.rs
 
 #![warn(clippy::use_self)]
index e14368a11aa746eddd1fffeeb88c3bc36c35982d..ecb78b3f9721b0b575a4a153e08e9833f63917b5 100644 (file)
@@ -1,5 +1,5 @@
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:23:21
+  --> $DIR/use_self.rs:22:21
    |
 LL |         fn new() -> Foo {
    |                     ^^^ help: use the applicable keyword: `Self`
@@ -7,163 +7,163 @@ LL |         fn new() -> Foo {
    = note: `-D clippy::use-self` implied by `-D warnings`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:24:13
+  --> $DIR/use_self.rs:23:13
    |
 LL |             Foo {}
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:26:22
+  --> $DIR/use_self.rs:25:22
    |
 LL |         fn test() -> Foo {
    |                      ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:27:13
+  --> $DIR/use_self.rs:26:13
    |
 LL |             Foo::new()
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:32:25
+  --> $DIR/use_self.rs:31:25
    |
 LL |         fn default() -> Foo {
    |                         ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:33:13
+  --> $DIR/use_self.rs:32:13
    |
 LL |             Foo::new()
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:98:24
+  --> $DIR/use_self.rs:97:24
    |
 LL |         fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
    |                        ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:98:55
+  --> $DIR/use_self.rs:97:55
    |
 LL |         fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
    |                                                       ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:113:13
+  --> $DIR/use_self.rs:112:13
    |
 LL |             TS(0)
    |             ^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:148:29
+  --> $DIR/use_self.rs:147:29
    |
 LL |                 fn bar() -> Bar {
    |                             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:149:21
+  --> $DIR/use_self.rs:148:21
    |
 LL |                     Bar { foo: Foo {} }
    |                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:160:21
+  --> $DIR/use_self.rs:159:21
    |
 LL |         fn baz() -> Foo {
    |                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:161:13
+  --> $DIR/use_self.rs:160:13
    |
 LL |             Foo {}
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:178:21
+  --> $DIR/use_self.rs:177:21
    |
 LL |             let _ = Enum::B(42);
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:179:21
+  --> $DIR/use_self.rs:178:21
    |
 LL |             let _ = Enum::C { field: true };
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:180:21
+  --> $DIR/use_self.rs:179:21
    |
 LL |             let _ = Enum::A;
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:222:13
+  --> $DIR/use_self.rs:221:13
    |
 LL |             nested::A::fun_1();
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:223:13
+  --> $DIR/use_self.rs:222:13
    |
 LL |             nested::A::A;
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:225:13
+  --> $DIR/use_self.rs:224:13
    |
 LL |             nested::A {};
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:244:13
+  --> $DIR/use_self.rs:243:13
    |
 LL |             TestStruct::from_something()
    |             ^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:258:25
+  --> $DIR/use_self.rs:257:25
    |
 LL |         async fn g() -> S {
    |                         ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:259:13
+  --> $DIR/use_self.rs:258:13
    |
 LL |             S {}
    |             ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:263:16
+  --> $DIR/use_self.rs:262:16
    |
 LL |             &p[S::A..S::B]
    |                ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:263:22
+  --> $DIR/use_self.rs:262:22
    |
 LL |             &p[S::A..S::B]
    |                      ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:286:29
+  --> $DIR/use_self.rs:285:29
    |
 LL |         fn foo(value: T) -> Foo<T> {
    |                             ^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:287:13
+  --> $DIR/use_self.rs:286:13
    |
 LL |             Foo::<T> { value }
    |             ^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:459:13
+  --> $DIR/use_self.rs:458:13
    |
 LL |             A::new::<submod::B>(submod::B {})
    |             ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:496:13
+  --> $DIR/use_self.rs:495:13
    |
 LL |             S2::new()
    |             ^^ help: use the applicable keyword: `Self`
index d8bda7e8f48a7eb32cc22fc54c4cb5d24d1ffea8..21d66d5df79ecfa0a8b1727424d38ffb1134081f 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 // aux-build:proc_macro_derive.rs
 
 #![feature(rustc_private)]
index 2cbfc5ca2e2705e0bb618bfad420339277493f22..790b849210c9b35875ff2c9b8c4d47f4c54017cd 100644 (file)
@@ -1,5 +1,5 @@
 error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
-  --> $DIR/used_underscore_binding.rs:26:5
+  --> $DIR/used_underscore_binding.rs:25:5
    |
 LL |     _foo + 1
    |     ^^^^
@@ -7,31 +7,31 @@ LL |     _foo + 1
    = note: `-D clippy::used-underscore-binding` implied by `-D warnings`
 
 error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
-  --> $DIR/used_underscore_binding.rs:31:20
+  --> $DIR/used_underscore_binding.rs:30:20
    |
 LL |     println!("{}", _foo);
    |                    ^^^^
 
 error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
-  --> $DIR/used_underscore_binding.rs:32:16
+  --> $DIR/used_underscore_binding.rs:31:16
    |
 LL |     assert_eq!(_foo, _foo);
    |                ^^^^
 
 error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
-  --> $DIR/used_underscore_binding.rs:32:22
+  --> $DIR/used_underscore_binding.rs:31:22
    |
 LL |     assert_eq!(_foo, _foo);
    |                      ^^^^
 
 error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
-  --> $DIR/used_underscore_binding.rs:45:5
+  --> $DIR/used_underscore_binding.rs:44:5
    |
 LL |     s._underscore_field += 1;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
-  --> $DIR/used_underscore_binding.rs:100:16
+  --> $DIR/used_underscore_binding.rs:99:16
    |
 LL |         uses_i(_i);
    |                ^^
index 76aa82068d62e67bff5fbe7fc73c6a42e05f98a7..70ff08f36551838743b29d059c5d207a6f1593cd 100644 (file)
@@ -66,7 +66,7 @@ fn main() {
     let _ = vec![1, 2, 3].into_iter();
     let _: String = format!("Hello {}", "world");
 
-    // keep parenthesis around `a + b` for suggestion (see #4750)
+    // keep parentheses around `a + b` for suggestion (see #4750)
     let a: i32 = 1;
     let b: i32 = 1;
     let _ = (a + b) * 3;
index ccee7abb404e68aa3f993d917b70536b5acdf62f..f2444a8f436bf1a699e45cdee099846a261f9568 100644 (file)
@@ -66,7 +66,7 @@ fn main() {
     let _ = vec![1, 2, 3].into_iter().into_iter();
     let _: String = format!("Hello {}", "world").into();
 
-    // keep parenthesis around `a + b` for suggestion (see #4750)
+    // keep parentheses around `a + b` for suggestion (see #4750)
     let a: i32 = 1;
     let b: i32 = 1;
     let _ = i32::from(a + b) * 3;
index ee9c9045fff55940b42177b9eecef25bebe2b780..8402c33a4cd5fb695d37116caf003763dcf186bd 100644 (file)
@@ -1,8 +1,13 @@
+// edition:2015
 // run-rustfix
 // aux-build:wildcard_imports_helper.rs
 
+// the 2015 edition here is needed because edition 2018 changed the module system
+// (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
+// no longer detects some of the cases starting with Rust 2018.
+// FIXME: We should likely add another edition 2021 test case for this lint
+
 #![warn(clippy::wildcard_imports)]
-//#![allow(clippy::redundant_pub_crate)]
 #![allow(unused)]
 #![allow(clippy::unnecessary_wraps)]
 #![warn(unused_imports)]
@@ -230,4 +235,12 @@ mod super_imports {
             let _ = foofoo();
         }
     }
+
+    mod attestation_should_be_replaced {
+        use super::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
 }
index efaa8f9ef664186b0ba5e70a6d9cd4143bb31460..faaeaade9b02bff03b30793a73638ba5a3a560eb 100644 (file)
@@ -1,8 +1,13 @@
+// edition:2015
 // run-rustfix
 // aux-build:wildcard_imports_helper.rs
 
+// the 2015 edition here is needed because edition 2018 changed the module system
+// (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
+// no longer detects some of the cases starting with Rust 2018.
+// FIXME: We should likely add another edition 2021 test case for this lint
+
 #![warn(clippy::wildcard_imports)]
-//#![allow(clippy::redundant_pub_crate)]
 #![allow(unused)]
 #![allow(clippy::unnecessary_wraps)]
 #![warn(unused_imports)]
@@ -231,4 +236,12 @@ fn with_super_explicit() {
             let _ = foofoo();
         }
     }
+
+    mod attestation_should_be_replaced {
+        use super::*;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
 }
index 66267dd27b84fcf4da55e265ed164709a6e6647e..7534a65ec9bd56c0878846b81663d05ef269cb92 100644 (file)
@@ -1,5 +1,5 @@
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:12:5
+  --> $DIR/wildcard_imports.rs:17:5
    |
 LL | use crate::fn_mod::*;
    |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
@@ -7,85 +7,85 @@ LL | use crate::fn_mod::*;
    = note: `-D clippy::wildcard-imports` implied by `-D warnings`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:13:5
+  --> $DIR/wildcard_imports.rs:18:5
    |
 LL | use crate::mod_mod::*;
    |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:14:5
+  --> $DIR/wildcard_imports.rs:19:5
    |
 LL | use crate::multi_fn_mod::*;
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:16:5
+  --> $DIR/wildcard_imports.rs:21:5
    |
 LL | use crate::struct_mod::*;
    |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:20:5
+  --> $DIR/wildcard_imports.rs:25:5
    |
 LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:21:5
+  --> $DIR/wildcard_imports.rs:26:5
    |
 LL | use wildcard_imports_helper::*;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:92:13
+  --> $DIR/wildcard_imports.rs:97:13
    |
 LL |         use crate::fn_mod::*;
    |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:98:75
+  --> $DIR/wildcard_imports.rs:103:75
    |
 LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
    |                                                                           ^ help: try: `inner_extern_foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:99:13
+  --> $DIR/wildcard_imports.rs:104:13
    |
 LL |         use wildcard_imports_helper::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:110:20
+  --> $DIR/wildcard_imports.rs:115:20
    |
 LL |         use self::{inner::*, inner2::*};
    |                    ^^^^^^^^ help: try: `inner::inner_foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:110:30
+  --> $DIR/wildcard_imports.rs:115:30
    |
 LL |         use self::{inner::*, inner2::*};
    |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:117:13
+  --> $DIR/wildcard_imports.rs:122:13
    |
 LL |         use wildcard_imports_helper::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:146:9
+  --> $DIR/wildcard_imports.rs:151:9
    |
 LL |     use crate::in_fn_test::*;
    |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:155:9
+  --> $DIR/wildcard_imports.rs:160:9
    |
 LL |     use crate:: in_fn_test::  * ;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:156:9
+  --> $DIR/wildcard_imports.rs:161:9
    |
 LL |       use crate:: fn_mod::
    |  _________^
@@ -93,34 +93,40 @@ LL | |         *;
    | |_________^ help: try: `crate:: fn_mod::foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:167:13
+  --> $DIR/wildcard_imports.rs:172:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:202:17
+  --> $DIR/wildcard_imports.rs:207:17
    |
 LL |             use super::*;
    |                 ^^^^^^^^ help: try: `super::insidefoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:210:13
+  --> $DIR/wildcard_imports.rs:215:13
    |
 LL |         use super_imports::*;
    |             ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:219:17
+  --> $DIR/wildcard_imports.rs:224:17
    |
 LL |             use super::super::*;
    |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:228:13
+  --> $DIR/wildcard_imports.rs:233:13
    |
 LL |         use super::super::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
 
-error: aborting due to 20 previous errors
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:241:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
 
index 151dd0c27d57dbab4f7b4e98f485eb3993e10b3b..1b9da8a55e53fe8796ff7b92ee9b393db29b25bd 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 #![warn(clippy::wrong_self_convention)]
 #![allow(dead_code)]
 
index ce23317abf651f59f66ca971aeb15e1520355cfa..590ee6d9c529d6493b8e29b755c2d3e07f982b2b 100644 (file)
@@ -1,5 +1,5 @@
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:17:17
+  --> $DIR/wrong_self_convention.rs:16:17
    |
 LL |     fn from_i32(self) {}
    |                 ^^^^
@@ -8,7 +8,7 @@ LL |     fn from_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:23:21
+  --> $DIR/wrong_self_convention.rs:22:21
    |
 LL |     pub fn from_i64(self) {}
    |                     ^^^^
@@ -16,7 +16,7 @@ LL |     pub fn from_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:35:15
+  --> $DIR/wrong_self_convention.rs:34:15
    |
 LL |     fn as_i32(self) {}
    |               ^^^^
@@ -24,7 +24,7 @@ LL |     fn as_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:37:17
+  --> $DIR/wrong_self_convention.rs:36:17
    |
 LL |     fn into_i32(&self) {}
    |                 ^^^^^
@@ -32,7 +32,7 @@ LL |     fn into_i32(&self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:39:15
+  --> $DIR/wrong_self_convention.rs:38:15
    |
 LL |     fn is_i32(self) {}
    |               ^^^^
@@ -40,7 +40,7 @@ LL |     fn is_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention.rs:41:15
+  --> $DIR/wrong_self_convention.rs:40:15
    |
 LL |     fn to_i32(self) {}
    |               ^^^^
@@ -48,7 +48,7 @@ LL |     fn to_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:43:17
+  --> $DIR/wrong_self_convention.rs:42:17
    |
 LL |     fn from_i32(self) {}
    |                 ^^^^
@@ -56,7 +56,7 @@ LL |     fn from_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:45:19
+  --> $DIR/wrong_self_convention.rs:44:19
    |
 LL |     pub fn as_i64(self) {}
    |                   ^^^^
@@ -64,7 +64,7 @@ LL |     pub fn as_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:46:21
+  --> $DIR/wrong_self_convention.rs:45:21
    |
 LL |     pub fn into_i64(&self) {}
    |                     ^^^^^
@@ -72,7 +72,7 @@ LL |     pub fn into_i64(&self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:47:19
+  --> $DIR/wrong_self_convention.rs:46:19
    |
 LL |     pub fn is_i64(self) {}
    |                   ^^^^
@@ -80,7 +80,7 @@ LL |     pub fn is_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention.rs:48:19
+  --> $DIR/wrong_self_convention.rs:47:19
    |
 LL |     pub fn to_i64(self) {}
    |                   ^^^^
@@ -88,7 +88,7 @@ LL |     pub fn to_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:49:21
+  --> $DIR/wrong_self_convention.rs:48:21
    |
 LL |     pub fn from_i64(self) {}
    |                     ^^^^
@@ -96,7 +96,7 @@ LL |     pub fn from_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:94:19
+  --> $DIR/wrong_self_convention.rs:93:19
    |
 LL |         fn as_i32(self) {}
    |                   ^^^^
@@ -104,7 +104,7 @@ LL |         fn as_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:97:25
+  --> $DIR/wrong_self_convention.rs:96:25
    |
 LL |         fn into_i32_ref(&self) {}
    |                         ^^^^^
@@ -112,7 +112,7 @@ LL |         fn into_i32_ref(&self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:99:19
+  --> $DIR/wrong_self_convention.rs:98:19
    |
 LL |         fn is_i32(self) {}
    |                   ^^^^
@@ -120,7 +120,7 @@ LL |         fn is_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:103:21
+  --> $DIR/wrong_self_convention.rs:102:21
    |
 LL |         fn from_i32(self) {}
    |                     ^^^^
@@ -128,7 +128,7 @@ LL |         fn from_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:118:19
+  --> $DIR/wrong_self_convention.rs:117:19
    |
 LL |         fn as_i32(self);
    |                   ^^^^
@@ -136,7 +136,7 @@ LL |         fn as_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:121:25
+  --> $DIR/wrong_self_convention.rs:120:25
    |
 LL |         fn into_i32_ref(&self);
    |                         ^^^^^
@@ -144,7 +144,7 @@ LL |         fn into_i32_ref(&self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:123:19
+  --> $DIR/wrong_self_convention.rs:122:19
    |
 LL |         fn is_i32(self);
    |                   ^^^^
@@ -152,7 +152,7 @@ LL |         fn is_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:127:21
+  --> $DIR/wrong_self_convention.rs:126:21
    |
 LL |         fn from_i32(self);
    |                     ^^^^
@@ -160,7 +160,7 @@ LL |         fn from_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:145:25
+  --> $DIR/wrong_self_convention.rs:144:25
    |
 LL |         fn into_i32_ref(&self);
    |                         ^^^^^
@@ -168,7 +168,7 @@ LL |         fn into_i32_ref(&self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:151:21
+  --> $DIR/wrong_self_convention.rs:150:21
    |
 LL |         fn from_i32(self);
    |                     ^^^^
@@ -176,7 +176,7 @@ LL |         fn from_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:175:22
+  --> $DIR/wrong_self_convention.rs:174:22
    |
 LL |         fn to_u64_v2(&self) -> u64 {
    |                      ^^^^^
@@ -184,7 +184,7 @@ LL |         fn to_u64_v2(&self) -> u64 {
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention.rs:184:19
+  --> $DIR/wrong_self_convention.rs:183:19
    |
 LL |         fn to_u64(self) -> u64 {
    |                   ^^^^
index 0d827c1feb3e722c4842684a441f6386ee2f2eb5..a8fe8331133778ebcf934b4b234c07c430f484c9 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 #![warn(clippy::wrong_self_convention)]
 #![allow(dead_code)]
 
index 0e0d066d656b56a174ff00a9190927ca16abbf70..5bdc47f91f65b42b1376b18a7a661926c6d3805b 100644 (file)
@@ -1,5 +1,5 @@
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention2.rs:55:29
+  --> $DIR/wrong_self_convention2.rs:54:29
    |
 LL |         pub fn from_be_self(self) -> Self {
    |                             ^^^^
@@ -8,7 +8,7 @@ LL |         pub fn from_be_self(self) -> Self {
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention2.rs:64:25
+  --> $DIR/wrong_self_convention2.rs:63:25
    |
 LL |         fn from_be_self(self) -> Self;
    |                         ^^^^
index 486a0d772358531ca75e14eea62e41547ad294dd..5bb2116bd339af9ef01ddc281abb2d70416a5610 100644 (file)
@@ -1,4 +1,3 @@
-// edition:2018
 #![warn(clippy::wrong_self_convention)]
 #![allow(dead_code)]
 
index 6ce37c5949111bf20d20b66ffc00ad6170029a69..8665d8dc9a9dea4f7b1ed03b3b5a26084fdf11d3 100644 (file)
@@ -1,5 +1,5 @@
 error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_conventions_mut.rs:15:24
+  --> $DIR/wrong_self_conventions_mut.rs:14:24
    |
 LL |         pub fn to_many(&mut self) -> Option<&mut [T]> {
    |                        ^^^^^^^^^
@@ -8,7 +8,7 @@ LL |         pub fn to_many(&mut self) -> Option<&mut [T]> {
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `*_mut`) usually take `self` by mutable reference
-  --> $DIR/wrong_self_conventions_mut.rs:23:28
+  --> $DIR/wrong_self_conventions_mut.rs:22:28
    |
 LL |         pub fn to_many_mut(&self) -> Option<&[T]> {
    |                            ^^^^^
diff --git a/src/tools/clippy/tests/ui_test/eq_op.rs b/src/tools/clippy/tests/ui_test/eq_op.rs
new file mode 100644 (file)
index 0000000..f2f5f1e
--- /dev/null
@@ -0,0 +1,15 @@
+#[warn(clippy::eq_op)]
+#[test]
+fn eq_op_shouldnt_trigger_in_tests() {
+    let a = 1;
+    let result = a + 1 == 1 + a;
+    assert!(result);
+}
+
+#[test]
+fn eq_op_macros_shouldnt_trigger_in_tests() {
+    let a = 1;
+    let b = 2;
+    assert_eq!(a, a);
+    assert_eq!(a + b, b + a);
+}
index cd0a56d08d8bc6c72d7d5b38db0093f672047652..82fe790a576ab04c8fccc84af8bb1ebc1c1fcdb1 100644 (file)
@@ -349,6 +349,9 @@ pub struct Config {
     /// The current Rust channel
     pub channel: String,
 
+    /// The default Rust edition
+    pub edition: Option<String>,
+
     // Configuration for various run-make tests frobbing things like C compilers
     // or querying about various LLVM component information.
     pub cc: String,
index efd85502799595ab12fc6e31528a3a5510996b88..5fcaa452ca30e6eaf9278d3e0647fc98de15e09d 100644 (file)
@@ -222,6 +222,7 @@ pub fn from_file(testfile: &Path, cfg: Option<&str>, config: &Config) -> Self {
     /// `//[foo]`), then the property is ignored unless `cfg` is
     /// `Some("foo")`.
     fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
+        let mut has_edition = false;
         if !testfile.is_dir() {
             let file = File::open(testfile).unwrap();
 
@@ -240,9 +241,7 @@ fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
 
                 if let Some(edition) = config.parse_edition(ln) {
                     self.compile_flags.push(format!("--edition={}", edition));
-                    if edition == "2021" {
-                        self.compile_flags.push("-Zunstable-options".to_string());
-                    }
+                    has_edition = true;
                 }
 
                 config.parse_and_update_revisions(ln, &mut self.revisions);
@@ -391,6 +390,10 @@ fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
                 }
             }
         }
+
+        if let (Some(edition), false) = (&config.edition, has_edition) {
+            self.compile_flags.push(format!("--edition={}", edition));
+        }
     }
 
     fn update_fail_mode(&mut self, ln: &str, config: &Config) {
index 2485dbadab5bfdbb5bb6cb55f4ec336a90f98778..157b42e2d17f5a52f3bfdb8870178c7a0f28c7ba 100644 (file)
@@ -168,7 +168,7 @@ fn only_target() {
     let mut config = config();
     config.target = "x86_64-pc-windows-gnu".to_owned();
 
-    assert!(check_ignore(&config, "// only-i686"));
+    assert!(check_ignore(&config, "// only-x86"));
     assert!(check_ignore(&config, "// only-linux"));
     assert!(check_ignore(&config, "// only-msvc"));
     assert!(check_ignore(&config, "// only-32bit"));
index dc6d67983c5d22da7932f17b07ea77f1e386ba0e..a5ff779a4abfb5fda511554d944830ef90229128 100644 (file)
@@ -74,8 +74,6 @@ struct DiagnosticSpanMacroExpansion {
 struct DiagnosticCode {
     /// The code itself.
     code: String,
-    /// An explanation for the code.
-    explanation: Option<String>,
 }
 
 pub fn rustfix_diagnostics_only(output: &str) -> String {
index 87aba8c5d32bfcae9296c87804bc9853379094fc..58cde108b33221987b025fd0e5dcae64f8c5e8ff 100644 (file)
@@ -147,7 +147,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
         )
         .optflag("", "force-rerun", "rerun tests even if the inputs are unchanged")
         .optflag("h", "help", "show this message")
-        .reqopt("", "channel", "current Rust channel", "CHANNEL");
+        .reqopt("", "channel", "current Rust channel", "CHANNEL")
+        .optopt("", "edition", "default Rust edition", "EDITION");
 
     let (argv0, args_) = args.split_first().unwrap();
     if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
@@ -282,6 +283,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
         rustfix_coverage: matches.opt_present("rustfix-coverage"),
         has_tidy,
         channel: matches.opt_str("channel").unwrap(),
+        edition: matches.opt_str("edition"),
 
         cc: matches.opt_str("cc").unwrap(),
         cxx: matches.opt_str("cxx").unwrap(),
index 4470272a9f86672adcf1fbf168723040f89bd8e8..3c85b9076dd1af977591fc0fcbdcd6d54a3fbf01 100644 (file)
@@ -1607,9 +1607,6 @@ fn build_all_auxiliary(&self, rustc: &mut Command) -> PathBuf {
                 get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), is_dylib);
             rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir.display(), lib_name));
         }
-        if !self.props.aux_crates.is_empty() {
-            rustc.arg("-Zunstable-options");
-        }
 
         aux_dir
     }
index 94ebbb33e8d8ffad075cd6d06d3248e13e5ecf48..94e82e3d9f7664f993ea6fcb2db1e0a9a156d1df 100644 (file)
@@ -85,6 +85,8 @@
     ("core/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
     ("alloc/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
     ("std/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
+    ("core/primitive.str.html", &["begin</code>, <code>end"]),
+    ("std/primitive.str.html", &["begin</code>, <code>end"]),
 
 ];
 
index fa91a89193d26e6a86e2eee1cbaa38cb28ccebe1..9c18177cd36fe07a3c251234240a9c77a4e66785 160000 (submodule)
@@ -1 +1 @@
-Subproject commit fa91a89193d26e6a86e2eee1cbaa38cb28ccebe1
+Subproject commit 9c18177cd36fe07a3c251234240a9c77a4e66785
index ed4b312fa777ebb39ba1348fe3df574c441a485e..04f03a360ab8fef3d9c0ff84de2d39b8a196c717 160000 (submodule)
@@ -1 +1 @@
-Subproject commit ed4b312fa777ebb39ba1348fe3df574c441a485e
+Subproject commit 04f03a360ab8fef3d9c0ff84de2d39b8a196c717
index bb9cd00f3f5829196df0a2a93d12274d82702f8a..a673e425dfff9d41610b59ae14f014486f911018 100644 (file)
@@ -414,7 +414,7 @@ function parseOptions(args) {
         "test_folder": "",
         "test_file": "",
     };
-    var correspondances = {
+    var correspondences = {
         "--resource-suffix": "resource_suffix",
         "--doc-folder": "doc_folder",
         "--test-folder": "test_folder",
@@ -423,17 +423,13 @@ function parseOptions(args) {
     };
 
     for (var i = 0; i < args.length; ++i) {
-        if (args[i] === "--resource-suffix"
-            || args[i] === "--doc-folder"
-            || args[i] === "--test-folder"
-            || args[i] === "--test-file"
-            || args[i] === "--crate-name") {
+        if (correspondences.hasOwnProperty(args[i])) {
             i += 1;
             if (i >= args.length) {
                 console.log("Missing argument after `" + args[i - 1] + "` option.");
                 return null;
             }
-            opts[correspondances[args[i - 1]]] = args[i];
+            opts[correspondences[args[i - 1]]] = args[i];
         } else if (args[i] === "--help") {
             showHelp();
             process.exit(0);
index 9a5fd0dd1d31b84ae98d1ff8dfaddaacba29aeed..f4dd394445301c165bc285166a12974c44381931 100644 (file)
@@ -1,8 +1,10 @@
 name: upload
 
 on:
+  push:
   release:
     types: [created]
+  workflow_dispatch:
 
 jobs:
   build-release:
@@ -14,42 +16,40 @@ jobs:
           - build: linux-x86_64
             os: ubuntu-latest
             rust: nightly
+            target: x86_64-unknown-linux-gnu
           - build: macos-x86_64
             os: macos-latest
             rust: nightly
+            target: x86_64-apple-darwin
           - build: windows-x86_64-gnu
             os: windows-latest
             rust: nightly-x86_64-gnu
+            target: x86_64-pc-windows-gnu
           - build: windows-x86_64-msvc
             os: windows-latest
             rust: nightly-x86_64-msvc
+            target: x86_64-pc-windows-msvc
     runs-on: ${{ matrix.os }}
     steps:
       - uses: actions/checkout@v2
 
-      - name: Install Rust
-        uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: ${{ matrix.rust }}
-          override: true
+        # Run build
+      - name: install rustup
+        run: |
+          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
+          sh rustup-init.sh -y --default-toolchain none
+          rustup target add ${{ matrix.target }}
 
       - name: Add mingw64 to path for x86_64-gnu
         run: echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH
         if: matrix.rust == 'nightly-x86_64-gnu'
         shell: bash
 
-      - name: Install cargo-make
-        uses: actions-rs/cargo@v1
-        with:
-          command: install
-          args: --force cargo-make
-
       - name: Build release binaries
         uses: actions-rs/cargo@v1
         with:
-          command: make
-          args: release
+          command: build
+          args: --release
 
       - name: Build archive
         shell: bash
@@ -70,6 +70,7 @@ jobs:
           fi
 
       - name: Upload Release Asset
+        if: github.event_name == 'release'
         uses: actions/upload-release-asset@v1
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
index 08cb52eedaea789ad2550f97e11e6dd92e2f2f37..c05e8d4896ac707d2c23b24d12eda006355a01be 100644 (file)
@@ -54,9 +54,6 @@ jobs:
       if: matrix.target == 'x86_64-pc-windows-gnu' && matrix.channel == 'nightly'
       shell: bash
 
-    - name: cargo-make
-      run: cargo install --force cargo-make
-
     - name: build
       run: |
         rustc -Vv
index 37adf8751ca8f91fb041bcdbf31845632114562c..71cf88f79e67b674ecf7abc54035fabaa4c84539 100644 (file)
@@ -5,6 +5,7 @@
 # Generated by Cargo
 # will have compiled files and executables
 /target
+tests/cargo-fmt/**/target
 
 # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
 # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
index 68354b6ceaf25aa1a973050c358bac6baaf823fe..b59438dc4fe78a11483f61b2c69b875a006c2f16 100644 (file)
@@ -2,6 +2,73 @@
 
 ## [Unreleased]
 
+## [1.4.38] 2021-10-20
+
+### Changed
+
+- Switched from `rustc-ap-*` crates to `rustc_private` for consumption model of rustc internals
+- `annotate-snippets` updated to v0.8 [PR #4762](https://github.com/rust-lang/rustfmt/pull/4762)
+- Greatly improved the performance of `cargo fmt` in large workspaces utilizing the `--all` flag by updating to a newer version of `cargo_metadata` that leverages updated `cargo` output from v1.51+ [PR #4997](https://github.com/rust-lang/rustfmt/pull/4997)
+- Improved formatting of long slice patterns [#4530](https://github.com/rust-lang/rustfmt/issues/4530)
+  - **Note you must have `version = Two` in your configuration to take advantage of the new formatting**
+- Stabilized `match_block_trailing_comma` configuration option [#3380](https://github.com/rust-lang/rustfmt/issues/3380) - [https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#match_block_trailing_comma](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#match_block_trailing_comma)
+- Stabilized `disable_all_formatting` configuration option [#5026](https://github.com/rust-lang/rustfmt/pull/5026) - [https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#disable_all_formatting](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#disable_all_formatting)
+- Various improvements to the configuration documentation website [https://rust-lang.github.io/rustfmt/?version=v1.4.38]([https://rust-lang.github.io/rustfmt/?version=v1.4.38])
+- Addressed various clippy and rustc warnings
+
+
+### Fixed
+
+- Resolved issue where specious whitespace would be inserted when a block style comment was terminated within string literal processing [#4312](https://github.com/rust-lang/rustfmt/issues/4312)
+- Nested out-of-line mods are again parsed and formatted [#4874](https://github.com/rust-lang/rustfmt/issues/4874)
+- Accepts `2021` for edition value from rustfmt command line [PR #4847](https://github.com/rust-lang/rustfmt/pull/4847)
+- Unstable command line options are no longer displayed in `--help` text on stable [PR #4798](https://github.com/rust-lang/rustfmt/issues/4798)
+- Stopped panicking on patterns in match arms which start with non-ascii characters [#4868](https://github.com/rust-lang/rustfmt/issues/4868)
+- Stopped stripping defaults on const params [#4816](https://github.com/rust-lang/rustfmt/issues/4816)
+- Fixed issue with dropped content with GAT aliases with self bounds in impls [#4911](https://github.com/rust-lang/rustfmt/issues/4911)
+- Stopped removing generic args on associated type constraints [#4943](https://github.com/rust-lang/rustfmt/issues/4943)
+- Stopped dropping visibility on certain trait and impl items [#4960](https://github.com/rust-lang/rustfmt/issues/4960)
+- Fixed dropping of qualified paths in struct patterns [#4908](https://github.com/rust-lang/rustfmt/issues/4908) and [#5005](https://github.com/rust-lang/rustfmt/issues/5005)
+- Fixed bug in line width calculation that was causing specious formatting of certain patterns [#4031](https://github.com/rust-lang/rustfmt/issues/4031)
+  - **Note that this bug fix may cause observable formatting changes in cases where code had been formatted with prior versions of rustfmt that contained the bug**
+- Fixed bug where rustfmt would drop parameter attributes if they were too long in certain cases [#4579](https://github.com/rust-lang/rustfmt/issues/4579)
+- Resolved idempotency issue with extern body elements [#4963](https://github.com/rust-lang/rustfmt/issues/4963)
+- rustfmt will now handle doc-style comments on function parameters, since they could appear with certain macro usage patterns even though it's generally invalid syntax [#4936](https://github.com/rust-lang/rustfmt/issues/4936)
+- Fixed bug in `match_block_trailing_comma` where commas were not added to the blocks of bodies whose arm had a guard that did not fit on the same line as the pattern [#4998](https://github.com/rust-lang/rustfmt/pull/4998)
+- Fixed bug in cases where derive attributes started with a block style comment [#4984](https://github.com/rust-lang/rustfmt/issues/4984)
+- Fixed issue where the struct rest could be lost when `struct_field_align_threshold` was enabled [#4926](https://github.com/rust-lang/rustfmt/issues/4926)
+- Handles cases where certain control flow type expressions have comments between patterns/keywords and the pattern ident contains the keyword [#5009](https://github.com/rust-lang/rustfmt/issues/5009)
+- Handles tuple structs that have explicit visibilities and start with a block style comment [#5011](https://github.com/rust-lang/rustfmt/issues/5011)
+- Handles leading line-style comments in certain types of macro calls [#4615](https://github.com/rust-lang/rustfmt/issues/4615)
+
+
+### Added
+- Granular width heuristic options made available for user control [PR #4782](https://github.com/rust-lang/rustfmt/pull/4782). This includes the following:
+  - [`array_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#array_width)
+  - [`attr_fn_like_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#attr_fn_like_width)
+  - [`chain_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#chain_width)
+  - [`fn_call_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#fn_call_width)
+  - [`single_line_if_else_max_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#single_line_if_else_max_width)
+  - [`struct_lit_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#struct_lit_width)
+  - [`struct_variant_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#struct_variant_width)
+
+Note this hit the rustup distributions prior to the v1.4.38 release as part of an out-of-cycle updates, but is listed in this version because the feature was not in the other v1.4.37 releases. See also the `use_small_heuristics` section on the configuration site for more information
+[https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#use_small_heuristics](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#use_small_heuristics)
+
+- New `One` variant added to `imports_granularity` configuration option which can be used to reformat all imports into a single use statement [#4669](https://github.com/rust-lang/rustfmt/issues/4669)
+- rustfmt will now skip files that are annotated with `@generated` at the top of the file [#3958](https://github.com/rust-lang/rustfmt/issues/3958)
+- New configuration option `hex_literal_case` that allows user to control the casing utilized for hex literals [PR #4903](https://github.com/rust-lang/rustfmt/pull/4903)
+
+See the section on the configuration site for more information
+https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#hex_literal_case
+
+- `cargo fmt` now directly supports the `--check` flag, which means it's now possible to run `cargo fmt --check` instead of the more verbose `cargo fmt -- --check` [#3888](https://github.com/rust-lang/rustfmt/issues/3888)
+
+### Install/Download Options
+- **rustup (nightly)** - *pending*
+- **GitHub Release Binaries** - [Release v1.4.38](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.38)
+- **Build from source** - [Tag v1.4.38](https://github.com/rust-lang/rustfmt/tree/v1.4.38), see instructions for how to [install rustfmt from source][install-from-source]
+
 ## [1.4.37] 2021-04-03
 
 ### Changed
index 03bb5598007ce55779b26c9276be46586bc94425..2ef83ddd1ae6c1b6e89361f47705a00304bb1c0f 100644 (file)
@@ -35,21 +35,6 @@ version = "1.0.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14"
 
-[[package]]
-name = "arrayref"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
-
-[[package]]
-name = "arrayvec"
-version = "0.4.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
-dependencies = [
- "nodrop",
-]
-
 [[package]]
 name = "atty"
 version = "0.2.13"
@@ -62,40 +47,9 @@ dependencies = [
 
 [[package]]
 name = "autocfg"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
-
-[[package]]
-name = "backtrace"
-version = "0.3.40"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
-dependencies = [
- "backtrace-sys",
- "cfg-if 0.1.10",
- "libc",
- "rustc-demangle",
-]
-
-[[package]]
-name = "backtrace-sys"
-version = "0.1.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
-name = "base64"
-version = "0.10.1"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
-dependencies = [
- "byteorder",
-]
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 
 [[package]]
 name = "bitflags"
@@ -103,17 +57,6 @@ version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
 
-[[package]]
-name = "blake2b_simd"
-version = "0.5.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182"
-dependencies = [
- "arrayref",
- "arrayvec",
- "constant_time_eq",
-]
-
 [[package]]
 name = "bstr"
 version = "0.2.8"
@@ -125,36 +68,43 @@ dependencies = [
 
 [[package]]
 name = "bytecount"
-version = "0.6.0"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0017894339f586ccb943b01b9555de56770c11cda818e7e3d8bd93f4ed7f46e"
+checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e"
 dependencies = [
- "packed_simd",
+ "packed_simd_2",
 ]
 
 [[package]]
-name = "byteorder"
-version = "1.3.2"
+name = "camino"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
+checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b"
+dependencies = [
+ "serde",
+]
 
 [[package]]
-name = "cargo_metadata"
-version = "0.8.2"
+name = "cargo-platform"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426"
+checksum = "0226944a63d1bf35a3b5f948dd7c59e263db83695c9e8bffc4037de02e30f1d7"
 dependencies = [
- "semver",
  "serde",
- "serde_derive",
- "serde_json",
 ]
 
 [[package]]
-name = "cc"
-version = "1.0.46"
+name = "cargo_metadata"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c"
+checksum = "c297bd3135f558552f99a0daa180876984ea2c4ffa7470314540dff8c654109a"
+dependencies = [
+ "camino",
+ "cargo-platform",
+ "semver",
+ "serde",
+ "serde_json",
+]
 
 [[package]]
 name = "cfg-if"
@@ -183,48 +133,14 @@ dependencies = [
  "vec_map",
 ]
 
-[[package]]
-name = "cloudabi"
-version = "0.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
-dependencies = [
- "bitflags",
-]
-
-[[package]]
-name = "constant_time_eq"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120"
-
-[[package]]
-name = "crossbeam-channel"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c"
-dependencies = [
- "crossbeam-utils 0.7.0",
-]
-
 [[package]]
 name = "crossbeam-utils"
-version = "0.6.6"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
-dependencies = [
- "cfg-if 0.1.10",
- "lazy_static",
-]
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
+checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
 dependencies = [
  "autocfg",
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "lazy_static",
 ]
 
@@ -257,11 +173,10 @@ dependencies = [
 
 [[package]]
 name = "dirs-sys"
-version = "0.3.4"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
+checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
 dependencies = [
- "cfg-if 0.1.10",
  "libc",
  "redox_users",
  "winapi",
@@ -275,9 +190,9 @@ checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
 
 [[package]]
 name = "env_logger"
-version = "0.6.2"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
+checksum = "54532e3223c5af90a6a757c90b5c5521564b07e5e7a958681bcd2afad421cdcd"
 dependencies = [
  "atty",
  "humantime",
@@ -286,40 +201,12 @@ dependencies = [
  "termcolor",
 ]
 
-[[package]]
-name = "failure"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9"
-dependencies = [
- "backtrace",
- "failure_derive",
-]
-
-[[package]]
-name = "failure_derive"
-version = "0.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "synstructure",
-]
-
 [[package]]
 name = "fnv"
 version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
 
-[[package]]
-name = "fuchsia-cprng"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
-
 [[package]]
 name = "getopts"
 version = "0.2.21"
@@ -329,11 +216,22 @@ dependencies = [
  "unicode-width",
 ]
 
+[[package]]
+name = "getrandom"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "wasi",
+]
+
 [[package]]
 name = "globset"
-version = "0.4.4"
+version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2"
+checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a"
 dependencies = [
  "aho-corasick",
  "bstr",
@@ -353,36 +251,33 @@ dependencies = [
 
 [[package]]
 name = "humantime"
-version = "1.3.0"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
-dependencies = [
- "quick-error",
-]
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
 [[package]]
 name = "ignore"
-version = "0.4.11"
+version = "0.4.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "522daefc3b69036f80c7d2990b28ff9e0471c683bad05ca258e0a01dd22c5a1e"
+checksum = "b287fb45c60bb826a0dc68ff08742b9d88a2fea13d6e0c286b3172065aaf878c"
 dependencies = [
- "crossbeam-channel",
+ "crossbeam-utils",
  "globset",
  "lazy_static",
  "log",
  "memchr",
  "regex",
  "same-file",
- "thread_local 1.0.1",
+ "thread_local",
  "walkdir",
  "winapi-util",
 ]
 
 [[package]]
 name = "itertools"
-version = "0.8.0"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
+checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
 dependencies = [
  "either",
 ]
@@ -405,6 +300,12 @@ version = "0.2.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
 
+[[package]]
+name = "libm"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
+
 [[package]]
 name = "log"
 version = "0.4.14"
@@ -421,18 +322,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
 
 [[package]]
-name = "nodrop"
-version = "0.1.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
-
-[[package]]
-name = "packed_simd"
-version = "0.3.3"
+name = "packed_simd_2"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
+checksum = "3278e0492f961fd4ae70909f56b2723a7e8d01a228427294e19cdfdebda89a17"
 dependencies = [
  "cfg-if 0.1.10",
+ "libm",
 ]
 
 [[package]]
@@ -463,19 +359,13 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.6"
+version = "1.0.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
+checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
 dependencies = [
  "unicode-xid",
 ]
 
-[[package]]
-name = "quick-error"
-version = "1.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
-
 [[package]]
 name = "quote"
 version = "1.0.6"
@@ -486,95 +376,41 @@ dependencies = [
 ]
 
 [[package]]
-name = "rand_core"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
-dependencies = [
- "rand_core 0.4.2",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
-
-[[package]]
-name = "rand_os"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
-dependencies = [
- "cloudabi",
- "fuchsia-cprng",
- "libc",
- "rand_core 0.4.2",
- "rdrand",
- "winapi",
-]
-
-[[package]]
-name = "rdrand"
-version = "0.4.0"
+name = "redox_syscall"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
+checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570"
 dependencies = [
- "rand_core 0.3.1",
+ "bitflags",
 ]
 
-[[package]]
-name = "redox_syscall"
-version = "0.1.56"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
-
 [[package]]
 name = "redox_users"
-version = "0.3.1"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d"
+checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
 dependencies = [
- "failure",
- "rand_os",
+ "getrandom",
  "redox_syscall",
- "rust-argon2",
 ]
 
 [[package]]
 name = "regex"
-version = "1.3.1"
+version = "1.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
+checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
 dependencies = [
  "aho-corasick",
  "memchr",
  "regex-syntax",
- "thread_local 0.3.6",
+ "thread_local",
 ]
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
-
-[[package]]
-name = "rust-argon2"
-version = "0.5.1"
+version = "0.6.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf"
-dependencies = [
- "base64",
- "blake2b_simd",
- "crossbeam-utils 0.6.6",
-]
-
-[[package]]
-name = "rustc-demangle"
-version = "0.1.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
+checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
 
 [[package]]
 name = "rustc-workspace-hack"
@@ -593,7 +429,7 @@ dependencies = [
 
 [[package]]
 name = "rustfmt-nightly"
-version = "1.4.37"
+version = "1.4.38"
 dependencies = [
  "annotate-snippets",
  "anyhow",
@@ -639,34 +475,27 @@ dependencies = [
 
 [[package]]
 name = "semver"
-version = "0.9.0"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
 dependencies = [
- "semver-parser",
  "serde",
 ]
 
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-
 [[package]]
 name = "serde"
-version = "1.0.101"
+version = "1.0.126"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
+checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.101"
+version = "1.0.126"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
+checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -675,9 +504,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.41"
+version = "1.0.59"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
+checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
 dependencies = [
  "itoa",
  "ryu",
@@ -716,9 +545,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.11"
+version = "1.0.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
+checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -736,18 +565,6 @@ dependencies = [
  "syn",
 ]
 
-[[package]]
-name = "synstructure"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "unicode-xid",
-]
-
 [[package]]
 name = "term"
 version = "0.6.1"
@@ -796,15 +613,6 @@ dependencies = [
  "syn",
 ]
 
-[[package]]
-name = "thread_local"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
-dependencies = [
- "lazy_static",
-]
-
 [[package]]
 name = "thread_local"
 version = "1.0.1"
@@ -870,6 +678,12 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
 [[package]]
 name = "winapi"
 version = "0.3.8"
index 7b4667c17c8647cd3e6f7ddacf33a077df20b531..8d9c4a7fb20cd93264f5459a7997cb9ca7cbc4df 100644 (file)
@@ -1,7 +1,7 @@
 [package]
 
 name = "rustfmt-nightly"
-version = "1.4.37"
+version = "1.4.38"
 description = "Tool to find and fix Rust formatting issues"
 repository = "https://github.com/rust-lang/rustfmt"
 readme = "README.md"
@@ -33,7 +33,7 @@ rustfmt-format-diff = []
 generic-simd = ["bytecount/generic-simd"]
 
 [dependencies]
-itertools = "0.8"
+itertools = "0.9"
 toml = "0.5"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
@@ -42,15 +42,15 @@ regex = "1.0"
 term = "0.6"
 diff = "0.1"
 log = "0.4.14"
-env_logger = "0.6"
+env_logger = "0.8"
 getopts = "0.2"
 derive-new = "0.5"
-cargo_metadata = "0.8"
+cargo_metadata = "0.14"
 bytecount = "0.6"
 unicode-width = "0.1.5"
 unicode_categories = "0.1.1"
 dirs = "2.0.1"
-ignore = "0.4.11"
+ignore = "0.4.17"
 annotate-snippets = { version = "0.8", features = ["color"] }
 structopt = "0.3"
 rustfmt-config_proc_macro = { version = "0.2", path = "config_proc_macro" }
index d2e5613eba964cc62a543864da940f7cc1bbb60b..7a77dbe154b60f2f55224cfeae2cb41f2127c53c 100644 (file)
@@ -521,11 +521,13 @@ fn main() {
 
 ## `disable_all_formatting`
 
-Don't reformat anything
+Don't reformat anything.
+
+Note that this option may be soft-deprecated in the future once the [ignore](#ignore) option is stabilized. Nightly toolchain users are encouraged to use [ignore](#ignore) instead when possible.
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3388)
+- **Stable**: Yes
 
 ## `edition`
 
@@ -924,6 +926,15 @@ 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.
+
+- **Default value**: `false`
+- **Possible values**: `true`, `false`
+- **Stable**: No
+
 ## `format_macro_matchers`
 
 Format the metavariable matching patterns in macros.
@@ -1047,6 +1058,13 @@ fn lorem() -> usize {
 
 See also: [`tab_spaces`](#tab_spaces).
 
+## `hex_literal_case`
+
+Control the case of the letters in hexadecimal literal values
+
+- **Default value**: `Preserve`
+- **Possible values**: `Upper`, `Lower`
+- **Stable**: No
 
 ## `hide_parse_errors`
 
@@ -1610,7 +1628,7 @@ Put a trailing comma after a block based match arm (non-block arms are not affec
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3380)
+- **Stable**: Yes
 
 #### `false` (default):
 
@@ -1668,6 +1686,9 @@ pub enum Foo {}
 #### `false`:
 
 ```rust
+#[derive(Eq, PartialEq, Debug, Copy, Clone)]
+pub enum Bar {}
+
 #[derive(Eq, PartialEq)]
 #[derive(Debug)]
 #[derive(Copy, Clone)]
@@ -1679,7 +1700,7 @@ pub enum Foo {}
 How imports should be grouped into `use` statements. Imports will be merged or split to the configured level of granularity.
 
 - **Default value**: `Preserve`
-- **Possible values**: `Preserve`, `Crate`, `Module`, `Item`
+- **Possible values**: `Preserve`, `Crate`, `Module`, `Item`, `One`
 - **Stable**: No
 
 #### `Preserve` (default):
@@ -1733,6 +1754,23 @@ use qux::h;
 use qux::i;
 ```
 
+#### `One`:
+
+Merge all imports into a single `use` statement as long as they have the same visibility.
+
+```rust
+pub use foo::{x, y};
+use {
+    bar::{
+        a,
+        b::{self, f, g},
+        c,
+        d::e,
+    },
+    qux::{h, i},
+};
+```
+
 ## `merge_imports`
 
 This option is deprecated. Use `imports_granularity = "Crate"` instead.
@@ -1824,6 +1862,9 @@ Convert `#![doc]` and `#[doc]` attributes to `//!` and `///` doc comments.
 #![doc = "Example documentation"]
 
 #[doc = "Example item documentation"]
+pub enum Bar {}
+
+/// Example item documentation
 pub enum Foo {}
 ```
 
@@ -1938,6 +1979,8 @@ fn main() {
 #### `false`:
 ```rust
 fn main() {
+    (foo());
+
     ((((foo()))));
 }
 ```
@@ -1963,6 +2006,14 @@ impl Iterator for Dummy {
 
     type Item = i32;
 }
+
+impl Iterator for Dummy {
+    type Item = i32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        None
+    }
+}
 ```
 
 #### `true`
@@ -2519,7 +2570,8 @@ fn main() {
     let x = 1;
     let y = 2;
     let z = 3;
-    let a = Foo { x: x, y: y, z: z };
+    let a = Foo { x, y, z };
+    let b = Foo { x: x, y: y, z: z };
 }
 ```
 
@@ -2688,6 +2740,8 @@ Replace uses of the try! macro by the ? shorthand
 
 ```rust
 fn main() {
+    let lorem = ipsum.map(|dolor| dolor.sit())?;
+
     let lorem = try!(ipsum.map(|dolor| dolor.sit()));
 }
 ```
@@ -2759,6 +2813,12 @@ Break comments to fit on the line
 #### `false` (default):
 
 ```rust
+// Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+// sed do eiusmod tempor incididunt ut labore et dolore
+// magna aliqua. Ut enim ad minim veniam, quis nostrud
+// exercitation ullamco laboris nisi ut aliquip ex ea
+// commodo consequat.
+
 // Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
 ```
 
index 5ac99fd71f8f87efcf51346e7f8f3fda43dc9d76..b3dda091e0a9607e75c79e3551c1ae59f85c60df 100644 (file)
@@ -1,55 +1,8 @@
-# This is based on https://github.com/japaric/rust-everywhere/blob/master/appveyor.yml
-# and modified (mainly removal of deployment) to suit rustfmt.
-
 environment:
   global:
     PROJECT_NAME: rustfmt
-  matrix:
-    # Stable channel
-    # - TARGET: i686-pc-windows-gnu
-    #   CHANNEL: stable
-    # - TARGET: i686-pc-windows-msvc
-    #   CHANNEL: stable
-    # - TARGET: x86_64-pc-windows-gnu
-    #   CHANNEL: stable
-    # - TARGET: x86_64-pc-windows-msvc
-    #   CHANNEL: stable
-    # Beta channel
-    # - TARGET: i686-pc-windows-gnu
-    #   CHANNEL: beta
-    # - TARGET: i686-pc-windows-msvc
-    #   CHANNEL: beta
-    # - TARGET: x86_64-pc-windows-gnu
-    #   CHANNEL: beta
-    # - TARGET: x86_64-pc-windows-msvc
-    #   CHANNEL: beta
-    # Nightly channel
-    - TARGET: i686-pc-windows-gnu
-      CHANNEL: nightly
-    - TARGET: i686-pc-windows-msvc
-      CHANNEL: nightly
-    - TARGET: x86_64-pc-windows-gnu
-      CHANNEL: nightly
-    - TARGET: x86_64-pc-windows-msvc
-      CHANNEL: nightly
-
-# Install Rust and Cargo
-# (Based on from https://github.com/rust-lang/libc/blob/master/appveyor.yml)
-install:
-  - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
-  - if "%TARGET%" == "i686-pc-windows-gnu" set PATH=%PATH%;C:\msys64\mingw32\bin
-  - if "%TARGET%" == "x86_64-pc-windows-gnu" set PATH=%PATH%;C:\msys64\mingw64\bin
-  - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
-  - rustup-init.exe --default-host %TARGET% --default-toolchain %CHANNEL% -y
-  - rustc -Vv
-  - cargo -V
 
-# ???
 build: false
 
 test_script:
-  - set CFG_RELEASE_CHANNEL=nightly
-  - set CFG_RELEASE=nightly
-  - cargo build --verbose
-  - cargo test
-  - cargo test -- --ignored
+  - echo Why does no one have access to delete me?
index 56d1917e2b61b211eb8ae3112f07e93ea1cdf0c9..4fa932d4c762ee77ae19489a6c62d05bc64c27c2 100644 (file)
@@ -2,9 +2,13 @@
 <html>
     <head>
       <meta name="viewport" content="width=device-width">
+      <title>Rustfmt</title>
       <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/3.0.1/github-markdown.css" />
+      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/styles/github-gist.min.css">
       <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
       <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
+      <script src="https://unpkg.com/vue-async-computed@3.8.1"></script>
+      <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/highlight.min.js"></script>
       <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
       <style>
         @media (max-width: 767px) {
         .searchCondition > div {
           margin-right: 30px;
         }
+        .header-link {
+          position: relative;
+        }
+        .header-link:hover::before {
+          position: absolute;
+          left: -2em;
+          padding-right: 0.5em;
+          content: '\2002\00a7\2002';
+        }
       </style>
     </head>
     <body>
                   <label for="stable">stable: </label>
                   <input type="checkbox" id="stable" v-model="shouldStable">
               </div>
+              <div>
+                  <label for="viewVersion">version: </label>
+                  <select name="viewVersion" id="viewVersion" v-model="viewVersion">
+                    <option v-for="option in versionOptions" v-bind:value="option">
+                      {{ option }}
+                    </option>
+                  </select>
+              </div>
             </div>
             <div v-html="aboutHtml"></div>
             <div v-html="configurationAboutHtml"></div>
           </article>
         </div>
         <script>
-            const ConfigurationMdUrl = 'https://raw.githubusercontent.com/rust-lang/rustfmt/master/Configurations.md';
+            const RusfmtTagsUrl = 'https://api.github.com/repos/rust-lang/rustfmt/tags';
+            const RustfmtLatestUrl = 'https://api.github.com/repos/rust-lang/rustfmt/releases/latest';
             const UrlHash = window.location.hash.replace(/^#/, '');
+            const queryParams = new URLSearchParams(window.location.search);
+            const searchParam = queryParams.get('search');
+            const searchTerm = null !== searchParam ? searchParam : '';
+            const versionParam = queryParams.get('version');
+            const parseVersionParam = (version) => {
+              if (version === 'master') return 'master';
+              if (version.startsWith('v')) return version;
+              return `v${version}`;
+            };
+            const versionNumber = null !== versionParam ? parseVersionParam(versionParam) : 'master';
             new Vue({
               el: '#app',
-              data() {
-                const configurationDescriptions = [];
-                configurationDescriptions.links = {};
-                return {
-                  aboutHtml: '',
-                  configurationAboutHtml: '',
-                  searchCondition: UrlHash,
-                  configurationDescriptions,
-                  shouldStable: false
-                }
+              data: {
+                aboutHtml: '',
+                configurationAboutHtml: '',
+                configurationDescriptions: [],
+                searchCondition: searchTerm,
+                shouldStable: false,
+                viewVersion: versionNumber,
+                oldViewVersion: undefined,
+                versionOptions: ['master'],
+                scrolledOnce: false,
               },
-              computed: {
-                outputHtml() {
-                  const ast = this.configurationDescriptions
-                                  .filter(({ head, text, stable }) => {
+              asyncComputed: {
+                async updateVersion() {
+                  let latest;
+                  try {
+                    latest = (await axios.get(RustfmtLatestUrl)).data;
+                  } catch(err) {
+                      console.log(err);
+                    return;
+                  }
+                  if (versionParam == null) {
+                    this.viewVersion = latest.name;
+                  }
+                },
+                async outputHtml() {
+                  if (this.viewVersion !== this.oldViewVersion) {
+                    const ConfigurationMdUrl =
+                      `https://raw.githubusercontent.com/rust-lang/rustfmt/${this.viewVersion}/Configurations.md`;
+                    let res;
+                    try {
+                      res = await axios.get(ConfigurationMdUrl).catch(e => { throw e });
+                    } catch(e) {
+                      this.handleReqFailure(e);
+                      return;
+                    }
+                    const {
+                      about,
+                      configurationAbout,
+                      configurationDescriptions
+                    } = parseMarkdownAst(res.data);
+                    this.aboutHtml = marked.parser(about);
+                    this.configurationAboutHtml = marked.parser(configurationAbout);
+                    this.configurationDescriptions = configurationDescriptions;
+                    this.oldViewVersion = this.viewVersion;
+                  }
 
-                                    if (
-                                      text.includes(this.searchCondition) === false &&
-                                      head.includes(this.searchCondition) === false
-                                    ) {
-                                      return false;
-                                    }
-                                    return (this.shouldStable)
-                                      ? stable === true
-                                      : true;
-                                  })
-                                  .reduce((stack, { value }) => {
-                                    return stack.concat(value);
-                                  }, []);
+                  const ast = this.configurationDescriptions
+                      .filter(({ head, text, stable }) => {
+                        if (text.includes(this.searchCondition) === false &&
+                          head.includes(this.searchCondition) === false) {
+                          return false;
+                        }
+                        return (this.shouldStable)
+                          ? stable === true
+                          : true;
+                      })
+                      .reduce((stack, { value }) => {
+                        return stack.concat(value);
+                      }, []);
                   ast.links = {};
-                  return marked.parser(ast);
+
+                  queryParams.set('version', this.viewVersion);
+                  queryParams.set('search', this.searchCondition);
+                  const curUrl = window.location.pathname +
+                    '?' + queryParams.toString() + window.location.hash;
+                  history.pushState(null, '', curUrl);
+
+                  const renderer = new marked.Renderer();
+                  renderer.heading = function(text, level) {
+                    const id = htmlToId(text);
+                    return `<h${level}>
+                              <a id="${id}" href="#${id}" name="${id}" class="header-link">${text}</a>
+                            </h${level}>`;
+                  };
+
+                  return marked.parser(ast, {
+                    highlight(code, lang) {
+                      return hljs.highlight(lang ? lang : 'rust', code).value;
+                    },
+                    headerIds: true,
+                    headerPrefix: '',
+                    renderer,
+                  });
                 }
               },
               created: async function() {
-                const res = await axios.get(ConfigurationMdUrl);
-                const {
-                  about,
-                  configurationAbout,
-                  configurationDescriptions
-                } = parseMarkdownAst(res.data);
-                this.aboutHtml = marked.parser(about);
-                this.configurationAboutHtml = marked.parser(configurationAbout);
-                this.configurationDescriptions = configurationDescriptions;
+                let tags;
+                try {
+                  tags = (await axios.get(RusfmtTagsUrl)).data;
+                } catch(e) {
+                  this.handleReqFailure(e);
+                  return;
+                }
+
+                const excludedTagVersions = new Set(['v0.7', 'v0.8.1']);
+
+                const tagOptions = tags
+                  .map(tag => tag.name)
+                  .filter(tag => tag.startsWith('v') && !excludedTagVersions.has(tag));
+                this.versionOptions = this.versionOptions.concat(tagOptions);
               },
-              mounted() {
+              updated() {
                 if (UrlHash === '') return;
-                const interval = setInterval(() => {
+                this.$nextTick(() => {
                   const target = document.querySelector(`#${UrlHash}`);
-                  if (target != null) {
+                  if (target != null && !this.scrolledOnce) {
                     target.scrollIntoView(true);
-                    clearInterval(interval);
+                    this.scrolledOnce = true;
                   }
-                }, 100);
+                });
+              },
+              methods: {
+                handleReqFailure(e) {
+                  if (e.response.status === 404) {
+                    this.aboutHtml =
+                      "<p>Failed to get configuration options for this version, please select the version from the dropdown above.</p>";
+                  } else if (
+                    e.response.status === 403 &&
+                    e.response.headers["X-RateLimit-Remaining"] === 0
+                  ) {
+                    const resetDate = new Date(
+                      e.response.headers['X-RateLimit-Reset'] * 1000
+                    ).toLocaleString();
+                    this.aboutHtml =
+                      `<p>You have hit the GitHub API rate limit; documentation cannot be updated.` +
+                      `<p>The rate limit will be reset at ${resetDate}.</p>`;
+                  } else {
+                    this.aboutHtml =
+                      `<p>Ecountered an error when fetching documentation data:</p>` +
+                      `<pre><code>${e.response.data}</code></pre>` +
+                      `<p>We would appreciate <a href="https://github.com/rust-lang/rustfmt/issues/new?template=bug_report.md">a bug report</a>.` +
+                      `<p>Try refreshing the page.</p>`;
+                  }
+                }
               }
             });
             const extractDepthOnes = (ast) => {
                     head: val[0].text,
                     value: val,
                     stable: val.some((elem) => {
-                      return !!elem.text && elem.text.includes("**Stable**: Yes")
+                      return elem.type === "list" &&
+                        !!elem.raw &&
+                        elem.raw.includes("**Stable**: Yes");
                     }),
                     text: val.reduce((result, next) => {
                       return next.text != null
                 configurationDescriptions
               };
             }
+            function htmlToId(text) {
+              const tmpl = document.createElement('template');
+              tmpl.innerHTML = text.trim();
+              return encodeURIComponent(CSS.escape(tmpl.content.textContent));
+            }
         </script>
     </body>
-</html>
\ No newline at end of file
+</html>
index b0cd4464df8e5107f4e674ff8a6a403c9a01d5fe..b19ecbdb07c4f425540264a618144618e7acbcab 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-07-23"
+channel = "nightly-2021-10-20"
 components = ["rustc-dev"]
index 315eb10a9dbc0eeb5f720949cf0b0d6b95d75f7a..a5982820e3ded6f2de868975ac9003ee441623f4 100644 (file)
@@ -13,6 +13,7 @@
 use crate::overflow;
 use crate::rewrite::{Rewrite, RewriteContext};
 use crate::shape::Shape;
+use crate::source_map::SpanUtils;
 use crate::types::{rewrite_path, PathContext};
 use crate::utils::{count_newlines, mk_sp};
 
@@ -116,7 +117,9 @@ fn format_derive(
                 |span| span.lo(),
                 |span| span.hi(),
                 |span| Some(context.snippet(*span).to_owned()),
-                attr.span.lo(),
+                // We update derive attribute spans to start after the opening '('
+                // This helps us focus parsing to just what's inside #[derive(...)]
+                context.snippet_provider.span_after(attr.span, "("),
                 attr.span.hi(),
                 false,
             );
index 4b4aa42d935960ab963b68fe172eb77f597cb6f5..1bcc5c0dada3bd0695d9fd5c8167890ab7eff255 100644 (file)
@@ -121,7 +121,7 @@ fn make_opts() -> Options {
          found reverts to the input file path",
         "[Path for the configuration file]",
     );
-    opts.optopt("", "edition", "Rust edition to use", "[2015|2018]");
+    opts.optopt("", "edition", "Rust edition to use", "[2015|2018|2021]");
     opts.optopt(
         "",
         "color",
index 90ffad927e2c4dd861b7dba3291338072919f056..1d423ac34919b421a31e4f77f4e63030746082a6 100644 (file)
 
 use structopt::StructOpt;
 
+#[path = "test/mod.rs"]
+#[cfg(test)]
+mod cargo_fmt_tests;
+
 #[derive(StructOpt, Debug)]
 #[structopt(
     bin_name = "cargo fmt",
@@ -36,7 +40,7 @@ pub struct Opts {
     #[structopt(long = "version")]
     version: bool,
 
-    /// Specify package to format (only usable in workspaces)
+    /// Specify package to format
     #[structopt(short = "p", long = "package", value_name = "package")]
     packages: Vec<String>,
 
@@ -53,9 +57,13 @@ pub struct Opts {
     #[structopt(name = "rustfmt_options", raw(true))]
     rustfmt_options: Vec<String>,
 
-    /// Format all packages (only usable in workspaces)
+    /// Format all packages, and also their local path-based dependencies
     #[structopt(long = "all")]
     format_all: bool,
+
+    /// Run rustfmt in check mode
+    #[structopt(long = "check")]
+    check: bool,
 }
 
 fn main() {
@@ -104,6 +112,12 @@ fn execute() -> i32 {
 
     let strategy = CargoFmtStrategy::from_opts(&opts);
     let mut rustfmt_args = opts.rustfmt_options;
+    if opts.check {
+        let check_flag = "--check";
+        if !rustfmt_args.iter().any(|o| o == check_flag) {
+            rustfmt_args.push(check_flag.to_owned());
+        }
+    }
     if let Some(message_format) = opts.message_format {
         if let Err(msg) = convert_message_format_to_rustfmt_args(&message_format, &mut rustfmt_args)
         {
@@ -346,7 +360,7 @@ fn get_targets_root_only(
     manifest_path: Option<&Path>,
     targets: &mut BTreeSet<Target>,
 ) -> Result<(), io::Error> {
-    let metadata = get_cargo_metadata(manifest_path, false)?;
+    let metadata = get_cargo_metadata(manifest_path)?;
     let workspace_root_path = PathBuf::from(&metadata.workspace_root).canonicalize()?;
     let (in_workspace_root, current_dir_manifest) = if let Some(target_manifest) = manifest_path {
         (
@@ -390,34 +404,29 @@ fn get_targets_recursive(
     mut targets: &mut BTreeSet<Target>,
     visited: &mut BTreeSet<String>,
 ) -> Result<(), io::Error> {
-    let metadata = get_cargo_metadata(manifest_path, false)?;
-    let metadata_with_deps = get_cargo_metadata(manifest_path, true)?;
-
-    for package in metadata.packages {
+    let metadata = get_cargo_metadata(manifest_path)?;
+    for package in &metadata.packages {
         add_targets(&package.targets, &mut targets);
 
-        // Look for local dependencies.
-        for dependency in package.dependencies {
-            if dependency.source.is_some() || visited.contains(&dependency.name) {
+        // Look for local dependencies using information available since cargo v1.51
+        // It's theoretically possible someone could use a newer version of rustfmt with
+        // a much older version of `cargo`, but we don't try to explicitly support that scenario.
+        // If someone reports an issue with path-based deps not being formatted, be sure to
+        // confirm their version of `cargo` (not `cargo-fmt`) is >= v1.51
+        // https://github.com/rust-lang/cargo/pull/8994
+        for dependency in &package.dependencies {
+            if dependency.path.is_none() || visited.contains(&dependency.name) {
                 continue;
             }
 
-            let dependency_package = metadata_with_deps
-                .packages
-                .iter()
-                .find(|p| p.name == dependency.name && p.source.is_none());
-            let manifest_path = if let Some(dep_pkg) = dependency_package {
-                PathBuf::from(&dep_pkg.manifest_path)
-            } else {
-                let mut package_manifest_path = PathBuf::from(&package.manifest_path);
-                package_manifest_path.pop();
-                package_manifest_path.push(&dependency.name);
-                package_manifest_path.push("Cargo.toml");
-                package_manifest_path
-            };
-
-            if manifest_path.exists() {
-                visited.insert(dependency.name);
+            let manifest_path = PathBuf::from(dependency.path.as_ref().unwrap()).join("Cargo.toml");
+            if manifest_path.exists()
+                && !metadata
+                    .packages
+                    .iter()
+                    .any(|p| p.manifest_path.eq(&manifest_path))
+            {
+                visited.insert(dependency.name.to_owned());
                 get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
             }
         }
@@ -431,8 +440,7 @@ fn get_targets_with_hitlist(
     hitlist: &[String],
     targets: &mut BTreeSet<Target>,
 ) -> Result<(), io::Error> {
-    let metadata = get_cargo_metadata(manifest_path, false)?;
-
+    let metadata = get_cargo_metadata(manifest_path)?;
     let mut workspace_hitlist: BTreeSet<&String> = BTreeSet::from_iter(hitlist);
 
     for package in metadata.packages {
@@ -517,18 +525,13 @@ fn run_rustfmt(
         .unwrap_or(SUCCESS))
 }
 
-fn get_cargo_metadata(
-    manifest_path: Option<&Path>,
-    include_deps: bool,
-) -> Result<cargo_metadata::Metadata, io::Error> {
+fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
     let mut cmd = cargo_metadata::MetadataCommand::new();
-    if !include_deps {
-        cmd.no_deps();
-    }
+    cmd.no_deps();
     if let Some(manifest_path) = manifest_path {
         cmd.manifest_path(manifest_path);
     }
-    cmd.other_options(&[String::from("--offline")]);
+    cmd.other_options(vec![String::from("--offline")]);
 
     match cmd.exec() {
         Ok(metadata) => Ok(metadata),
@@ -541,221 +544,3 @@ fn get_cargo_metadata(
         }
     }
 }
-
-#[cfg(test)]
-mod cargo_fmt_tests {
-    use super::*;
-
-    #[test]
-    fn default_options() {
-        let empty: Vec<String> = vec![];
-        let o = Opts::from_iter(&empty);
-        assert_eq!(false, o.quiet);
-        assert_eq!(false, o.verbose);
-        assert_eq!(false, o.version);
-        assert_eq!(empty, o.packages);
-        assert_eq!(empty, o.rustfmt_options);
-        assert_eq!(false, o.format_all);
-        assert_eq!(None, o.manifest_path);
-        assert_eq!(None, o.message_format);
-    }
-
-    #[test]
-    fn good_options() {
-        let o = Opts::from_iter(&[
-            "test",
-            "-q",
-            "-p",
-            "p1",
-            "-p",
-            "p2",
-            "--message-format",
-            "short",
-            "--",
-            "--edition",
-            "2018",
-        ]);
-        assert_eq!(true, o.quiet);
-        assert_eq!(false, o.verbose);
-        assert_eq!(false, o.version);
-        assert_eq!(vec!["p1", "p2"], o.packages);
-        assert_eq!(vec!["--edition", "2018"], o.rustfmt_options);
-        assert_eq!(false, o.format_all);
-        assert_eq!(Some(String::from("short")), o.message_format);
-    }
-
-    #[test]
-    fn unexpected_option() {
-        assert!(
-            Opts::clap()
-                .get_matches_from_safe(&["test", "unexpected"])
-                .is_err()
-        );
-    }
-
-    #[test]
-    fn unexpected_flag() {
-        assert!(
-            Opts::clap()
-                .get_matches_from_safe(&["test", "--flag"])
-                .is_err()
-        );
-    }
-
-    #[test]
-    fn mandatory_separator() {
-        assert!(
-            Opts::clap()
-                .get_matches_from_safe(&["test", "--check"])
-                .is_err()
-        );
-        assert!(
-            !Opts::clap()
-                .get_matches_from_safe(&["test", "--", "--check"])
-                .is_err()
-        );
-    }
-
-    #[test]
-    fn multiple_packages_one_by_one() {
-        let o = Opts::from_iter(&[
-            "test",
-            "-p",
-            "package1",
-            "--package",
-            "package2",
-            "-p",
-            "package3",
-        ]);
-        assert_eq!(3, o.packages.len());
-    }
-
-    #[test]
-    fn multiple_packages_grouped() {
-        let o = Opts::from_iter(&[
-            "test",
-            "--package",
-            "package1",
-            "package2",
-            "-p",
-            "package3",
-            "package4",
-        ]);
-        assert_eq!(4, o.packages.len());
-    }
-
-    #[test]
-    fn empty_packages_1() {
-        assert!(Opts::clap().get_matches_from_safe(&["test", "-p"]).is_err());
-    }
-
-    #[test]
-    fn empty_packages_2() {
-        assert!(
-            Opts::clap()
-                .get_matches_from_safe(&["test", "-p", "--", "--check"])
-                .is_err()
-        );
-    }
-
-    #[test]
-    fn empty_packages_3() {
-        assert!(
-            Opts::clap()
-                .get_matches_from_safe(&["test", "-p", "--verbose"])
-                .is_err()
-        );
-    }
-
-    #[test]
-    fn empty_packages_4() {
-        assert!(
-            Opts::clap()
-                .get_matches_from_safe(&["test", "-p", "--check"])
-                .is_err()
-        );
-    }
-
-    mod convert_message_format_to_rustfmt_args_tests {
-        use super::*;
-
-        #[test]
-        fn invalid_message_format() {
-            assert_eq!(
-                convert_message_format_to_rustfmt_args("awesome", &mut vec![]),
-                Err(String::from(
-                    "invalid --message-format value: awesome. Allowed values are: short|json|human"
-                )),
-            );
-        }
-
-        #[test]
-        fn json_message_format_and_check_arg() {
-            let mut args = vec![String::from("--check")];
-            assert_eq!(
-                convert_message_format_to_rustfmt_args("json", &mut args),
-                Err(String::from(
-                    "cannot include --check arg when --message-format is set to json"
-                )),
-            );
-        }
-
-        #[test]
-        fn json_message_format_and_emit_arg() {
-            let mut args = vec![String::from("--emit"), String::from("checkstyle")];
-            assert_eq!(
-                convert_message_format_to_rustfmt_args("json", &mut args),
-                Err(String::from(
-                    "cannot include --emit arg when --message-format is set to json"
-                )),
-            );
-        }
-
-        #[test]
-        fn json_message_format() {
-            let mut args = vec![String::from("--edition"), String::from("2018")];
-            assert!(convert_message_format_to_rustfmt_args("json", &mut args).is_ok());
-            assert_eq!(
-                args,
-                vec![
-                    String::from("--edition"),
-                    String::from("2018"),
-                    String::from("--emit"),
-                    String::from("json")
-                ]
-            );
-        }
-
-        #[test]
-        fn human_message_format() {
-            let exp_args = vec![String::from("--emit"), String::from("json")];
-            let mut act_args = exp_args.clone();
-            assert!(convert_message_format_to_rustfmt_args("human", &mut act_args).is_ok());
-            assert_eq!(act_args, exp_args);
-        }
-
-        #[test]
-        fn short_message_format() {
-            let mut args = vec![String::from("--check")];
-            assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
-            assert_eq!(args, vec![String::from("--check"), String::from("-l")]);
-        }
-
-        #[test]
-        fn short_message_format_included_short_list_files_flag() {
-            let mut args = vec![String::from("--check"), String::from("-l")];
-            assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
-            assert_eq!(args, vec![String::from("--check"), String::from("-l")]);
-        }
-
-        #[test]
-        fn short_message_format_included_long_list_files_flag() {
-            let mut args = vec![String::from("--check"), String::from("--files-with-diff")];
-            assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
-            assert_eq!(
-                args,
-                vec![String::from("--check"), String::from("--files-with-diff")]
-            );
-        }
-    }
-}
diff --git a/src/tools/rustfmt/src/cargo-fmt/test/message_format.rs b/src/tools/rustfmt/src/cargo-fmt/test/message_format.rs
new file mode 100644 (file)
index 0000000..bf44924
--- /dev/null
@@ -0,0 +1,80 @@
+use super::*;
+
+#[test]
+fn invalid_message_format() {
+    assert_eq!(
+        convert_message_format_to_rustfmt_args("awesome", &mut vec![]),
+        Err(String::from(
+            "invalid --message-format value: awesome. Allowed values are: short|json|human"
+        )),
+    );
+}
+
+#[test]
+fn json_message_format_and_check_arg() {
+    let mut args = vec![String::from("--check")];
+    assert_eq!(
+        convert_message_format_to_rustfmt_args("json", &mut args),
+        Err(String::from(
+            "cannot include --check arg when --message-format is set to json"
+        )),
+    );
+}
+
+#[test]
+fn json_message_format_and_emit_arg() {
+    let mut args = vec![String::from("--emit"), String::from("checkstyle")];
+    assert_eq!(
+        convert_message_format_to_rustfmt_args("json", &mut args),
+        Err(String::from(
+            "cannot include --emit arg when --message-format is set to json"
+        )),
+    );
+}
+
+#[test]
+fn json_message_format() {
+    let mut args = vec![String::from("--edition"), String::from("2018")];
+    assert!(convert_message_format_to_rustfmt_args("json", &mut args).is_ok());
+    assert_eq!(
+        args,
+        vec![
+            String::from("--edition"),
+            String::from("2018"),
+            String::from("--emit"),
+            String::from("json")
+        ]
+    );
+}
+
+#[test]
+fn human_message_format() {
+    let exp_args = vec![String::from("--emit"), String::from("json")];
+    let mut act_args = exp_args.clone();
+    assert!(convert_message_format_to_rustfmt_args("human", &mut act_args).is_ok());
+    assert_eq!(act_args, exp_args);
+}
+
+#[test]
+fn short_message_format() {
+    let mut args = vec![String::from("--check")];
+    assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
+    assert_eq!(args, vec![String::from("--check"), String::from("-l")]);
+}
+
+#[test]
+fn short_message_format_included_short_list_files_flag() {
+    let mut args = vec![String::from("--check"), String::from("-l")];
+    assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
+    assert_eq!(args, vec![String::from("--check"), String::from("-l")]);
+}
+
+#[test]
+fn short_message_format_included_long_list_files_flag() {
+    let mut args = vec![String::from("--check"), String::from("--files-with-diff")];
+    assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
+    assert_eq!(
+        args,
+        vec![String::from("--check"), String::from("--files-with-diff")]
+    );
+}
diff --git a/src/tools/rustfmt/src/cargo-fmt/test/mod.rs b/src/tools/rustfmt/src/cargo-fmt/test/mod.rs
new file mode 100644 (file)
index 0000000..3605036
--- /dev/null
@@ -0,0 +1,137 @@
+use super::*;
+
+mod message_format;
+mod targets;
+
+#[test]
+fn default_options() {
+    let empty: Vec<String> = vec![];
+    let o = Opts::from_iter(&empty);
+    assert_eq!(false, o.quiet);
+    assert_eq!(false, o.verbose);
+    assert_eq!(false, o.version);
+    assert_eq!(false, o.check);
+    assert_eq!(empty, o.packages);
+    assert_eq!(empty, o.rustfmt_options);
+    assert_eq!(false, o.format_all);
+    assert_eq!(None, o.manifest_path);
+    assert_eq!(None, o.message_format);
+}
+
+#[test]
+fn good_options() {
+    let o = Opts::from_iter(&[
+        "test",
+        "-q",
+        "-p",
+        "p1",
+        "-p",
+        "p2",
+        "--message-format",
+        "short",
+        "--check",
+        "--",
+        "--edition",
+        "2018",
+    ]);
+    assert_eq!(true, o.quiet);
+    assert_eq!(false, o.verbose);
+    assert_eq!(false, o.version);
+    assert_eq!(true, o.check);
+    assert_eq!(vec!["p1", "p2"], o.packages);
+    assert_eq!(vec!["--edition", "2018"], o.rustfmt_options);
+    assert_eq!(false, o.format_all);
+    assert_eq!(Some(String::from("short")), o.message_format);
+}
+
+#[test]
+fn unexpected_option() {
+    assert!(
+        Opts::clap()
+            .get_matches_from_safe(&["test", "unexpected"])
+            .is_err()
+    );
+}
+
+#[test]
+fn unexpected_flag() {
+    assert!(
+        Opts::clap()
+            .get_matches_from_safe(&["test", "--flag"])
+            .is_err()
+    );
+}
+
+#[test]
+fn mandatory_separator() {
+    assert!(
+        Opts::clap()
+            .get_matches_from_safe(&["test", "--emit"])
+            .is_err()
+    );
+    assert!(
+        !Opts::clap()
+            .get_matches_from_safe(&["test", "--", "--emit"])
+            .is_err()
+    );
+}
+
+#[test]
+fn multiple_packages_one_by_one() {
+    let o = Opts::from_iter(&[
+        "test",
+        "-p",
+        "package1",
+        "--package",
+        "package2",
+        "-p",
+        "package3",
+    ]);
+    assert_eq!(3, o.packages.len());
+}
+
+#[test]
+fn multiple_packages_grouped() {
+    let o = Opts::from_iter(&[
+        "test",
+        "--package",
+        "package1",
+        "package2",
+        "-p",
+        "package3",
+        "package4",
+    ]);
+    assert_eq!(4, o.packages.len());
+}
+
+#[test]
+fn empty_packages_1() {
+    assert!(Opts::clap().get_matches_from_safe(&["test", "-p"]).is_err());
+}
+
+#[test]
+fn empty_packages_2() {
+    assert!(
+        Opts::clap()
+            .get_matches_from_safe(&["test", "-p", "--", "--check"])
+            .is_err()
+    );
+}
+
+#[test]
+fn empty_packages_3() {
+    assert!(
+        Opts::clap()
+            .get_matches_from_safe(&["test", "-p", "--verbose"])
+            .is_err()
+    );
+}
+
+#[test]
+fn empty_packages_4() {
+    assert!(
+        Opts::clap()
+            .get_matches_from_safe(&["test", "-p", "--check"])
+            .is_err()
+    );
+}
diff --git a/src/tools/rustfmt/src/cargo-fmt/test/targets.rs b/src/tools/rustfmt/src/cargo-fmt/test/targets.rs
new file mode 100644 (file)
index 0000000..b7e7fab
--- /dev/null
@@ -0,0 +1,134 @@
+use super::*;
+
+struct ExpTarget {
+    path: &'static str,
+    edition: &'static str,
+    kind: &'static str,
+}
+
+mod all_targets {
+    use super::*;
+
+    fn assert_correct_targets_loaded(
+        manifest_suffix: &str,
+        source_root: &str,
+        exp_targets: &[ExpTarget],
+        exp_num_targets: usize,
+    ) {
+        let root_path = Path::new("tests/cargo-fmt/source").join(source_root);
+        let get_path = |exp: &str| PathBuf::from(&root_path).join(exp).canonicalize().unwrap();
+        let manifest_path = Path::new(&root_path).join(manifest_suffix);
+        let targets = get_targets(&CargoFmtStrategy::All, Some(manifest_path.as_path()))
+            .expect("Targets should have been loaded");
+
+        assert_eq!(targets.len(), exp_num_targets);
+
+        for target in exp_targets {
+            assert!(targets.contains(&Target {
+                path: get_path(target.path),
+                edition: target.edition.to_owned(),
+                kind: target.kind.to_owned(),
+            }));
+        }
+    }
+
+    mod different_crate_and_dir_names {
+        use super::*;
+
+        fn assert_correct_targets_loaded(manifest_suffix: &str) {
+            let exp_targets = vec![
+                ExpTarget {
+                    path: "dependency-dir-name/subdep-dir-name/src/lib.rs",
+                    edition: "2018",
+                    kind: "lib",
+                },
+                ExpTarget {
+                    path: "dependency-dir-name/src/lib.rs",
+                    edition: "2018",
+                    kind: "lib",
+                },
+                ExpTarget {
+                    path: "src/main.rs",
+                    edition: "2018",
+                    kind: "main",
+                },
+            ];
+            super::assert_correct_targets_loaded(
+                manifest_suffix,
+                "divergent-crate-dir-names",
+                &exp_targets,
+                3,
+            );
+        }
+
+        #[test]
+        fn correct_targets_from_root() {
+            assert_correct_targets_loaded("Cargo.toml");
+        }
+
+        #[test]
+        fn correct_targets_from_sub_local_dep() {
+            assert_correct_targets_loaded("dependency-dir-name/Cargo.toml");
+        }
+    }
+
+    mod workspaces {
+        use super::*;
+
+        fn assert_correct_targets_loaded(manifest_suffix: &str) {
+            let exp_targets = vec![
+                ExpTarget {
+                    path: "ws/a/src/main.rs",
+                    edition: "2018",
+                    kind: "bin",
+                },
+                ExpTarget {
+                    path: "ws/b/src/main.rs",
+                    edition: "2018",
+                    kind: "bin",
+                },
+                ExpTarget {
+                    path: "ws/c/src/lib.rs",
+                    edition: "2018",
+                    kind: "lib",
+                },
+                ExpTarget {
+                    path: "ws/a/d/src/lib.rs",
+                    edition: "2018",
+                    kind: "lib",
+                },
+                ExpTarget {
+                    path: "e/src/main.rs",
+                    edition: "2018",
+                    kind: "main",
+                },
+                ExpTarget {
+                    path: "ws/a/d/f/src/lib.rs",
+                    edition: "2018",
+                    kind: "lib",
+                },
+            ];
+            super::assert_correct_targets_loaded(
+                manifest_suffix,
+                "workspaces/path-dep-above",
+                &exp_targets,
+                6,
+            );
+        }
+
+        #[test]
+        fn includes_outside_workspace_deps() {
+            assert_correct_targets_loaded("ws/Cargo.toml");
+        }
+
+        #[test]
+        fn includes_workspace_from_dep_above() {
+            assert_correct_targets_loaded("e/Cargo.toml");
+        }
+
+        #[test]
+        fn includes_all_packages_from_workspace_subdir() {
+            assert_correct_targets_loaded("ws/a/d/f/Cargo.toml");
+        }
+    }
+}
index 58a2b5e6aecf32fb0e1e67b98b4d1edda93238d9..dc4f4516252b122267dfb3030bdc01324deeba3a 100644 (file)
@@ -10,7 +10,8 @@
 use crate::shape::{Indent, Shape};
 use crate::string::{rewrite_string, StringFormat};
 use crate::utils::{
-    count_newlines, first_line_width, last_line_width, trim_left_preserve_layout, unicode_str_width,
+    count_newlines, first_line_width, last_line_width, trim_left_preserve_layout,
+    trimmed_last_line_width, unicode_str_width,
 };
 use crate::{ErrorKind, FormattingError};
 
@@ -171,11 +172,12 @@ pub(crate) fn combine_strs_with_missing_comments(
         String::with_capacity(prev_str.len() + next_str.len() + shape.indent.width() + 128);
     result.push_str(prev_str);
     let mut allow_one_line = !prev_str.contains('\n') && !next_str.contains('\n');
-    let first_sep = if prev_str.is_empty() || next_str.is_empty() {
-        ""
-    } else {
-        " "
-    };
+    let first_sep =
+        if prev_str.is_empty() || next_str.is_empty() || trimmed_last_line_width(prev_str) == 0 {
+            ""
+        } else {
+            " "
+        };
     let mut one_line_width =
         last_line_width(prev_str) + first_line_width(next_str) + first_sep.len();
 
@@ -184,7 +186,7 @@ pub(crate) fn combine_strs_with_missing_comments(
     let missing_comment = rewrite_missing_comment(span, shape, context)?;
 
     if missing_comment.is_empty() {
-        if allow_extend && prev_str.len() + first_sep.len() + next_str.len() <= shape.width {
+        if allow_extend && one_line_width <= shape.width {
             result.push_str(first_sep);
         } else if !prev_str.is_empty() {
             result.push_str(&indent.to_string_with_newline(config))
@@ -392,28 +394,26 @@ fn consume_same_line_comments(
     }
 }
 
-/// Attributes for code blocks in rustdoc.
-/// See <https://doc.rust-lang.org/rustdoc/print.html#attributes>.
+/// Enum indicating if the code block contains rust based on attributes
 enum CodeBlockAttribute {
     Rust,
-    Ignore,
-    Text,
-    ShouldPanic,
-    NoRun,
-    CompileFail,
+    NotRust,
 }
 
 impl CodeBlockAttribute {
-    fn new(attribute: &str) -> CodeBlockAttribute {
-        match attribute {
-            "rust" | "" => CodeBlockAttribute::Rust,
-            "ignore" => CodeBlockAttribute::Ignore,
-            "text" => CodeBlockAttribute::Text,
-            "should_panic" => CodeBlockAttribute::ShouldPanic,
-            "no_run" => CodeBlockAttribute::NoRun,
-            "compile_fail" => CodeBlockAttribute::CompileFail,
-            _ => CodeBlockAttribute::Text,
+    /// Parse comma separated attributes list. Return rust only if all
+    /// attributes are valid rust attributes
+    /// See <https://doc.rust-lang.org/rustdoc/print.html#attributes>
+    fn new(attributes: &str) -> CodeBlockAttribute {
+        for attribute in attributes.split(",") {
+            match attribute.trim() {
+                "" | "rust" | "should_panic" | "no_run" | "edition2015" | "edition2018"
+                | "edition2021" => (),
+                "ignore" | "compile_fail" | "text" => return CodeBlockAttribute::NotRust,
+                _ => return CodeBlockAttribute::NotRust,
+            }
         }
+        CodeBlockAttribute::Rust
     }
 }
 
@@ -647,25 +647,21 @@ fn handle_line(
         } else if self.code_block_attr.is_some() {
             if line.starts_with("```") {
                 let code_block = match self.code_block_attr.as_ref().unwrap() {
-                    CodeBlockAttribute::Ignore | CodeBlockAttribute::Text => {
-                        trim_custom_comment_prefix(&self.code_block_buffer)
-                    }
-                    _ if self.code_block_buffer.is_empty() => String::new(),
-                    _ => {
+                    CodeBlockAttribute::Rust
+                        if self.fmt.config.format_code_in_doc_comments()
+                            && !self.code_block_buffer.is_empty() =>
+                    {
                         let mut config = self.fmt.config.clone();
                         config.set().wrap_comments(false);
-                        if config.format_code_in_doc_comments() {
-                            if let Some(s) =
-                                crate::format_code_block(&self.code_block_buffer, &config, false)
-                            {
-                                trim_custom_comment_prefix(&s.snippet)
-                            } else {
-                                trim_custom_comment_prefix(&self.code_block_buffer)
-                            }
+                        if let Some(s) =
+                            crate::format_code_block(&self.code_block_buffer, &config, false)
+                        {
+                            trim_custom_comment_prefix(&s.snippet)
                         } else {
                             trim_custom_comment_prefix(&self.code_block_buffer)
                         }
                     }
+                    _ => trim_custom_comment_prefix(&self.code_block_buffer),
                 };
                 if !code_block.is_empty() {
                     self.result.push_str(&self.comment_line_separator);
index 8c04363b1fd4b95125fd2c1506215ba72bbfd9bb..c5419d860c94312952f19dcaf26130e7cf1bfa35 100644 (file)
@@ -69,6 +69,8 @@
     format_macro_matchers: bool, false, false,
         "Format the metavariable matching patterns in macros";
     format_macro_bodies: bool, true, false, "Format the bodies of macros";
+    hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false,
+        "Format hexadecimal integer literals";
 
     // Single line expressions and items
     empty_item_single_line: bool, true, false,
         "Add trailing semicolon after break, continue and return";
     trailing_comma: SeparatorTactic, SeparatorTactic::Vertical, false,
         "How to handle trailing commas for lists";
-    match_block_trailing_comma: bool, false, false,
+    match_block_trailing_comma: bool, false, true,
         "Put a trailing comma after a block based match arm (non-block arms are not affected)";
     blank_lines_upper_bound: usize, 1, false,
         "Maximum number of blank lines which can be put between items";
     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";
 
     // 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";
         "Require a specific version of rustfmt";
     unstable_features: bool, false, false,
             "Enables unstable features. Only available on nightly channel";
-    disable_all_formatting: bool, false, false, "Don't reformat anything";
+    disable_all_formatting: bool, false, true, "Don't reformat anything";
     skip_children: bool, false, false, "Don't reformat out of line modules";
     hide_parse_errors: bool, false, false, "Hide errors from the parser";
     error_on_line_overflow: bool, false, false, "Error if unable to get all lines within max_width";
@@ -569,6 +572,7 @@ fn test_dump_default_config() {
 format_strings = false
 format_macro_matchers = false
 format_macro_bodies = true
+hex_literal_case = "Preserve"
 empty_item_single_line = true
 struct_lit_single_line = true
 fn_single_line = false
@@ -604,6 +608,7 @@ fn test_dump_default_config() {
 edition = "2015"
 version = "One"
 inline_attribute_width = 0
+format_generated_files = false
 merge_derives = true
 use_try_shorthand = false
 use_field_init_shorthand = false
index 3b91021813c16a164df655535c8ecbfb28f26915..e92f8e8a53152e666cec884eae3a8808bcf40d18 100644 (file)
@@ -125,6 +125,19 @@ pub enum ImportGranularity {
     Module,
     /// Use one `use` statement per imported item.
     Item,
+    /// Use one `use` statement including all items.
+    One,
+}
+
+/// Controls how rustfmt should handle case in hexadecimal literals.
+#[config_type]
+pub enum HexLiteralCase {
+    /// Leave the literal as-is
+    Preserve,
+    /// Ensure all literals use uppercase lettering
+    Upper,
+    /// Ensure all literals use lowercase lettering
+    Lower,
 }
 
 #[config_type]
index 975af6c02947af48b9308f7d72908e7b79f8402b..7f1dd363f9379a3bd971dbf87c93e4a0955a0cab 100644 (file)
@@ -13,7 +13,7 @@
     rewrite_missing_comment, CharClasses, FindUncommented,
 };
 use crate::config::lists::*;
-use crate::config::{Config, ControlBraceStyle, IndentStyle, Version};
+use crate::config::{Config, ControlBraceStyle, HexLiteralCase, IndentStyle, Version};
 use crate::lists::{
     definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape,
     struct_lit_tactic, write_list, ListFormatting, Separator,
@@ -822,7 +822,7 @@ fn rewrite_pat_expr(
             let pat_string = pat.rewrite(context, pat_shape)?;
             let comments_lo = context
                 .snippet_provider
-                .span_after(self.span, self.connector.trim());
+                .span_after(self.span.with_lo(pat.span.hi()), self.connector.trim());
             let comments_span = mk_sp(comments_lo, expr.span.lo());
             return rewrite_assign_rhs_with_comments(
                 context,
@@ -1168,6 +1168,7 @@ pub(crate) fn rewrite_literal(
 ) -> Option<String> {
     match l.kind {
         ast::LitKind::Str(_, ast::StrStyle::Cooked) => rewrite_string_lit(context, l.span, shape),
+        ast::LitKind::Int(..) => rewrite_int_lit(context, l, shape),
         _ => wrap_str(
             context.snippet(l.span).to_owned(),
             context.config.max_width(),
@@ -1202,6 +1203,36 @@ fn rewrite_string_lit(context: &RewriteContext<'_>, span: Span, shape: Shape) ->
     )
 }
 
+fn rewrite_int_lit(context: &RewriteContext<'_>, lit: &ast::Lit, shape: Shape) -> Option<String> {
+    let span = lit.span;
+    let symbol = lit.token.symbol.as_str();
+
+    if symbol.starts_with("0x") {
+        let hex_lit = match context.config.hex_literal_case() {
+            HexLiteralCase::Preserve => None,
+            HexLiteralCase::Upper => Some(symbol[2..].to_ascii_uppercase()),
+            HexLiteralCase::Lower => Some(symbol[2..].to_ascii_lowercase()),
+        };
+        if let Some(hex_lit) = hex_lit {
+            return wrap_str(
+                format!(
+                    "0x{}{}",
+                    hex_lit,
+                    lit.token.suffix.map_or(String::new(), |s| s.to_string())
+                ),
+                context.config.max_width(),
+                shape,
+            );
+        }
+    }
+
+    wrap_str(
+        context.snippet(span).to_owned(),
+        context.config.max_width(),
+        shape,
+    )
+}
+
 fn choose_separator_tactic(context: &RewriteContext<'_>, span: Span) -> Option<SeparatorTactic> {
     if context.inside_macro() {
         if span_ends_with_comma(context, span) {
@@ -1497,12 +1528,12 @@ enum StructLitField<'a> {
     let path_shape = shape.sub_width(2)?;
     let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?;
 
-    let has_base = match struct_rest {
+    let has_base_or_rest = match struct_rest {
         ast::StructRest::None if fields.is_empty() => return Some(format!("{} {{}}", path_str)),
         ast::StructRest::Rest(_) if fields.is_empty() => {
             return Some(format!("{} {{ .. }}", path_str));
         }
-        ast::StructRest::Base(_) => true,
+        ast::StructRest::Rest(_) | ast::StructRest::Base(_) => true,
         _ => false,
     };
 
@@ -1511,7 +1542,7 @@ enum StructLitField<'a> {
 
     let one_line_width = h_shape.map_or(0, |shape| shape.width);
     let body_lo = context.snippet_provider.span_after(span, "{");
-    let fields_str = if struct_lit_can_be_aligned(fields, has_base)
+    let fields_str = if struct_lit_can_be_aligned(fields, has_base_or_rest)
         && context.config.struct_field_align_threshold() > 0
     {
         rewrite_with_alignment(
@@ -1583,10 +1614,7 @@ enum StructLitField<'a> {
             nested_shape,
             tactic,
             context,
-            force_no_trailing_comma
-                || has_base
-                || !context.use_block_indent()
-                || matches!(struct_rest, ast::StructRest::Rest(_)),
+            force_no_trailing_comma || has_base_or_rest || !context.use_block_indent(),
         );
 
         write_list(&item_vec, &fmt)?
index e0403574eebc1d73a361c70e144fe67920c4a40a..9ef47b887cadb8809345b1dc196017bbbad92c59 100644 (file)
@@ -10,6 +10,7 @@
 use self::newline_style::apply_newline_style;
 use crate::comment::{CharClasses, FullCodeCharKind};
 use crate::config::{Config, FileName, Verbosity};
+use crate::formatting::generated::is_generated_file;
 use crate::issues::BadIssueSeeker;
 use crate::modules::Module;
 use crate::syntux::parser::{DirectoryOwnership, Parser, ParserError};
@@ -18,6 +19,7 @@
 use crate::visitor::FmtVisitor;
 use crate::{modules, source_file, ErrorKind, FormatReport, Input, Session};
 
+mod generated;
 mod newline_style;
 
 // A map of the files of a crate, with their new content
@@ -103,7 +105,12 @@ fn format_project<T: FormatHandler>(
     context.parse_session.set_silent_emitter();
 
     for (path, module) in files {
-        let should_ignore = !input_is_stdin && context.ignore_file(&path);
+        let source_file = context.parse_session.span_to_file_contents(module.span);
+        let src = source_file.src.as_ref().expect("SourceFile without src");
+
+        let should_ignore = (!input_is_stdin && context.ignore_file(&path))
+            || (!config.format_generated_files() && is_generated_file(src));
+
         if (config.skip_children() && path != main_file) || should_ignore {
             continue;
         }
diff --git a/src/tools/rustfmt/src/formatting/generated.rs b/src/tools/rustfmt/src/formatting/generated.rs
new file mode 100644 (file)
index 0000000..58f43f1
--- /dev/null
@@ -0,0 +1,7 @@
+/// Returns `true` if the given span is a part of generated files.
+pub(super) fn is_generated_file(original_snippet: &str) -> bool {
+    original_snippet
+        .lines()
+        .take(5) // looking for marker only in the beginning of the file
+        .any(|line| line.contains("@generated"))
+}
index 64d78605f0c5f7be90d706fc43a40a25f2df57f5..5ac799366894de843dd6250a97adc2786a1cc1e4 100644 (file)
@@ -138,6 +138,29 @@ fn remove_alias(&self) -> UseSegment {
         }
     }
 
+    // Check if self == other with their aliases removed.
+    fn equal_except_alias(&self, other: &Self) -> bool {
+        match (self, other) {
+            (UseSegment::Ident(ref s1, _), UseSegment::Ident(ref s2, _)) => s1 == s2,
+            (UseSegment::Slf(_), UseSegment::Slf(_))
+            | (UseSegment::Super(_), UseSegment::Super(_))
+            | (UseSegment::Crate(_), UseSegment::Crate(_))
+            | (UseSegment::Glob, UseSegment::Glob) => true,
+            (UseSegment::List(ref list1), UseSegment::List(ref list2)) => list1 == list2,
+            _ => false,
+        }
+    }
+
+    fn get_alias(&self) -> Option<&str> {
+        match self {
+            UseSegment::Ident(_, a)
+            | UseSegment::Slf(a)
+            | UseSegment::Super(a)
+            | UseSegment::Crate(a) => a.as_deref(),
+            _ => None,
+        }
+    }
+
     fn from_path_segment(
         context: &RewriteContext<'_>,
         path_seg: &ast::PathSegment,
@@ -558,6 +581,7 @@ fn share_prefix(&self, other: &UseTree, shared_prefix: SharedPrefix) -> bool {
                 SharedPrefix::Module => {
                     self.path[..self.path.len() - 1] == other.path[..other.path.len() - 1]
                 }
+                SharedPrefix::One => true,
             }
         }
     }
@@ -598,7 +622,7 @@ fn flatten(self) -> Vec<UseTree> {
     fn merge(&mut self, other: &UseTree, merge_by: SharedPrefix) {
         let mut prefix = 0;
         for (a, b) in self.path.iter().zip(other.path.iter()) {
-            if *a == *b {
+            if a.equal_except_alias(b) {
                 prefix += 1;
             } else {
                 break;
@@ -633,14 +657,20 @@ fn merge_rest(
             return Some(new_path);
         }
     } else if len == 1 {
-        let rest = if a.len() == len { &b[1..] } else { &a[1..] };
-        return Some(vec![
-            b[0].clone(),
-            UseSegment::List(vec![
-                UseTree::from_path(vec![UseSegment::Slf(None)], DUMMY_SP),
-                UseTree::from_path(rest.to_vec(), DUMMY_SP),
-            ]),
-        ]);
+        let (common, rest) = if a.len() == len {
+            (&a[0], &b[1..])
+        } else {
+            (&b[0], &a[1..])
+        };
+        let mut list = vec![UseTree::from_path(
+            vec![UseSegment::Slf(common.get_alias().map(ToString::to_string))],
+            DUMMY_SP,
+        )];
+        match rest {
+            [UseSegment::List(rest_list)] => list.extend(rest_list.clone()),
+            _ => list.push(UseTree::from_path(rest.to_vec(), DUMMY_SP)),
+        }
+        return Some(vec![b[0].clone(), UseSegment::List(list)]);
     } else {
         len -= 1;
     }
@@ -655,18 +685,54 @@ fn merge_rest(
 }
 
 fn merge_use_trees_inner(trees: &mut Vec<UseTree>, use_tree: UseTree, merge_by: SharedPrefix) {
-    let similar_trees = trees
-        .iter_mut()
-        .filter(|tree| tree.share_prefix(&use_tree, merge_by));
+    struct SimilarTree<'a> {
+        similarity: usize,
+        path_len: usize,
+        tree: &'a mut UseTree,
+    }
+
+    let similar_trees = trees.iter_mut().filter_map(|tree| {
+        if tree.share_prefix(&use_tree, merge_by) {
+            // In the case of `SharedPrefix::One`, `similarity` is used for deciding with which
+            // tree `use_tree` should be merge.
+            // In other cases `similarity` won't be used, so set it to `0` as a dummy value.
+            let similarity = if merge_by == SharedPrefix::One {
+                tree.path
+                    .iter()
+                    .zip(&use_tree.path)
+                    .take_while(|(a, b)| a.equal_except_alias(b))
+                    .count()
+            } else {
+                0
+            };
+
+            let path_len = tree.path.len();
+            Some(SimilarTree {
+                similarity,
+                tree,
+                path_len,
+            })
+        } else {
+            None
+        }
+    });
+
     if use_tree.path.len() == 1 && merge_by == SharedPrefix::Crate {
-        if let Some(tree) = similar_trees.min_by_key(|tree| tree.path.len()) {
-            if tree.path.len() == 1 {
+        if let Some(tree) = similar_trees.min_by_key(|tree| tree.path_len) {
+            if tree.path_len == 1 {
+                return;
+            }
+        }
+    } else if merge_by == SharedPrefix::One {
+        if let Some(sim_tree) = similar_trees.max_by_key(|tree| tree.similarity) {
+            if sim_tree.similarity > 0 {
+                sim_tree.tree.merge(&use_tree, merge_by);
                 return;
             }
         }
-    } else if let Some(tree) = similar_trees.max_by_key(|tree| tree.path.len()) {
-        if tree.path.len() > 1 {
-            tree.merge(&use_tree, merge_by);
+    } else if let Some(sim_tree) = similar_trees.max_by_key(|tree| tree.path_len) {
+        if sim_tree.path_len > 1 {
+            sim_tree.tree.merge(&use_tree, merge_by);
             return;
         }
     }
@@ -880,6 +946,7 @@ fn rewrite(&self, context: &RewriteContext<'_>, mut shape: Shape) -> Option<Stri
 pub(crate) enum SharedPrefix {
     Crate,
     Module,
+    One,
 }
 
 #[cfg(test)]
@@ -904,7 +971,7 @@ fn bump(&mut self) {
             }
 
             fn eat(&mut self, c: char) {
-                assert!(self.input.next().unwrap() == c);
+                assert_eq!(self.input.next().unwrap(), c);
             }
 
             fn push_segment(
@@ -1094,6 +1161,49 @@ fn test_use_tree_merge_module() {
         );
     }
 
+    #[test]
+    fn test_use_tree_merge_one() {
+        test_merge!(One, ["a", "b"], ["{a, b}"]);
+
+        test_merge!(One, ["a::{aa, ab}", "b", "a"], ["{a::{self, aa, ab}, b}"]);
+
+        test_merge!(One, ["a as x", "b as y"], ["{a as x, b as y}"]);
+
+        test_merge!(
+            One,
+            ["a::{aa as xa, ab}", "b", "a"],
+            ["{a::{self, aa as xa, ab}, b}"]
+        );
+
+        test_merge!(
+            One,
+            ["a", "a::{aa, ab::{aba, abb}}"],
+            ["a::{self, aa, ab::{aba, abb}}"]
+        );
+
+        test_merge!(One, ["a", "b::{ba, *}"], ["{a, b::{ba, *}}"]);
+
+        test_merge!(One, ["a", "b", "a::aa"], ["{a::{self, aa}, b}"]);
+
+        test_merge!(
+            One,
+            ["a::aa::aaa", "a::ac::aca", "a::aa::*"],
+            ["a::{aa::{aaa, *}, ac::aca}"]
+        );
+
+        test_merge!(
+            One,
+            ["a", "b::{ba, bb}", "a::{aa::*, ab::aba}"],
+            ["{a::{self, aa::*, ab::aba}, b::{ba, bb}}"]
+        );
+
+        test_merge!(
+            One,
+            ["b", "a::ac::{aca, acb}", "a::{aa::*, ab}"],
+            ["{a::{aa::*, ab, ac::{aca, acb}}, b}"]
+        );
+    }
+
     #[test]
     fn test_flatten_use_trees() {
         assert_eq!(
index 14041539b9dfd618536dc240416b65a60f283d3d..1cb1a2701c36bf24f78109c56c45d320c4da2806 100644 (file)
@@ -174,14 +174,14 @@ pub(crate) struct FnSig<'a> {
     constness: ast::Const,
     defaultness: ast::Defaultness,
     unsafety: ast::Unsafe,
-    visibility: ast::Visibility,
+    visibility: &'a ast::Visibility,
 }
 
 impl<'a> FnSig<'a> {
     pub(crate) fn from_method_sig(
         method_sig: &'a ast::FnSig,
         generics: &'a ast::Generics,
-        visibility: ast::Visibility,
+        visibility: &'a ast::Visibility,
     ) -> FnSig<'a> {
         FnSig {
             unsafety: method_sig.header.unsafety,
@@ -204,7 +204,7 @@ pub(crate) fn from_fn_kind(
         match *fn_kind {
             visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, _) => match fn_ctxt {
                 visit::FnCtxt::Assoc(..) => {
-                    let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis.clone());
+                    let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis);
                     fn_sig.defaultness = defaultness;
                     fn_sig
                 }
@@ -216,7 +216,7 @@ pub(crate) fn from_fn_kind(
                     is_async: Cow::Borrowed(&fn_sig.header.asyncness),
                     defaultness,
                     unsafety: fn_sig.header.unsafety,
-                    visibility: vis.clone(),
+                    visibility: vis,
                 },
             },
             _ => unreachable!(),
@@ -323,6 +323,7 @@ pub(crate) fn rewrite_required_fn(
         indent: Indent,
         ident: symbol::Ident,
         sig: &ast::FnSig,
+        vis: &ast::Visibility,
         generics: &ast::Generics,
         span: Span,
     ) -> Option<String> {
@@ -334,7 +335,7 @@ pub(crate) fn rewrite_required_fn(
             &context,
             indent,
             ident,
-            &FnSig::from_method_sig(sig, generics, DEFAULT_VISIBILITY),
+            &FnSig::from_method_sig(sig, generics, vis),
             span,
             FnBraceStyle::None,
         )?;
@@ -1474,12 +1475,17 @@ fn format_tuple_struct(
         format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "(", ")");
     } else {
         let shape = Shape::indented(offset, context.config).sub_width(1)?;
+        let lo = if let Some(generics) = struct_parts.generics {
+            generics.span.hi()
+        } else {
+            struct_parts.ident.span.hi()
+        };
         result = overflow::rewrite_with_parens(
             context,
             &result,
             fields.iter(),
             shape,
-            span,
+            mk_sp(lo, span.hi()),
             context.config.fn_call_width(),
             None,
         )?;
@@ -1503,7 +1509,7 @@ fn format_tuple_struct(
     Some(result)
 }
 
-fn rewrite_type<R: Rewrite>(
+pub(crate) fn rewrite_type<R: Rewrite>(
     context: &RewriteContext<'_>,
     indent: Indent,
     ident: symbol::Ident,
@@ -1760,7 +1766,7 @@ pub(crate) fn from_trait_item(ti: &'a ast::AssocItem) -> Self {
         };
         StaticParts {
             prefix: "const",
-            vis: &DEFAULT_VISIBILITY,
+            vis: &ti.vis,
             ident: ti.ident,
             ty,
             mutability: ast::Mutability::Not,
@@ -1847,29 +1853,6 @@ fn rewrite_static(
         Some(format!("{}{};", prefix, ty_str))
     }
 }
-
-pub(crate) fn rewrite_type_alias(
-    ident: symbol::Ident,
-    ty_opt: Option<&ptr::P<ast::Ty>>,
-    generics: &ast::Generics,
-    generic_bounds_opt: Option<&ast::GenericBounds>,
-    context: &RewriteContext<'_>,
-    indent: Indent,
-    vis: &ast::Visibility,
-    span: Span,
-) -> Option<String> {
-    rewrite_type(
-        context,
-        indent,
-        ident,
-        vis,
-        generics,
-        generic_bounds_opt,
-        ty_opt,
-        span,
-    )
-}
-
 struct OpaqueType<'a> {
     bounds: &'a ast::GenericBounds,
 }
@@ -1883,32 +1866,7 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
     }
 }
 
-pub(crate) fn rewrite_opaque_impl_type(
-    context: &RewriteContext<'_>,
-    ident: symbol::Ident,
-    generics: &ast::Generics,
-    generic_bounds: &ast::GenericBounds,
-    indent: Indent,
-) -> Option<String> {
-    let ident_str = rewrite_ident(context, ident);
-    // 5 = "type "
-    let generics_shape = Shape::indented(indent, context.config).offset_left(5)?;
-    let generics_str = rewrite_generics(context, ident_str, generics, generics_shape)?;
-    let prefix = format!("type {} =", generics_str);
-    let rhs = OpaqueType {
-        bounds: generic_bounds,
-    };
-
-    rewrite_assign_rhs(
-        context,
-        &prefix,
-        &rhs,
-        Shape::indented(indent, context.config).sub_width(1)?,
-    )
-    .map(|s| s + ";")
-}
-
-pub(crate) fn rewrite_associated_impl_type(
+pub(crate) fn rewrite_impl_type(
     ident: symbol::Ident,
     vis: &ast::Visibility,
     defaultness: ast::Defaultness,
@@ -1918,7 +1876,25 @@ pub(crate) fn rewrite_associated_impl_type(
     indent: Indent,
     span: Span,
 ) -> Option<String> {
-    let result = rewrite_type_alias(ident, ty_opt, generics, None, context, indent, vis, span)?;
+    // Opaque type
+    let result = if let Some(rustc_ast::ast::Ty {
+        kind: ast::TyKind::ImplTrait(_, ref bounds),
+        ..
+    }) = ty_opt.map(|t| &**t)
+    {
+        rewrite_type(
+            context,
+            indent,
+            ident,
+            &DEFAULT_VISIBILITY,
+            generics,
+            None,
+            Some(&OpaqueType { bounds }),
+            span,
+        )
+    } else {
+        rewrite_type(context, indent, ident, vis, generics, None, ty_opt, span)
+    }?;
 
     match defaultness {
         ast::Defaultness::Default(..) => Some(format!("default {}", result)),
@@ -1995,14 +1971,17 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
         let param_attrs_result = self
             .attrs
             .rewrite(context, Shape::legacy(shape.width, shape.indent))?;
-        let (span, has_multiple_attr_lines) = if !self.attrs.is_empty() {
+        // N.B. Doc comments aren't typically valid syntax, but could appear
+        // in the presence of certain macros - https://github.com/rust-lang/rustfmt/issues/4936
+        let (span, has_multiple_attr_lines, has_doc_comments) = if !self.attrs.is_empty() {
             let num_attrs = self.attrs.len();
             (
                 mk_sp(self.attrs[num_attrs - 1].span.hi(), self.pat.span.lo()),
                 param_attrs_result.contains('\n'),
+                self.attrs.iter().any(|a| a.is_doc_comment()),
             )
         } else {
-            (mk_sp(self.span.lo(), self.span.lo()), false)
+            (mk_sp(self.span.lo(), self.span.lo()), false, false)
         };
 
         if let Some(ref explicit_self) = self.to_self() {
@@ -2015,15 +1994,16 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
                 has_multiple_attr_lines,
             )
         } else if is_named_param(self) {
+            let param_name = &self
+                .pat
+                .rewrite(context, Shape::legacy(shape.width, shape.indent))?;
             let mut result = combine_strs_with_missing_comments(
                 context,
                 &param_attrs_result,
-                &self
-                    .pat
-                    .rewrite(context, Shape::legacy(shape.width, shape.indent))?,
+                param_name,
                 span,
                 shape,
-                !has_multiple_attr_lines,
+                !has_multiple_attr_lines && !has_doc_comments,
             )?;
 
             if !is_empty_infer(&*self.ty, self.pat.span) {
@@ -2034,10 +2014,30 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
                 result.push_str(&after_comment);
                 let overhead = last_line_width(&result);
                 let max_width = shape.width.checked_sub(overhead)?;
-                let ty_str = self
+                if let Some(ty_str) = self
                     .ty
-                    .rewrite(context, Shape::legacy(max_width, shape.indent))?;
-                result.push_str(&ty_str);
+                    .rewrite(context, Shape::legacy(max_width, shape.indent))
+                {
+                    result.push_str(&ty_str);
+                } else {
+                    result = combine_strs_with_missing_comments(
+                        context,
+                        &(param_attrs_result + &shape.to_string_with_newline(context.config)),
+                        param_name,
+                        span,
+                        shape,
+                        !has_multiple_attr_lines,
+                    )?;
+                    result.push_str(&before_comment);
+                    result.push_str(colon_spaces(context.config));
+                    result.push_str(&after_comment);
+                    let overhead = last_line_width(&result);
+                    let max_width = shape.width.checked_sub(overhead)?;
+                    let ty_str = self
+                        .ty
+                        .rewrite(context, Shape::legacy(max_width, shape.indent))?;
+                    result.push_str(&ty_str);
+                }
             }
 
             Some(result)
@@ -3146,7 +3146,7 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
                         context,
                         shape.indent,
                         self.ident,
-                        &FnSig::from_method_sig(&fn_sig, generics, self.vis.clone()),
+                        &FnSig::from_method_sig(&fn_sig, generics, &self.vis),
                         span,
                         FnBraceStyle::None,
                     )
@@ -3170,14 +3170,14 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
             ast::ForeignItemKind::TyAlias(ref ty_alias_kind) => {
                 let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref type_default) =
                     **ty_alias_kind;
-                rewrite_type_alias(
-                    self.ident,
-                    type_default.as_ref(),
-                    generics,
-                    Some(generic_bounds),
+                rewrite_type(
                     &context,
                     shape.indent,
+                    self.ident,
                     &self.vis,
+                    generics,
+                    Some(generic_bounds),
+                    type_default.as_ref(),
                     self.span,
                 )
             }
index 73e886c55637e1d01073409c361a0151349e85ab..c04b4787616933e84528d1695a386eefce5769ab 100644 (file)
@@ -367,9 +367,9 @@ pub(crate) fn write_list<I, T>(items: I, formatting: &ListFormatting<'_>) -> Opt
             result.push_str(&comment);
 
             if !inner_item.is_empty() {
-                if tactic == DefinitiveListTactic::Vertical || tactic == DefinitiveListTactic::Mixed
-                {
-                    // We cannot keep pre-comments on the same line if the comment if normalized.
+                use DefinitiveListTactic::*;
+                if matches!(tactic, Vertical | Mixed | SpecialMacro(_)) {
+                    // We cannot keep pre-comments on the same line if the comment is normalized.
                     let keep_comment = if formatting.config.normalize_comments()
                         || item.pre_comment_style == ListItemCommentStyle::DifferentLine
                     {
@@ -389,7 +389,7 @@ pub(crate) fn write_list<I, T>(items: I, formatting: &ListFormatting<'_>) -> Opt
                         line_len = item.item.as_ref().map_or(0, |s| unicode_str_width(&s));
                     }
                 } else {
-                    result.push(' ');
+                    result.push(' ')
                 }
             }
             item_max_width = None;
index 140ec226c02e5a072929ab318c477af93e2f5bb2..5a6ed0ec06e55a37ca203bafdbd9625a2ad3ce4c 100644 (file)
@@ -409,6 +409,7 @@ fn rewrite_match_body(
             }
             result.push_str(&nested_indent_str);
             result.push_str(&body_str);
+            result.push_str(&comma);
             return Some(result);
         }
 
index 263d840785a2953468f42a976058d8490c4a7f53..28edcb784b40ee17030a7660087803dfc347b866 100644 (file)
@@ -51,6 +51,14 @@ pub(crate) fn format_missing(&mut self, end: BytePos) {
     }
 
     pub(crate) fn format_missing_with_indent(&mut self, end: BytePos) {
+        self.format_missing_indent(end, true)
+    }
+
+    pub(crate) fn format_missing_no_indent(&mut self, end: BytePos) {
+        self.format_missing_indent(end, false)
+    }
+
+    fn format_missing_indent(&mut self, end: BytePos, should_indent: bool) {
         let config = self.config;
         self.format_missing_inner(end, |this, last_snippet, snippet| {
             this.push_str(last_snippet.trim_end());
@@ -58,14 +66,10 @@ pub(crate) fn format_missing_with_indent(&mut self, end: BytePos) {
                 // No new lines in the snippet.
                 this.push_str("\n");
             }
-            let indent = this.block_indent.to_string(config);
-            this.push_str(&indent);
-        })
-    }
-
-    pub(crate) fn format_missing_no_indent(&mut self, end: BytePos) {
-        self.format_missing_inner(end, |this, last_snippet, _| {
-            this.push_str(last_snippet.trim_end());
+            if should_indent {
+                let indent = this.block_indent.to_string(config);
+                this.push_str(&indent);
+            }
         })
     }
 
index e32213467a51f8f2ee08053135a59e9c3c8c2c5a..ac24181c7805258b89c053d6c444a65709f79af6 100644 (file)
@@ -77,6 +77,7 @@ pub(crate) enum OverflowableItem<'a> {
     FieldDef(&'a ast::FieldDef),
     TuplePatField(&'a TuplePatField<'a>),
     Ty(&'a ast::Ty),
+    Pat(&'a ast::Pat),
 }
 
 impl<'a> Rewrite for OverflowableItem<'a> {
@@ -116,6 +117,7 @@ pub(crate) fn map<F, T>(&self, f: F) -> T
             OverflowableItem::FieldDef(sf) => f(*sf),
             OverflowableItem::TuplePatField(pat) => f(*pat),
             OverflowableItem::Ty(ty) => f(*ty),
+            OverflowableItem::Pat(pat) => f(*pat),
         }
     }
 
@@ -232,7 +234,7 @@ fn into_overflowable_item(&'a self) -> OverflowableItem<'a> {
     }
 }
 
-impl_into_overflowable_item_for_ast_node!(Expr, GenericParam, NestedMetaItem, FieldDef, Ty);
+impl_into_overflowable_item_for_ast_node!(Expr, GenericParam, NestedMetaItem, FieldDef, Ty, Pat);
 impl_into_overflowable_item_for_rustfmt_types!([MacroArg], [SegmentParam, TuplePatField]);
 
 pub(crate) fn into_overflowable_list<'a, T>(
index 0501e76d2772725ad724f26e9374262ae4316a60..ba8d8024a9707c34ef31c4eae24665eb99f5f39d 100644 (file)
@@ -4,6 +4,7 @@
 
 use crate::comment::{combine_strs_with_missing_comments, FindUncommented};
 use crate::config::lists::*;
+use crate::config::Version;
 use crate::expr::{can_be_overflowed_expr, rewrite_unary_prefix, wrap_struct_field};
 use crate::lists::{
     definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape,
@@ -226,12 +227,13 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
             PatKind::Path(ref q_self, ref path) => {
                 rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape)
             }
-            PatKind::TupleStruct(_, ref path, ref pat_vec) => {
-                let path_str = rewrite_path(context, PathContext::Expr, None, path, shape)?;
+            PatKind::TupleStruct(ref q_self, ref path, ref pat_vec) => {
+                let path_str =
+                    rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape)?;
                 rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape)
             }
             PatKind::Lit(ref expr) => expr.rewrite(context, shape),
-            PatKind::Slice(ref slice_pat) => {
+            PatKind::Slice(ref slice_pat) if context.config.version() == Version::One => {
                 let rw: Vec<String> = slice_pat
                     .iter()
                     .map(|p| {
@@ -244,8 +246,17 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
                     .collect();
                 Some(format!("[{}]", rw.join(", ")))
             }
-            PatKind::Struct(_, ref path, ref fields, ellipsis) => {
-                rewrite_struct_pat(path, fields, ellipsis, self.span, context, shape)
+            PatKind::Slice(ref slice_pat) => overflow::rewrite_with_square_brackets(
+                context,
+                "",
+                slice_pat.iter(),
+                shape,
+                self.span,
+                None,
+                None,
+            ),
+            PatKind::Struct(ref qself, ref path, ref fields, ellipsis) => {
+                rewrite_struct_pat(qself, path, fields, ellipsis, self.span, context, shape)
             }
             PatKind::MacCall(ref mac) => {
                 rewrite_macro(mac, None, context, shape, MacroPosition::Pat)
@@ -258,6 +269,7 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
 }
 
 fn rewrite_struct_pat(
+    qself: &Option<ast::QSelf>,
     path: &ast::Path,
     fields: &[ast::PatField],
     ellipsis: bool,
@@ -267,7 +279,7 @@ fn rewrite_struct_pat(
 ) -> Option<String> {
     // 2 =  ` {`
     let path_shape = shape.sub_width(2)?;
-    let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?;
+    let path_str = rewrite_path(context, PathContext::Expr, qself.as_ref(), path, path_shape)?;
 
     if fields.is_empty() && !ellipsis {
         return Some(format!("{} {{}}", path_str));
index ac65ff2c1086e853edfd5e10ac355fe93631657c..2c58350d4feb6d8e0bf9a3cbfc15d084a0af73a7 100644 (file)
@@ -113,6 +113,7 @@ fn rewrite_reorderable_or_regroupable_items(
                     merge_use_trees(normalized_items, SharedPrefix::Module)
                 }
                 ImportGranularity::Item => flatten_use_trees(normalized_items),
+                ImportGranularity::One => merge_use_trees(normalized_items, SharedPrefix::One),
                 ImportGranularity::Preserve => normalized_items,
             };
 
index 7e3786b7cd94cd344660863b9f083a3d0e89b9e2..8e6c75a3744ac6a8e4b1e0c6a7460f664ff09b0d 100644 (file)
@@ -104,7 +104,7 @@ fn span(&self) -> Span {
 impl Spanned for ast::Param {
     fn span(&self) -> Span {
         if crate::items::is_named_param(self) {
-            mk_sp(self.pat.span.lo(), self.ty.span.hi())
+            mk_sp(crate::items::span_lo_for_param(self), self.ty.span.hi())
         } else {
             self.ty.span
         }
index 2965b0928aadaf751663bad5017ecfbf93101057..946c076d9f2d1fdf388b19156c5c2a7b5ca254e0 100644 (file)
@@ -175,6 +175,12 @@ pub(crate) fn span_to_filename(&self, span: Span) -> FileName {
         self.parse_sess.source_map().span_to_filename(span).into()
     }
 
+    pub(crate) fn span_to_file_contents(&self, span: Span) -> Lrc<rustc_span::SourceFile> {
+        self.parse_sess
+            .source_map()
+            .lookup_source_file(span.data().lo)
+    }
+
     pub(crate) fn span_to_first_line_string(&self, span: Span) -> String {
         let file_lines = self.parse_sess.source_map().span_to_lines(span).ok();
 
index cb52346a13a41c0ad9c94991925d7f53bfc2974a..48d61289a9b8f34a25d89237f5842a1d4245ed29 100644 (file)
@@ -469,11 +469,6 @@ fn stdin_works_with_modified_lines() {
 #[test]
 fn stdin_disable_all_formatting_test() {
     init_log();
-    match option_env!("CFG_RELEASE_CHANNEL") {
-        None | Some("nightly") => {}
-        // These tests require nightly.
-        _ => return,
-    }
     let input = String::from("fn main() { println!(\"This should not be formatted.\"); }");
     let mut child = Command::new(rustfmt().to_str().unwrap())
         .stdin(Stdio::piped())
@@ -694,7 +689,7 @@ fn read_significant_comments(file_name: &Path) -> HashMap<String, String> {
     reader
         .lines()
         .map(|line| line.expect("failed getting line"))
-        .take_while(|line| line_regex.is_match(line))
+        .filter(|line| line_regex.is_match(line))
         .filter_map(|line| {
             regex.captures_iter(&line).next().map(|capture| {
                 (
index 76bf58e875b1f6d48218fce5a909ac010ddd2b40..62c05ba078c56facce55f848d2b4cee53e0a1c78 100644 (file)
@@ -169,31 +169,38 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
             SegmentParam::Const(const_) => const_.rewrite(context, shape),
             SegmentParam::LifeTime(lt) => lt.rewrite(context, shape),
             SegmentParam::Type(ty) => ty.rewrite(context, shape),
-            SegmentParam::Binding(assoc_ty_constraint) => {
-                let mut result = match assoc_ty_constraint.kind {
-                    ast::AssocTyConstraintKind::Bound { .. } => {
-                        format!("{}: ", rewrite_ident(context, assoc_ty_constraint.ident))
-                    }
-                    ast::AssocTyConstraintKind::Equality { .. } => {
-                        match context.config.type_punctuation_density() {
-                            TypeDensity::Wide => {
-                                format!("{} = ", rewrite_ident(context, assoc_ty_constraint.ident))
-                            }
-                            TypeDensity::Compressed => {
-                                format!("{}=", rewrite_ident(context, assoc_ty_constraint.ident))
-                            }
-                        }
-                    }
-                };
+            SegmentParam::Binding(atc) => atc.rewrite(context, shape),
+        }
+    }
+}
 
-                let budget = shape.width.checked_sub(result.len())?;
-                let rewrite = assoc_ty_constraint
-                    .kind
-                    .rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
-                result.push_str(&rewrite);
-                Some(result)
-            }
+impl Rewrite for ast::AssocTyConstraint {
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
+        use ast::AssocTyConstraintKind::{Bound, Equality};
+
+        let mut result = String::with_capacity(128);
+        result.push_str(rewrite_ident(context, self.ident));
+
+        if let Some(ref gen_args) = self.gen_args {
+            let budget = shape.width.checked_sub(result.len())?;
+            let shape = Shape::legacy(budget, shape.indent + result.len());
+            let gen_str = rewrite_generic_args(gen_args, context, shape, gen_args.span())?;
+            result.push_str(&gen_str);
         }
+
+        let infix = match (&self.kind, context.config.type_punctuation_density()) {
+            (Bound { .. }, _) => ": ",
+            (Equality { .. }, TypeDensity::Wide) => " = ",
+            (Equality { .. }, TypeDensity::Compressed) => "=",
+        };
+        result.push_str(infix);
+
+        let budget = shape.width.checked_sub(result.len())?;
+        let shape = Shape::legacy(budget, shape.indent + result.len());
+        let rewrite = self.kind.rewrite(context, shape)?;
+        result.push_str(&rewrite);
+
+        Some(result)
     }
 }
 
@@ -235,21 +242,9 @@ fn rewrite_segment(
     };
 
     if let Some(ref args) = segment.args {
+        let generics_str = rewrite_generic_args(args, context, shape, mk_sp(*span_lo, span_hi))?;
         match **args {
             ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
-                let param_list = data
-                    .args
-                    .iter()
-                    .map(|x| match x {
-                        ast::AngleBracketedArg::Arg(generic_arg) => {
-                            SegmentParam::from_generic_arg(generic_arg)
-                        }
-                        ast::AngleBracketedArg::Constraint(constraint) => {
-                            SegmentParam::Binding(constraint)
-                        }
-                    })
-                    .collect::<Vec<_>>();
-
                 // HACK: squeeze out the span between the identifier and the parameters.
                 // The hack is requried so that we don't remove the separator inside macro calls.
                 // This does not work in the presence of comment, hoping that people are
@@ -265,33 +260,14 @@ fn rewrite_segment(
                 };
                 result.push_str(separator);
 
-                let generics_str = overflow::rewrite_with_angle_brackets(
-                    context,
-                    "",
-                    param_list.iter(),
-                    shape,
-                    mk_sp(*span_lo, span_hi),
-                )?;
-
                 // Update position of last bracket.
                 *span_lo = context
                     .snippet_provider
                     .span_after(mk_sp(*span_lo, span_hi), "<");
-
-                result.push_str(&generics_str)
-            }
-            ast::GenericArgs::Parenthesized(ref data) => {
-                result.push_str(&format_function_type(
-                    data.inputs.iter().map(|x| &**x),
-                    &data.output,
-                    false,
-                    data.span,
-                    context,
-                    shape,
-                )?);
             }
             _ => (),
         }
+        result.push_str(&generics_str)
     }
 
     Some(result)
@@ -484,6 +460,41 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
     }
 }
 
+fn rewrite_generic_args(
+    gen_args: &ast::GenericArgs,
+    context: &RewriteContext<'_>,
+    shape: Shape,
+    span: Span,
+) -> Option<String> {
+    match gen_args {
+        ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
+            let args = data
+                .args
+                .iter()
+                .map(|x| match x {
+                    ast::AngleBracketedArg::Arg(generic_arg) => {
+                        SegmentParam::from_generic_arg(generic_arg)
+                    }
+                    ast::AngleBracketedArg::Constraint(constraint) => {
+                        SegmentParam::Binding(constraint)
+                    }
+                })
+                .collect::<Vec<_>>();
+
+            overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span)
+        }
+        ast::GenericArgs::Parenthesized(ref data) => format_function_type(
+            data.inputs.iter().map(|x| &**x),
+            &data.output,
+            false,
+            data.span,
+            context,
+            shape,
+        ),
+        _ => Some("".to_owned()),
+    }
+}
+
 fn rewrite_bounded_lifetime(
     lt: &ast::Lifetime,
     bounds: &[ast::GenericBound],
@@ -566,13 +577,23 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
         if let ast::GenericParamKind::Const {
             ref ty,
             kw_span: _,
-            default: _,
+            default,
         } = &self.kind
         {
             result.push_str("const ");
             result.push_str(rewrite_ident(context, self.ident));
             result.push_str(": ");
             result.push_str(&ty.rewrite(context, shape)?);
+            if let Some(default) = default {
+                let eq_str = match context.config.type_punctuation_density() {
+                    TypeDensity::Compressed => "=",
+                    TypeDensity::Wide => " = ",
+                };
+                result.push_str(eq_str);
+                let budget = shape.width.checked_sub(result.len())?;
+                let rewrite = default.rewrite(context, Shape::legacy(budget, shape.indent))?;
+                result.push_str(&rewrite);
+            }
         } else {
             result.push_str(rewrite_ident(context, self.ident));
         }
index 770693d165b7ee142919fdb8bef986260a28462e..d854d90b40b6d9d33e7f7ff4917d8c872c97f6a5 100644 (file)
@@ -3,7 +3,7 @@
 
 use rustc_ast::{ast, token::DelimToken, visit, AstLike};
 use rustc_data_structures::sync::Lrc;
-use rustc_span::{symbol, BytePos, Pos, Span, DUMMY_SP};
+use rustc_span::{symbol, BytePos, Pos, Span};
 
 use crate::attr::*;
 use crate::comment::{contains_comment, rewrite_comment, CodeCharKind, CommentCodeSlices};
@@ -11,9 +11,9 @@
 use crate::config::{BraceStyle, Config};
 use crate::coverage::transform_missing_snippet;
 use crate::items::{
-    format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item,
-    rewrite_associated_impl_type, rewrite_extern_crate, rewrite_opaque_impl_type,
-    rewrite_opaque_type, rewrite_type_alias, FnBraceStyle, FnSig, StaticParts, StructParts,
+    format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_extern_crate,
+    rewrite_impl_type, rewrite_opaque_type, rewrite_type, FnBraceStyle, FnSig, StaticParts,
+    StructParts,
 };
 use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition};
 use crate::modules::Module;
@@ -568,6 +568,7 @@ pub(crate) fn visit_item(&mut self, item: &ast::Item) {
                             indent,
                             item.ident,
                             &fn_signature,
+                            &item.vis,
                             generics,
                             item.span,
                         );
@@ -579,14 +580,14 @@ pub(crate) fn visit_item(&mut self, item: &ast::Item) {
                         **alias_kind;
                     match ty {
                         Some(ty) => {
-                            let rewrite = rewrite_type_alias(
-                                item.ident,
-                                Some(&*ty),
-                                generics,
-                                Some(generic_bounds),
+                            let rewrite = rewrite_type(
                                 &self.get_context(),
                                 self.block_indent,
+                                item.ident,
                                 &item.vis,
+                                generics,
+                                Some(generic_bounds),
+                                Some(&*ty),
                                 item.span,
                             );
                             self.push_rewrite(item.span, rewrite);
@@ -641,14 +642,9 @@ pub(crate) fn visit_trait_item(&mut self, ti: &ast::AssocItem) {
                 let ast::FnKind(defaultness, ref sig, ref generics, ref block) = **fn_kind;
                 if let Some(ref body) = block {
                     let inner_attrs = inner_attributes(&ti.attrs);
-                    let vis = ast::Visibility {
-                        kind: ast::VisibilityKind::Inherited,
-                        span: DUMMY_SP,
-                        tokens: None,
-                    };
                     let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Trait);
                     self.visit_fn(
-                        visit::FnKind::Fn(fn_ctxt, ti.ident, sig, &vis, Some(body)),
+                        visit::FnKind::Fn(fn_ctxt, ti.ident, sig, &ti.vis, Some(body)),
                         generics,
                         &sig.decl,
                         ti.span,
@@ -658,21 +654,21 @@ pub(crate) fn visit_trait_item(&mut self, ti: &ast::AssocItem) {
                 } else {
                     let indent = self.block_indent;
                     let rewrite =
-                        self.rewrite_required_fn(indent, ti.ident, sig, generics, ti.span);
+                        self.rewrite_required_fn(indent, ti.ident, sig, &ti.vis, generics, ti.span);
                     self.push_rewrite(ti.span, rewrite);
                 }
             }
             ast::AssocItemKind::TyAlias(ref ty_alias_kind) => {
                 let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref type_default) =
                     **ty_alias_kind;
-                let rewrite = rewrite_type_alias(
-                    ti.ident,
-                    type_default.as_ref(),
-                    generics,
-                    Some(generic_bounds),
+                let rewrite = rewrite_type(
                     &self.get_context(),
                     self.block_indent,
+                    ti.ident,
                     &ti.vis,
+                    generics,
+                    Some(generic_bounds),
+                    type_default.as_ref(),
                     ti.span,
                 );
                 self.push_rewrite(ti.span, rewrite);
@@ -708,15 +704,16 @@ pub(crate) fn visit_impl_item(&mut self, ii: &ast::AssocItem) {
                 } else {
                     let indent = self.block_indent;
                     let rewrite =
-                        self.rewrite_required_fn(indent, ii.ident, sig, generics, ii.span);
+                        self.rewrite_required_fn(indent, ii.ident, sig, &ii.vis, generics, ii.span);
                     self.push_rewrite(ii.span, rewrite);
                 }
             }
             ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_impl_item(ii)),
             ast::AssocItemKind::TyAlias(ref ty_alias_kind) => {
                 let ast::TyAliasKind(defaultness, ref generics, _, ref ty) = **ty_alias_kind;
-                let rewrite_associated = || {
-                    rewrite_associated_impl_type(
+                self.push_rewrite(
+                    ii.span,
+                    rewrite_impl_type(
                         ii.ident,
                         &ii.vis,
                         defaultness,
@@ -725,22 +722,8 @@ pub(crate) fn visit_impl_item(&mut self, ii: &ast::AssocItem) {
                         &self.get_context(),
                         self.block_indent,
                         ii.span,
-                    )
-                };
-                let rewrite = match ty {
-                    None => rewrite_associated(),
-                    Some(ty) => match ty.kind {
-                        ast::TyKind::ImplTrait(_, ref bounds) => rewrite_opaque_impl_type(
-                            &self.get_context(),
-                            ii.ident,
-                            generics,
-                            bounds,
-                            self.block_indent,
-                        ),
-                        _ => rewrite_associated(),
-                    },
-                };
-                self.push_rewrite(ii.span, rewrite);
+                    ),
+                );
             }
             ast::AssocItemKind::MacCall(ref mac) => {
                 self.visit_mac(mac, Some(ii.ident), MacroPosition::Item);
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/Cargo.toml
new file mode 100644 (file)
index 0000000..315364a
--- /dev/null
@@ -0,0 +1,13 @@
+[package]
+name = "cargo-fmt-test"
+version = "0.1.0"
+authors = ["calebcartwright"]
+edition = "2018"
+
+[dependencies]
+indexmap = "1.0.2"
+
+[workspace]
+members = [
+  "dependency-dir-name",
+]
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/dependency-dir-name/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/dependency-dir-name/Cargo.toml
new file mode 100644 (file)
index 0000000..4493882
--- /dev/null
@@ -0,0 +1,10 @@
+[package]
+name = "dependency-crate-name"
+version = "0.1.0"
+authors = ["calebcartwright"]
+edition = "2018"
+
+[dependencies]
+subdep-crate-name = { path = "subdep-dir-name" }
+indexmap = "1.0.2"
+rusty-hook = "0.8.4"
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/dependency-dir-name/src/lib.rs b/src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/dependency-dir-name/src/lib.rs
new file mode 100644 (file)
index 0000000..e93b18d
--- /dev/null
@@ -0,0 +1,7 @@
+#[cfg(test)]
+mod tests {
+#[test]
+fn it_works() {
+    assert_eq!(2 + 2, 4);
+}
+}
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/dependency-dir-name/subdep-dir-name/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/dependency-dir-name/subdep-dir-name/Cargo.toml
new file mode 100644 (file)
index 0000000..7dad09f
--- /dev/null
@@ -0,0 +1,7 @@
+[package]
+name = "subdep-crate-name"
+version = "0.1.0"
+authors = ["calebcartwright"]
+edition = "2018"
+
+[dependencies]
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/dependency-dir-name/subdep-dir-name/src/lib.rs b/src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/dependency-dir-name/subdep-dir-name/src/lib.rs
new file mode 100644 (file)
index 0000000..1c08c1c
--- /dev/null
@@ -0,0 +1,7 @@
+#[cfg(test)]
+mod tests {
+#[test]
+fn sub_test_that_works() {
+    assert_eq!(3 + 3, 6);
+}
+ }
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/src/main.rs b/src/tools/rustfmt/tests/cargo-fmt/source/divergent-crate-dir-names/src/main.rs
new file mode 100644 (file)
index 0000000..f5c339a
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+println!("Hello, world!");
+}
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/e/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/e/Cargo.toml
new file mode 100644 (file)
index 0000000..eaf1d76
--- /dev/null
@@ -0,0 +1,8 @@
+[package]
+name = "e"
+version = "0.1.0"
+edition = "2018"
+[dependencies]
+c = { path = "../ws/c" }
+
+[workspace]
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/e/src/main.rs b/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/e/src/main.rs
new file mode 100644 (file)
index 0000000..1c26a38
--- /dev/null
@@ -0,0 +1 @@
+struct E{   }
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/Cargo.toml
new file mode 100644 (file)
index 0000000..202739b
--- /dev/null
@@ -0,0 +1,5 @@
+[workspace]
+members = [
+    "a",
+    "b"
+] 
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/Cargo.toml
new file mode 100644 (file)
index 0000000..712a113
--- /dev/null
@@ -0,0 +1,6 @@
+[package]
+name = "a"
+version = "0.1.0"
+edition = "2018"
+[dependencies]
+d = { path = "./d" }
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/d/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/d/Cargo.toml
new file mode 100644 (file)
index 0000000..fb0f06f
--- /dev/null
@@ -0,0 +1,7 @@
+[package]
+name = "d"
+version = "0.1.0"
+edition = "2018"
+[dependencies]
+e = { path = "../../../e" }
+f = { path = "f" }
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/d/f/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/d/f/Cargo.toml
new file mode 100644 (file)
index 0000000..5c4fa56
--- /dev/null
@@ -0,0 +1,4 @@
+[package]
+name = "f"
+version = "0.1.0"
+edition = "2018"
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/d/f/src/lib.rs b/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/d/f/src/lib.rs
new file mode 100644 (file)
index 0000000..c655c4d
--- /dev/null
@@ -0,0 +1 @@
+struct F{   }
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/d/src/lib.rs b/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/d/src/lib.rs
new file mode 100644 (file)
index 0000000..04e6e4c
--- /dev/null
@@ -0,0 +1 @@
+struct D{   }
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/src/main.rs b/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/a/src/main.rs
new file mode 100644 (file)
index 0000000..04e6e4c
--- /dev/null
@@ -0,0 +1 @@
+struct D{   }
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/b/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/b/Cargo.toml
new file mode 100644 (file)
index 0000000..47a24ff
--- /dev/null
@@ -0,0 +1,6 @@
+[package]
+name = "b"
+version = "0.1.0"
+edition = "2018"
+[dependencies]
+c = { path = "../c" }
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/b/src/main.rs b/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/b/src/main.rs
new file mode 100644 (file)
index 0000000..4833bbc
--- /dev/null
@@ -0,0 +1 @@
+struct B{   }
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/c/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/c/Cargo.toml
new file mode 100644 (file)
index 0000000..49fa6c3
--- /dev/null
@@ -0,0 +1,4 @@
+[package]
+name = "c"
+version = "0.1.0"
+edition = "2018"
diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/c/src/lib.rs b/src/tools/rustfmt/tests/cargo-fmt/source/workspaces/path-dep-above/ws/c/src/lib.rs
new file mode 100644 (file)
index 0000000..1245ac9
--- /dev/null
@@ -0,0 +1 @@
+struct C{   }
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/source/binop-separator-back/bitwise.rs b/src/tools/rustfmt/tests/source/binop-separator-back/bitwise.rs
new file mode 100644 (file)
index 0000000..3804bf3
--- /dev/null
@@ -0,0 +1,14 @@
+// rustfmt-binop_separator: Back
+
+fn main() {
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ^ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ & abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ | abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ << abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >> abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+}
diff --git a/src/tools/rustfmt/tests/source/binop-separator-back/comp.rs b/src/tools/rustfmt/tests/source/binop-separator-back/comp.rs
new file mode 100644 (file)
index 0000000..50a2712
--- /dev/null
@@ -0,0 +1,23 @@
+// rustfmt-binop_separator: Back
+
+fn main() {
+    if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ < abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+        //
+    }
+
+    if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ <= abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+        //
+    }
+
+    if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ > abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+        //
+    }
+
+    if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >= abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+        //
+    }
+
+    if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ == abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+        //
+    }
+}
diff --git a/src/tools/rustfmt/tests/source/binop-separator-back/logic.rs b/src/tools/rustfmt/tests/source/binop-separator-back/logic.rs
new file mode 100644 (file)
index 0000000..8c297e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rustfmt-binop_separator: Back
+
+fn main() {
+    if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ && abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ || abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+        //
+    }
+}
diff --git a/src/tools/rustfmt/tests/source/binop-separator-back/math.rs b/src/tools/rustfmt/tests/source/binop-separator-back/math.rs
new file mode 100644 (file)
index 0000000..3af4aad
--- /dev/null
@@ -0,0 +1,7 @@
+// rustfmt-binop_separator: Back
+
+fn main() {
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ * abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ - abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ / abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ * abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ * abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ / abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ / abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
diff --git a/src/tools/rustfmt/tests/source/binop-separator-back/patterns.rs b/src/tools/rustfmt/tests/source/binop-separator-back/patterns.rs
new file mode 100644 (file)
index 0000000..a8c3b5c
--- /dev/null
@@ -0,0 +1,9 @@
+// rustfmt-binop_separator: Back
+
+fn main() {
+    match val {
+    ThisIsA::ReallyLongPatternNameToHelpOverflowTheNextValueOntoTheNextLine | ThisIsA::SecondValueSeparatedByAPipe | ThisIsA::ThirdValueSeparatedByAPipe => {
+    //
+    }
+    }
+}
diff --git a/src/tools/rustfmt/tests/source/binop-separator-back/range.rs b/src/tools/rustfmt/tests/source/binop-separator-back/range.rs
new file mode 100644 (file)
index 0000000..bdd3de9
--- /dev/null
@@ -0,0 +1,7 @@
+// rustfmt-binop_separator: Back
+
+fn main() {
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ..abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ..=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
diff --git a/src/tools/rustfmt/tests/source/configs/format_generated_files/false.rs b/src/tools/rustfmt/tests/source/configs/format_generated_files/false.rs
new file mode 100644 (file)
index 0000000..dec1e00
--- /dev/null
@@ -0,0 +1,8 @@
+// @generated
+// rustfmt-format_generated_files: false
+
+fn main()
+{
+    println!("hello, world")
+    ;
+}
diff --git a/src/tools/rustfmt/tests/source/configs/format_generated_files/true.rs b/src/tools/rustfmt/tests/source/configs/format_generated_files/true.rs
new file mode 100644 (file)
index 0000000..a25ddc2
--- /dev/null
@@ -0,0 +1,8 @@
+// @generated
+// rustfmt-format_generated_files: true
+
+fn main()
+{
+    println!("hello, world")
+    ;
+}
diff --git a/src/tools/rustfmt/tests/source/hex_literal_lower.rs b/src/tools/rustfmt/tests/source/hex_literal_lower.rs
new file mode 100644 (file)
index 0000000..ce307b3
--- /dev/null
@@ -0,0 +1,5 @@
+// rustfmt-hex_literal_case: Lower
+fn main() {
+    let h1 = 0xCAFE_5EA7;
+    let h2 = 0xCAFE_F00Du32;
+}
diff --git a/src/tools/rustfmt/tests/source/hex_literal_upper.rs b/src/tools/rustfmt/tests/source/hex_literal_upper.rs
new file mode 100644 (file)
index 0000000..b1092ad
--- /dev/null
@@ -0,0 +1,5 @@
+// rustfmt-hex_literal_case: Upper
+fn main() {
+    let h1 = 0xCaFE_5ea7;
+    let h2 = 0xCAFE_F00Du32;
+}
index fb8701989fa1912fc004e0a4a56e71febd0fcf2f..dcd1f0cd5b09de29ed9f0eec68745c0488aa438c 100644 (file)
@@ -13,6 +13,14 @@ fn foo() { "hi" }
     // Comment 3
 }
 
+#[inherent]
+impl Visible for Bar {
+    pub const C: i32;
+    pub type T;
+    pub fn f();
+    pub fn g() {}
+}
+
 pub unsafe impl<'a, 'b, X, Y: Foo<Bar>> !Foo<'a, X> for Bar<'b, Y> where X: Foo<'a, Z> {
     fn foo() { "hi" }    
 }
diff --git a/src/tools/rustfmt/tests/source/imports_granularity_one.rs b/src/tools/rustfmt/tests/source/imports_granularity_one.rs
new file mode 100644 (file)
index 0000000..c21707d
--- /dev/null
@@ -0,0 +1,60 @@
+// rustfmt-imports_granularity: One
+
+use b;
+use a::ac::{aca, acb};
+use a::{aa::*, ab};
+
+use a as x;
+use b::ba;
+use a::{aa, ab};
+
+use a::aa::aaa;
+use a::ab::aba as x;
+use a::aa::*;
+
+use a::aa;
+use a::ad::ada;
+#[cfg(test)]
+use a::{ab, ac::aca};
+use b;
+#[cfg(test)]
+use b::{
+    ba, bb,
+    bc::bca::{bcaa, bcab},
+};
+
+pub use a::aa;
+pub use a::ae;
+use a::{ab, ac, ad};
+use b::ba;
+pub use b::{bb, bc::bca};
+
+use a::aa::aaa;
+use a::ac::{aca, acb};
+use a::{aa::*, ab};
+use b::{
+    ba,
+    bb::{self, bba},
+};
+
+use crate::a;
+use crate::b::ba;
+use c::ca;
+
+use super::a;
+use c::ca;
+use super::b::ba;
+
+use crate::a;
+use super::b;
+use c::{self, ca};
+
+use a::{
+    // some comment
+    aa::{aaa, aab},
+    ab,
+    // another comment
+    ac::aca,
+};
+use b as x;
+use a::ad::ada;
diff --git a/src/tools/rustfmt/tests/source/issue-3158.rs b/src/tools/rustfmt/tests/source/issue-3158.rs
new file mode 100644 (file)
index 0000000..315073d
--- /dev/null
@@ -0,0 +1,74 @@
+// rustfmt-format_code_in_doc_comments: true
+
+/// Should format
+/// ```rust
+/// assert!( false );
+/// ```
+///
+/// Should format
+/// ```rust,should_panic
+/// assert!( false );
+/// ```
+///
+/// Should format
+/// ```rust,should_panic,edition2018
+/// assert!( false );
+/// ```
+///
+/// Should format
+/// ```rust , should_panic , edition2018
+/// assert!( false );
+/// ```
+///
+/// Should not format
+/// ```ignore
+/// assert!( false );
+/// ```
+///
+/// Should not format (not all are rust)
+/// ```rust,ignore
+/// assert!( false );
+/// ```
+///
+/// Should not format (rust compile_fail)
+/// ```compile_fail
+/// assert!( false );
+/// ```
+///
+/// Should not format (rust compile_fail)
+/// ```rust,compile_fail
+/// assert!( false );
+/// ```
+///
+/// Various unspecified ones that should format
+/// ```
+/// assert!( false );
+/// ```
+///
+/// ```,
+/// assert!( false );
+/// ```
+///
+/// ```,,,,,
+/// assert!( false );
+/// ```
+///
+/// ```,,,  rust  ,,
+/// assert!( false );
+/// ```
+///
+/// Should not format
+/// ```,,,  rust  ,  ignore,
+/// assert!( false );
+/// ```
+///
+/// Few empty ones
+/// ```
+/// ```
+///
+/// ```rust
+/// ```
+///
+/// ```ignore
+/// ```
+fn foo() {}
diff --git a/src/tools/rustfmt/tests/source/issue-4530.rs b/src/tools/rustfmt/tests/source/issue-4530.rs
new file mode 100644 (file)
index 0000000..9d2882a
--- /dev/null
@@ -0,0 +1,4 @@
+// rustfmt-version: Two
+fn main() {
+    let [aaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccc, ddddddddddddddddddddddddd] = panic!();
+}
diff --git a/src/tools/rustfmt/tests/source/issue-4615/minimum_example.rs b/src/tools/rustfmt/tests/source/issue-4615/minimum_example.rs
new file mode 100644 (file)
index 0000000..89af5d1
--- /dev/null
@@ -0,0 +1,4 @@
+info!(//debug
+    "{}: sending function_code={:04x} data={:04x} crc=0x{:04X} data={:02X?}",
+    self.name, function_code, data, crc, output_cmd
+);
diff --git a/src/tools/rustfmt/tests/source/issue-4816/lib.rs b/src/tools/rustfmt/tests/source/issue-4816/lib.rs
new file mode 100644 (file)
index 0000000..43d540c
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(const_generics_defaults)]
+struct Foo<const N: usize    =  1, const N2: usize =           2>;
+struct Bar<const N: usize, const N2: usize = {      N + 
+1 }>;
+struct Lots<const N1BlahFooUwU: usize = { 10 + 28 + 1872 / 10 * 3 },const N2SecondParamOhmyyy: usize = { N1BlahFooUwU / 2 + 10 * 2 },>;
+struct NamesRHard<const N: usize = { 1 + 1 + 1 + 1 + 1 + 1 }>;
+struct FooBar<
+    const LessThan100ButClose: usize = {1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1}
+>;
+struct FooBarrrrrrrr<const N: usize        =           {13478234326456456444323871+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+1+1+1 + 1},>;
diff --git a/src/tools/rustfmt/tests/source/issue-4926/deeply_nested_struct.rs b/src/tools/rustfmt/tests/source/issue-4926/deeply_nested_struct.rs
new file mode 100644 (file)
index 0000000..e55e41b
--- /dev/null
@@ -0,0 +1,35 @@
+
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+    a: i32,
+    b: i32,
+    c: i32,
+}
+
+fn test(x: X) {
+    let d = {
+        let e = {
+            let f = {
+                let g = {
+                    let h = {
+                        let i = {
+                            let j = {
+                                matches!(
+                                    x,
+                                    X { a: 1_000, b: 1_000, .. }
+                                )
+                            };
+                            j
+                        };
+                        i
+                    };
+                    h
+                };
+                g
+            };
+            f
+        };
+        e
+    };
+}
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/source/issue-4926/deeply_nested_struct_with_long_field_names.rs b/src/tools/rustfmt/tests/source/issue-4926/deeply_nested_struct_with_long_field_names.rs
new file mode 100644 (file)
index 0000000..516699f
--- /dev/null
@@ -0,0 +1,43 @@
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+    really_really_long_field_a: i32,
+    really_really_really_long_field_b: i32,
+    really_really_really_really_long_field_c: i32,
+    really_really_really_really_really_long_field_d: i32,
+    really_really_really_really_really_really_long_field_e: i32,
+    f: i32,
+}
+
+fn test(x: X) {
+    let d = {
+        let e = {
+            let f = {
+                let g = {
+                    let h = {
+                        let i = {
+                            let j = {
+                                matches!(
+                                    x,
+                                    X {
+                                        really_really_long_field_a: 10,
+                                        really_really_really_long_field_b: 10,
+                                        really_really_really_really_long_field_c: 10,
+                                        really_really_really_really_really_long_field_d: 10,
+                                        really_really_really_really_really_really_long_field_e: 10, ..
+                                    }
+                                )
+                            };
+                            j
+                        };
+                        i
+                    };
+                    h
+                };
+                g
+            };
+            f
+        };
+        e
+    };
+}
diff --git a/src/tools/rustfmt/tests/source/issue-4926/deeply_nested_struct_with_many_fields.rs b/src/tools/rustfmt/tests/source/issue-4926/deeply_nested_struct_with_many_fields.rs
new file mode 100644 (file)
index 0000000..38fd6f0
--- /dev/null
@@ -0,0 +1,44 @@
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+    a: i32,
+    b: i32,
+    c: i32,
+    d: i32,
+    e: i32,
+    f: i32,
+    g: i32,
+    h: i32,
+    i: i32,
+    j: i32,
+    k: i32,
+}
+
+fn test(x: X) {
+    let d = {
+        let e = {
+            let f = {
+                let g = {
+                    let h = {
+                        let i = {
+                            let j = {
+                                matches!(
+                                    x,
+                                    X {
+                                        a: 1_000, b: 1_000, c: 1_000, d: 1_000, e: 1_000, f: 1_000, g: 1_000, h: 1_000, i: 1_000, j: 1_000, ..
+                                    }
+                                )
+                            };
+                            j
+                        };
+                        i
+                    };
+                    h
+                };
+                g
+            };
+            f
+        };
+        e
+    };
+}
diff --git a/src/tools/rustfmt/tests/source/issue-4926/enum_struct_field.rs b/src/tools/rustfmt/tests/source/issue-4926/enum_struct_field.rs
new file mode 100644 (file)
index 0000000..3363785
--- /dev/null
@@ -0,0 +1,35 @@
+// rustfmt-struct_field_align_threshold: 30
+// rustfmt-enum_discrim_align_threshold: 30
+// rustfmt-imports_layout: HorizontalVertical
+
+#[derive(Default)]
+struct InnerStructA { bbbbbbbbb: i32, cccccccc: i32 }
+
+enum SomeEnumNamedD {
+    E(InnerStructA),
+    F {
+        ggggggggggggggggggggggggg: bool,
+        h: bool,
+    }
+}
+
+impl SomeEnumNamedD {
+    fn f_variant() -> Self {
+        Self::F { ggggggggggggggggggggggggg: true, h: true }
+    }
+}
+
+fn main() {
+    let kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk = SomeEnumNamedD::f_variant();
+    let something_we_care_about = matches!(
+        kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk,
+        SomeEnumNamedD::F {
+            ggggggggggggggggggggggggg: true,
+            ..
+        }
+    );
+
+    if something_we_care_about {
+        println!("Yup it happened");
+    }
+}
diff --git a/src/tools/rustfmt/tests/source/issue-4926/minimum_example.rs b/src/tools/rustfmt/tests/source/issue-4926/minimum_example.rs
new file mode 100644 (file)
index 0000000..2c3045d
--- /dev/null
@@ -0,0 +1,10 @@
+// rustfmt-struct_field_align_threshold: 30
+
+struct X { a: i32, b: i32 }
+
+fn test(x: X) {
+    let y = matches!(x, X {
+        a: 1,
+        ..
+    });
+}
diff --git a/src/tools/rustfmt/tests/source/issue-4926/struct_with_long_field_names.rs b/src/tools/rustfmt/tests/source/issue-4926/struct_with_long_field_names.rs
new file mode 100644 (file)
index 0000000..b8a37f0
--- /dev/null
@@ -0,0 +1,21 @@
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+    really_really_long_field_a: i32,
+    really_really_really_long_field_b: i32,
+    really_really_really_really_long_field_c: i32,
+    really_really_really_really_really_long_field_d: i32,
+    really_really_really_really_really_really_long_field_e: i32,
+    f: i32,
+}
+
+fn test(x: X) {
+    let y = matches!(x, X {
+        really_really_long_field_a: 10,
+        really_really_really_long_field_b: 10,
+        really_really_really_really_long_field_c: 10,
+        really_really_really_really_really_long_field_d: 10,
+        really_really_really_really_really_really_long_field_e: 10,
+        ..
+    });
+}
diff --git a/src/tools/rustfmt/tests/source/issue-4926/struct_with_many_fields.rs b/src/tools/rustfmt/tests/source/issue-4926/struct_with_many_fields.rs
new file mode 100644 (file)
index 0000000..4adfd3b
--- /dev/null
@@ -0,0 +1,21 @@
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+    a: i32,
+    b: i32,
+    c: i32,
+    d: i32,
+    e: i32,
+    f: i32,
+    g: i32,
+    h: i32,
+    i: i32,
+    j: i32,
+    k: i32,
+}
+
+fn test(x: X) {
+    let y = matches!(x, X {
+        a: 1_000, b: 1_000, c: 1_000, d: 1_000, e: 1_000, f: 1_000, g: 1_000, h: 1_000, i: 1_000, j: 1_000, ..
+    });
+}
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/source/issue-4984/minimum_example.rs b/src/tools/rustfmt/tests/source/issue-4984/minimum_example.rs
new file mode 100644 (file)
index 0000000..677f873
--- /dev/null
@@ -0,0 +1,2 @@
+#[derive(/*Debug, */Clone)]
+struct Foo;
diff --git a/src/tools/rustfmt/tests/source/issue-4984/multi_line_derive.rs b/src/tools/rustfmt/tests/source/issue-4984/multi_line_derive.rs
new file mode 100644 (file)
index 0000000..73921dd
--- /dev/null
@@ -0,0 +1,20 @@
+#[derive(
+/* ---------- Some really important comment that just had to go inside the derive --------- */
+Debug, Clone, Eq, PartialEq,
+)]
+struct Foo {
+    a: i32,
+    b: T,
+}
+
+#[derive(
+/*
+    Some really important comment that just had to go inside the derive.
+    Also had to be put over multiple lines
+*/
+Debug, Clone, Eq, PartialEq,
+)]
+struct Bar {
+    a: i32,
+    b: T,
+}
diff --git a/src/tools/rustfmt/tests/source/issue-4984/multiple_comments_within.rs b/src/tools/rustfmt/tests/source/issue-4984/multiple_comments_within.rs
new file mode 100644 (file)
index 0000000..eb474a7
--- /dev/null
@@ -0,0 +1,8 @@
+#[derive(
+/* ---------- Some really important comment that just had to go inside the derive --------- */
+Debug, Clone,/* Another comment */Eq, PartialEq,
+)]
+struct Foo {
+    a: i32,
+    b: T,
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5011.rs b/src/tools/rustfmt/tests/source/issue-5011.rs
new file mode 100644 (file)
index 0000000..b482921
--- /dev/null
@@ -0,0 +1,12 @@
+pub(crate) struct ASlash(
+    // hello
+    i32
+);
+
+pub(crate) struct AStar(
+    /* hello */
+    i32
+);
+
+pub(crate) struct BStar(/* hello */ i32);
+
diff --git a/src/tools/rustfmt/tests/source/issue_4032.rs b/src/tools/rustfmt/tests/source/issue_4032.rs
new file mode 100644 (file)
index 0000000..11ded07
--- /dev/null
@@ -0,0 +1,4 @@
+fn a1(#[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] a: u8) {}
+fn b1(#[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] bb: u8) {}
+fn a2(#[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] a: u8) {}
+fn b2(#[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] bb: u8) {}
diff --git a/src/tools/rustfmt/tests/source/issue_4257.rs b/src/tools/rustfmt/tests/source/issue_4257.rs
new file mode 100644 (file)
index 0000000..2b887fa
--- /dev/null
@@ -0,0 +1,13 @@
+#![feature(generic_associated_types)]
+#![allow(incomplete_features)]
+
+trait Trait<T> {
+    type Type<'a> where T: 'a;
+    fn foo(x: &T) -> Self::Type<'_>;
+}
+impl<T> Trait<T> for () {
+    type Type<'a> where T: 'a = &'a T;
+    fn foo(x: &T) -> Self::Type<'_> {
+        x
+    }
+}
diff --git a/src/tools/rustfmt/tests/source/issue_4322.rs b/src/tools/rustfmt/tests/source/issue_4322.rs
new file mode 100644 (file)
index 0000000..b28cc7c
--- /dev/null
@@ -0,0 +1,3 @@
+trait Bar {
+  type X<'a> where Self: 'a;
+}
diff --git a/src/tools/rustfmt/tests/source/issue_4579.rs b/src/tools/rustfmt/tests/source/issue_4579.rs
new file mode 100644 (file)
index 0000000..73f3452
--- /dev/null
@@ -0,0 +1,15 @@
+// rustfmt-hard_tabs: true
+
+#[macro_export]
+macro_rules! main {
+       () => {
+               #[spirv(fragment)]
+               pub fn main_fs(
+                       mut out_color: ::spirv_std::storage_class::Output<Vec4>,
+                       #[spirv(descriptor_set = 1)]iChannelResolution: ::spirv_std::storage_class::UniformConstant<
+                               [::spirv_std::glam::Vec3A; 4],
+                       >,
+               ) {
+               }
+       };
+}
diff --git a/src/tools/rustfmt/tests/source/issue_4911.rs b/src/tools/rustfmt/tests/source/issue_4911.rs
new file mode 100644 (file)
index 0000000..21ef6c6
--- /dev/null
@@ -0,0 +1,6 @@
+#![feature(generic_associated_types)]
+#![feature(min_type_alias_impl_trait)]
+
+impl SomeTrait for SomeType {
+    type SomeGAT<'a> where Self: 'a = impl SomeOtherTrait;
+}
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/source/issue_4943.rs b/src/tools/rustfmt/tests/source/issue_4943.rs
new file mode 100644 (file)
index 0000000..0793b7b
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(generic_associated_types)]
+
+impl SomeStruct {
+    fn process<T>(v: T) -> <Self as GAT>::R<T>
+    where Self: GAT<R<T> = T>
+    {
+        SomeStruct::do_something(v)
+    }
+}
diff --git a/src/tools/rustfmt/tests/source/issue_4954.rs b/src/tools/rustfmt/tests/source/issue_4954.rs
new file mode 100644 (file)
index 0000000..8011c60
--- /dev/null
@@ -0,0 +1,5 @@
+trait Foo {
+  type Arg<'a>;
+}
+
+struct Bar<T>(T) where for<'a> T: Foo<Arg<'a> = ()>;
diff --git a/src/tools/rustfmt/tests/source/issue_4963.rs b/src/tools/rustfmt/tests/source/issue_4963.rs
new file mode 100644 (file)
index 0000000..32e1f6c
--- /dev/null
@@ -0,0 +1,5 @@
+mod test {
+    extern "C" {fn test();}
+}
+
+extern "C" {fn test();}
\ No newline at end of file
index e9daac13bf96f03674eed676d5b8552e5397908e..baa05b79c16175e5001ef80682b31d8cff0fe80b 100644 (file)
@@ -8,6 +8,14 @@ fn foo() {
             "line1";
             "line2"
         }
+        ThisIsA::Guard if true => {
+            "line1";
+            "line2"
+        }
+        ThisIsA::ReallyLongPattern(ThatWillForce::TheGuard, ToWrapOnto::TheFollowingLine) if true => {
+            "line1";
+            "line2"
+        }
         b => (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
               bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb),
     }
index 80ee0188a6baac4ac8cea857a5b789127f97d3e3..b6db9e1590d416a932db52ac89999b221e75d544 100644 (file)
@@ -174,3 +174,10 @@ trait B<'a, 'b, 'c,T> = Debug<'a, T> where for<'b> &'b Self:
     + DDDDDDDD
     + DDDDDDDDD
     + EEEEEEE;
+
+trait Visible {
+    pub const C: i32;
+    pub type T;
+    pub fn f();
+    pub fn g() {}
+}
diff --git a/src/tools/rustfmt/tests/target/binop-separator-back/bitwise.rs b/src/tools/rustfmt/tests/target/binop-separator-back/bitwise.rs
new file mode 100644 (file)
index 0000000..ce32c05
--- /dev/null
@@ -0,0 +1,18 @@
+// rustfmt-binop_separator: Back
+
+fn main() {
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ^
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ &
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ |
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ <<
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >>
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
diff --git a/src/tools/rustfmt/tests/target/binop-separator-back/comp.rs b/src/tools/rustfmt/tests/target/binop-separator-back/comp.rs
new file mode 100644 (file)
index 0000000..efd837b
--- /dev/null
@@ -0,0 +1,33 @@
+// rustfmt-binop_separator: Back
+
+fn main() {
+    if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ <
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+    {
+        //
+    }
+
+    if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ <=
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+    {
+        //
+    }
+
+    if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+    {
+        //
+    }
+
+    if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >=
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+    {
+        //
+    }
+
+    if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ==
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+    {
+        //
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/binop-separator-back/logic.rs b/src/tools/rustfmt/tests/target/binop-separator-back/logic.rs
new file mode 100644 (file)
index 0000000..5f69fd5
--- /dev/null
@@ -0,0 +1,10 @@
+// rustfmt-binop_separator: Back
+
+fn main() {
+    if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ &&
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ||
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+    {
+        //
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/binop-separator-back/math.rs b/src/tools/rustfmt/tests/target/binop-separator-back/math.rs
new file mode 100644 (file)
index 0000000..7a3f27e
--- /dev/null
@@ -0,0 +1,23 @@
+// rustfmt-binop_separator: Back
+
+fn main() {
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ *
+            abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ -
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ /
+            abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ *
+            abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ *
+            abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ /
+            abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ /
+            abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
diff --git a/src/tools/rustfmt/tests/target/binop-separator-back/patterns.rs b/src/tools/rustfmt/tests/target/binop-separator-back/patterns.rs
new file mode 100644 (file)
index 0000000..2e59713
--- /dev/null
@@ -0,0 +1,11 @@
+// rustfmt-binop_separator: Back
+
+fn main() {
+    match val {
+        ThisIsA::ReallyLongPatternNameToHelpOverflowTheNextValueOntoTheNextLine |
+        ThisIsA::SecondValueSeparatedByAPipe |
+        ThisIsA::ThirdValueSeparatedByAPipe => {
+            //
+        }
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/binop-separator-back/range.rs b/src/tools/rustfmt/tests/target/binop-separator-back/range.rs
new file mode 100644 (file)
index 0000000..19e5a81
--- /dev/null
@@ -0,0 +1,9 @@
+// rustfmt-binop_separator: Back
+
+fn main() {
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ..
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+    let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ..=
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
diff --git a/src/tools/rustfmt/tests/target/configs/format_generated_files/false.rs b/src/tools/rustfmt/tests/target/configs/format_generated_files/false.rs
new file mode 100644 (file)
index 0000000..dec1e00
--- /dev/null
@@ -0,0 +1,8 @@
+// @generated
+// rustfmt-format_generated_files: false
+
+fn main()
+{
+    println!("hello, world")
+    ;
+}
diff --git a/src/tools/rustfmt/tests/target/configs/format_generated_files/true.rs b/src/tools/rustfmt/tests/target/configs/format_generated_files/true.rs
new file mode 100644 (file)
index 0000000..5fea7e8
--- /dev/null
@@ -0,0 +1,6 @@
+// @generated
+// rustfmt-format_generated_files: true
+
+fn main() {
+    println!("hello, world");
+}
diff --git a/src/tools/rustfmt/tests/target/hex_literal_lower.rs b/src/tools/rustfmt/tests/target/hex_literal_lower.rs
new file mode 100644 (file)
index 0000000..5c27fde
--- /dev/null
@@ -0,0 +1,5 @@
+// rustfmt-hex_literal_case: Lower
+fn main() {
+    let h1 = 0xcafe_5ea7;
+    let h2 = 0xcafe_f00du32;
+}
diff --git a/src/tools/rustfmt/tests/target/hex_literal_preserve.rs b/src/tools/rustfmt/tests/target/hex_literal_preserve.rs
new file mode 100644 (file)
index 0000000..e8774d0
--- /dev/null
@@ -0,0 +1,5 @@
+// rustfmt-hex_literal_case: Preserve
+fn main() {
+    let h1 = 0xcAfE_5Ea7;
+    let h2 = 0xCaFe_F00du32;
+}
diff --git a/src/tools/rustfmt/tests/target/hex_literal_upper.rs b/src/tools/rustfmt/tests/target/hex_literal_upper.rs
new file mode 100644 (file)
index 0000000..48bb93d
--- /dev/null
@@ -0,0 +1,5 @@
+// rustfmt-hex_literal_case: Upper
+fn main() {
+    let h1 = 0xCAFE_5EA7;
+    let h2 = 0xCAFE_F00Du32;
+}
index bf63f924a33b0d18aa74b7127da01c155496314d..99e02990e417775ba8a9821a501e9ce0d4f0f960 100644 (file)
@@ -21,6 +21,14 @@ fn foo() {
     // Comment 3
 }
 
+#[inherent]
+impl Visible for Bar {
+    pub const C: i32;
+    pub type T;
+    pub fn f();
+    pub fn g() {}
+}
+
 pub unsafe impl<'a, 'b, X, Y: Foo<Bar>> !Foo<'a, X> for Bar<'b, Y>
 where
     X: Foo<'a, Z>,
diff --git a/src/tools/rustfmt/tests/target/imports_granularity_one.rs b/src/tools/rustfmt/tests/target/imports_granularity_one.rs
new file mode 100644 (file)
index 0000000..78ec5e7
--- /dev/null
@@ -0,0 +1,79 @@
+// rustfmt-imports_granularity: One
+
+use {
+    a::{
+        aa::*,
+        ab,
+        ac::{aca, acb},
+    },
+    b,
+};
+
+use {
+    a::{self as x, aa, ab},
+    b::ba,
+};
+
+use a::{
+    aa::{aaa, *},
+    ab::aba as x,
+};
+
+#[cfg(test)]
+use a::{ab, ac::aca};
+#[cfg(test)]
+use b::{
+    ba, bb,
+    bc::bca::{bcaa, bcab},
+};
+use {
+    a::{aa, ad::ada},
+    b,
+};
+
+pub use {
+    a::{aa, ae},
+    b::{bb, bc::bca},
+};
+use {
+    a::{ab, ac, ad},
+    b::ba,
+};
+
+use {
+    a::{
+        aa::{aaa, *},
+        ab,
+        ac::{aca, acb},
+    },
+    b::{
+        ba,
+        bb::{self, bba},
+    },
+};
+
+use {
+    crate::{a, b::ba},
+    c::ca,
+};
+
+use {
+    super::{a, b::ba},
+    c::ca,
+};
+
+use {
+    super::b,
+    crate::a,
+    c::{self, ca},
+};
+
+use {
+    a::{
+        aa::{aaa, aab},
+        ab,
+        ac::aca,
+        ad::ada,
+    },
+    b as x,
+};
diff --git a/src/tools/rustfmt/tests/target/issue-3158.rs b/src/tools/rustfmt/tests/target/issue-3158.rs
new file mode 100644 (file)
index 0000000..4bbbdc1
--- /dev/null
@@ -0,0 +1,74 @@
+// rustfmt-format_code_in_doc_comments: true
+
+/// Should format
+/// ```rust
+/// assert!(false);
+/// ```
+///
+/// Should format
+/// ```rust,should_panic
+/// assert!(false);
+/// ```
+///
+/// Should format
+/// ```rust,should_panic,edition2018
+/// assert!(false);
+/// ```
+///
+/// Should format
+/// ```rust , should_panic , edition2018
+/// assert!(false);
+/// ```
+///
+/// Should not format
+/// ```ignore
+/// assert!( false );
+/// ```
+///
+/// Should not format (not all are rust)
+/// ```rust,ignore
+/// assert!( false );
+/// ```
+///
+/// Should not format (rust compile_fail)
+/// ```compile_fail
+/// assert!( false );
+/// ```
+///
+/// Should not format (rust compile_fail)
+/// ```rust,compile_fail
+/// assert!( false );
+/// ```
+///
+/// Various unspecified ones that should format
+/// ```
+/// assert!(false);
+/// ```
+///
+/// ```,
+/// assert!(false);
+/// ```
+///
+/// ```,,,,,
+/// assert!(false);
+/// ```
+///
+/// ```,,,  rust  ,,
+/// assert!(false);
+/// ```
+///
+/// Should not format
+/// ```,,,  rust  ,  ignore,
+/// assert!( false );
+/// ```
+///
+/// Few empty ones
+/// ```
+/// ```
+///
+/// ```rust
+/// ```
+///
+/// ```ignore
+/// ```
+fn foo() {}
diff --git a/src/tools/rustfmt/tests/target/issue-4530.rs b/src/tools/rustfmt/tests/target/issue-4530.rs
new file mode 100644 (file)
index 0000000..296dc55
--- /dev/null
@@ -0,0 +1,9 @@
+// rustfmt-version: Two
+fn main() {
+    let [
+        aaaaaaaaaaaaaaaaaaaaaaaaaa,
+        bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
+        cccccccccccccccccccccccccc,
+        ddddddddddddddddddddddddd,
+    ] = panic!();
+}
diff --git a/src/tools/rustfmt/tests/target/issue-4615/minimum_example.rs b/src/tools/rustfmt/tests/target/issue-4615/minimum_example.rs
new file mode 100644 (file)
index 0000000..223b89b
--- /dev/null
@@ -0,0 +1,5 @@
+info!(
+    //debug
+    "{}: sending function_code={:04x} data={:04x} crc=0x{:04X} data={:02X?}",
+    self.name, function_code, data, crc, output_cmd
+);
diff --git a/src/tools/rustfmt/tests/target/issue-4816/lib.rs b/src/tools/rustfmt/tests/target/issue-4816/lib.rs
new file mode 100644 (file)
index 0000000..246e775
--- /dev/null
@@ -0,0 +1,35 @@
+#![feature(const_generics_defaults)]
+struct Foo<const N: usize = 1, const N2: usize = 2>;
+struct Bar<const N: usize, const N2: usize = { N + 1 }>;
+struct Lots<
+    const N1BlahFooUwU: usize = { 10 + 28 + 1872 / 10 * 3 },
+    const N2SecondParamOhmyyy: usize = { N1BlahFooUwU / 2 + 10 * 2 },
+>;
+struct NamesRHard<const N: usize = { 1 + 1 + 1 + 1 + 1 + 1 }>;
+struct FooBar<
+    const LessThan100ButClose: usize = {
+        1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
+    },
+>;
+struct FooBarrrrrrrr<
+    const N: usize = {
+        13478234326456456444323871
+            + 1
+            + 1
+            + 1
+            + 1
+            + 1
+            + 1
+            + 1
+            + 1
+            + 1
+            + 1
+            + 1
+            + 1
+            + 1
+            + 1
+            + 1
+            + 1
+            + 1
+    },
+>;
diff --git a/src/tools/rustfmt/tests/target/issue-4908-2.rs b/src/tools/rustfmt/tests/target/issue-4908-2.rs
new file mode 100644 (file)
index 0000000..023b323
--- /dev/null
@@ -0,0 +1,20 @@
+#![feature(more_qualified_paths)]
+
+fn main() {
+    // destructure through a qualified path
+    let <Foo as A>::Assoc { br } = StructStruct { br: 2 };
+}
+
+struct StructStruct {
+    br: i8,
+}
+
+struct Foo;
+
+trait A {
+    type Assoc;
+}
+
+impl A for Foo {
+    type Assoc = StructStruct;
+}
diff --git a/src/tools/rustfmt/tests/target/issue-4908.rs b/src/tools/rustfmt/tests/target/issue-4908.rs
new file mode 100644 (file)
index 0000000..ac5357a
--- /dev/null
@@ -0,0 +1,34 @@
+#![feature(more_qualified_paths)]
+
+mod foo_bar {
+    pub enum Example {
+        Example1 {},
+        Example2 {},
+    }
+}
+
+fn main() {
+    foo!(crate::foo_bar::Example, Example1);
+
+    let i1 = foo_bar::Example::Example1 {};
+
+    assert_eq!(i1.foo_example(), 1);
+
+    let i2 = foo_bar::Example::Example2 {};
+
+    assert_eq!(i2.foo_example(), 2);
+}
+
+#[macro_export]
+macro_rules! foo {
+    ($struct:path, $variant:ident) => {
+        impl $struct {
+            pub fn foo_example(&self) -> i32 {
+                match self {
+                    <$struct>::$variant { .. } => 1,
+                    _ => 2,
+                }
+            }
+        }
+    };
+}
diff --git a/src/tools/rustfmt/tests/target/issue-4926/deeply_nested_struct.rs b/src/tools/rustfmt/tests/target/issue-4926/deeply_nested_struct.rs
new file mode 100644 (file)
index 0000000..072cf2f
--- /dev/null
@@ -0,0 +1,38 @@
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+    a: i32,
+    b: i32,
+    c: i32,
+}
+
+fn test(x: X) {
+    let d = {
+        let e = {
+            let f = {
+                let g = {
+                    let h = {
+                        let i = {
+                            let j = {
+                                matches!(
+                                    x,
+                                    X {
+                                        a: 1_000,
+                                        b: 1_000,
+                                        ..
+                                    }
+                                )
+                            };
+                            j
+                        };
+                        i
+                    };
+                    h
+                };
+                g
+            };
+            f
+        };
+        e
+    };
+}
diff --git a/src/tools/rustfmt/tests/target/issue-4926/deeply_nested_struct_with_long_field_names.rs b/src/tools/rustfmt/tests/target/issue-4926/deeply_nested_struct_with_long_field_names.rs
new file mode 100644 (file)
index 0000000..c7bc7f7
--- /dev/null
@@ -0,0 +1,44 @@
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+    really_really_long_field_a: i32,
+    really_really_really_long_field_b: i32,
+    really_really_really_really_long_field_c: i32,
+    really_really_really_really_really_long_field_d: i32,
+    really_really_really_really_really_really_long_field_e: i32,
+    f: i32,
+}
+
+fn test(x: X) {
+    let d = {
+        let e = {
+            let f = {
+                let g = {
+                    let h = {
+                        let i = {
+                            let j = {
+                                matches!(
+                                    x,
+                                    X {
+                                        really_really_long_field_a: 10,
+                                        really_really_really_long_field_b: 10,
+                                        really_really_really_really_long_field_c: 10,
+                                        really_really_really_really_really_long_field_d: 10,
+                                        really_really_really_really_really_really_long_field_e: 10,
+                                        ..
+                                    }
+                                )
+                            };
+                            j
+                        };
+                        i
+                    };
+                    h
+                };
+                g
+            };
+            f
+        };
+        e
+    };
+}
diff --git a/src/tools/rustfmt/tests/target/issue-4926/deeply_nested_struct_with_many_fields.rs b/src/tools/rustfmt/tests/target/issue-4926/deeply_nested_struct_with_many_fields.rs
new file mode 100644 (file)
index 0000000..6979316
--- /dev/null
@@ -0,0 +1,54 @@
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+    a: i32,
+    b: i32,
+    c: i32,
+    d: i32,
+    e: i32,
+    f: i32,
+    g: i32,
+    h: i32,
+    i: i32,
+    j: i32,
+    k: i32,
+}
+
+fn test(x: X) {
+    let d = {
+        let e = {
+            let f = {
+                let g = {
+                    let h = {
+                        let i = {
+                            let j = {
+                                matches!(
+                                    x,
+                                    X {
+                                        a: 1_000,
+                                        b: 1_000,
+                                        c: 1_000,
+                                        d: 1_000,
+                                        e: 1_000,
+                                        f: 1_000,
+                                        g: 1_000,
+                                        h: 1_000,
+                                        i: 1_000,
+                                        j: 1_000,
+                                        ..
+                                    }
+                                )
+                            };
+                            j
+                        };
+                        i
+                    };
+                    h
+                };
+                g
+            };
+            f
+        };
+        e
+    };
+}
diff --git a/src/tools/rustfmt/tests/target/issue-4926/enum_struct_field.rs b/src/tools/rustfmt/tests/target/issue-4926/enum_struct_field.rs
new file mode 100644 (file)
index 0000000..2471df8
--- /dev/null
@@ -0,0 +1,41 @@
+// rustfmt-struct_field_align_threshold: 30
+// rustfmt-enum_discrim_align_threshold: 30
+// rustfmt-imports_layout: HorizontalVertical
+
+#[derive(Default)]
+struct InnerStructA {
+    bbbbbbbbb: i32,
+    cccccccc:  i32,
+}
+
+enum SomeEnumNamedD {
+    E(InnerStructA),
+    F {
+        ggggggggggggggggggggggggg: bool,
+        h:                         bool,
+    },
+}
+
+impl SomeEnumNamedD {
+    fn f_variant() -> Self {
+        Self::F {
+            ggggggggggggggggggggggggg: true,
+            h:                         true,
+        }
+    }
+}
+
+fn main() {
+    let kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk = SomeEnumNamedD::f_variant();
+    let something_we_care_about = matches!(
+        kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk,
+        SomeEnumNamedD::F {
+            ggggggggggggggggggggggggg: true,
+            ..
+        }
+    );
+
+    if something_we_care_about {
+        println!("Yup it happened");
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/issue-4926/minimum_example.rs b/src/tools/rustfmt/tests/target/issue-4926/minimum_example.rs
new file mode 100644 (file)
index 0000000..06e1842
--- /dev/null
@@ -0,0 +1,10 @@
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+    a: i32,
+    b: i32,
+}
+
+fn test(x: X) {
+    let y = matches!(x, X { a: 1, .. });
+}
diff --git a/src/tools/rustfmt/tests/target/issue-4926/struct_with_long_field_names.rs b/src/tools/rustfmt/tests/target/issue-4926/struct_with_long_field_names.rs
new file mode 100644 (file)
index 0000000..ac4674a
--- /dev/null
@@ -0,0 +1,24 @@
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+    really_really_long_field_a: i32,
+    really_really_really_long_field_b: i32,
+    really_really_really_really_long_field_c: i32,
+    really_really_really_really_really_long_field_d: i32,
+    really_really_really_really_really_really_long_field_e: i32,
+    f: i32,
+}
+
+fn test(x: X) {
+    let y = matches!(
+        x,
+        X {
+            really_really_long_field_a: 10,
+            really_really_really_long_field_b: 10,
+            really_really_really_really_long_field_c: 10,
+            really_really_really_really_really_long_field_d: 10,
+            really_really_really_really_really_really_long_field_e: 10,
+            ..
+        }
+    );
+}
diff --git a/src/tools/rustfmt/tests/target/issue-4926/struct_with_many_fields.rs b/src/tools/rustfmt/tests/target/issue-4926/struct_with_many_fields.rs
new file mode 100644 (file)
index 0000000..96dfe14
--- /dev/null
@@ -0,0 +1,34 @@
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+    a: i32,
+    b: i32,
+    c: i32,
+    d: i32,
+    e: i32,
+    f: i32,
+    g: i32,
+    h: i32,
+    i: i32,
+    j: i32,
+    k: i32,
+}
+
+fn test(x: X) {
+    let y = matches!(
+        x,
+        X {
+            a: 1_000,
+            b: 1_000,
+            c: 1_000,
+            d: 1_000,
+            e: 1_000,
+            f: 1_000,
+            g: 1_000,
+            h: 1_000,
+            i: 1_000,
+            j: 1_000,
+            ..
+        }
+    );
+}
diff --git a/src/tools/rustfmt/tests/target/issue-4984/minimum_example.rs b/src/tools/rustfmt/tests/target/issue-4984/minimum_example.rs
new file mode 100644 (file)
index 0000000..f0599c5
--- /dev/null
@@ -0,0 +1,2 @@
+#[derive(/*Debug, */ Clone)]
+struct Foo;
diff --git a/src/tools/rustfmt/tests/target/issue-4984/multi_line_derive.rs b/src/tools/rustfmt/tests/target/issue-4984/multi_line_derive.rs
new file mode 100644 (file)
index 0000000..5fbd978
--- /dev/null
@@ -0,0 +1,26 @@
+#[derive(
+    /* ---------- Some really important comment that just had to go inside the derive --------- */
+    Debug,
+    Clone,
+    Eq,
+    PartialEq,
+)]
+struct Foo {
+    a: i32,
+    b: T,
+}
+
+#[derive(
+    /*
+        Some really important comment that just had to go inside the derive.
+        Also had to be put over multiple lines
+    */
+    Debug,
+    Clone,
+    Eq,
+    PartialEq,
+)]
+struct Bar {
+    a: i32,
+    b: T,
+}
diff --git a/src/tools/rustfmt/tests/target/issue-4984/multiple_comments_within.rs b/src/tools/rustfmt/tests/target/issue-4984/multiple_comments_within.rs
new file mode 100644 (file)
index 0000000..d2924f0
--- /dev/null
@@ -0,0 +1,11 @@
+#[derive(
+    /* ---------- Some really important comment that just had to go inside the derive --------- */
+    Debug,
+    Clone,
+    /* Another comment */ Eq,
+    PartialEq,
+)]
+struct Foo {
+    a: i32,
+    b: T,
+}
diff --git a/src/tools/rustfmt/tests/target/issue-4984/should_not_change.rs b/src/tools/rustfmt/tests/target/issue-4984/should_not_change.rs
new file mode 100644 (file)
index 0000000..e46ee51
--- /dev/null
@@ -0,0 +1,5 @@
+#[derive(Clone, Debug, Eq, PartialEq)]
+struct Foo;
+
+#[derive(Clone)]
+struct Bar;
diff --git a/src/tools/rustfmt/tests/target/issue-5005/minimum_example.rs b/src/tools/rustfmt/tests/target/issue-5005/minimum_example.rs
new file mode 100644 (file)
index 0000000..11cc645
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(more_qualified_paths)]
+macro_rules! show {
+    ($ty:ty, $ex:expr) => {
+        match $ex {
+            <$ty>::A(_val) => println!("got a"), // formatting should not remove <$ty>::
+            <$ty>::B => println!("got b"),
+        }
+    };
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5009/1_minimum_example.rs b/src/tools/rustfmt/tests/target/issue-5009/1_minimum_example.rs
new file mode 100644 (file)
index 0000000..55836f4
--- /dev/null
@@ -0,0 +1,4 @@
+fn main() {
+    // the "in" inside the pattern produced invalid syntax
+    for variable_in_here /* ... */ in 0..1 {}
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5009/2_many_in_connectors_in_pattern.rs b/src/tools/rustfmt/tests/target/issue-5009/2_many_in_connectors_in_pattern.rs
new file mode 100644 (file)
index 0000000..d83590c
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    for in_in_in_in_in_in_in_in /* ... */ in 0..1 {}
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5009/3_nested_for_loop_with_connector_in_pattern.rs b/src/tools/rustfmt/tests/target/issue-5009/3_nested_for_loop_with_connector_in_pattern.rs
new file mode 100644 (file)
index 0000000..9c80072
--- /dev/null
@@ -0,0 +1,5 @@
+fn main() {
+    for variable_in_x /* ... */ in 0..1 {
+        for variable_in_y /* ... */ in 0..1 {}
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5009/4_nested_for_loop_with_if_elseif_else.rs b/src/tools/rustfmt/tests/target/issue-5009/4_nested_for_loop_with_if_elseif_else.rs
new file mode 100644 (file)
index 0000000..a716d0d
--- /dev/null
@@ -0,0 +1,13 @@
+fn main() {
+    for variable_in_x /* ... */ in 0..1 {
+        for variable_in_y /* ... */ in 0..1 {
+            if false {
+
+            } else if false {
+
+            } else {
+
+            }
+        }
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5009/5_nested_for_loop_with_connector_in_if_elseif_else.rs b/src/tools/rustfmt/tests/target/issue-5009/5_nested_for_loop_with_connector_in_if_elseif_else.rs
new file mode 100644 (file)
index 0000000..41ea46d
--- /dev/null
@@ -0,0 +1,15 @@
+fn main() {
+    let in_ = false;
+
+    for variable_in_x /* ... */ in 0..1 {
+        for variable_in_y /* ... */ in 0..1 {
+            if in_ {
+
+            } else if in_ {
+
+            } else {
+
+            }
+        }
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5009/6_deeply_nested_for_loop_with_connector_in_pattern.rs b/src/tools/rustfmt/tests/target/issue-5009/6_deeply_nested_for_loop_with_connector_in_pattern.rs
new file mode 100644 (file)
index 0000000..789e54f
--- /dev/null
@@ -0,0 +1,32 @@
+fn main() {
+    for variable_in_a /* ... */ in 0..1 {
+        for variable_in_b /* ... */ in 0..1 {
+            for variable_in_c /* ... */ in 0..1 {
+                for variable_in_d /* ... */ in 0..1 {
+                    for variable_in_e /* ... */ in 0..1 {
+                        for variable_in_f /* ... */ in 0..1 {
+                            for variable_in_g /* ... */ in 0..1 {
+                                for variable_in_h /* ... */ in 0..1 {
+                                    for variable_in_i /* ... */ in 0..1 {
+                                        for variable_in_j /* ... */ in 0..1 {
+                                            for variable_in_k /* ... */ in 0..1 {
+                                                for variable_in_l /* ... */ in 0..1 {
+                                                    for variable_in_m /* ... */ in 0..1 {
+                                                        for variable_in_n /* ... */ in 0..1 {
+                                                            for variable_in_o /* ... */ in 0..1 {
+                                                            }
+                                                        }
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5011.rs b/src/tools/rustfmt/tests/target/issue-5011.rs
new file mode 100644 (file)
index 0000000..9ad4a19
--- /dev/null
@@ -0,0 +1,8 @@
+pub(crate) struct ASlash(
+    // hello
+    i32,
+);
+
+pub(crate) struct AStar(/* hello */ i32);
+
+pub(crate) struct BStar(/* hello */ i32);
diff --git a/src/tools/rustfmt/tests/target/issue_4031.rs b/src/tools/rustfmt/tests/target/issue_4031.rs
new file mode 100644 (file)
index 0000000..065d539
--- /dev/null
@@ -0,0 +1,21 @@
+fn foo() {
+    with_woff2_glyf_table("tests/fonts/woff2/SFNT-TTF-Composite.woff2", |glyf| {
+        let actual = glyf
+            .records
+            .iter()
+            .map(|glyph| match glyph {
+                GlyfRecord::Parsed(
+                    found @ Glyph {
+                        data: GlyphData::Composite { .. },
+                        ..
+                    },
+                ) => Some(found),
+                _ => None,
+            })
+            .find(|candidate| candidate.is_some())
+            .unwrap()
+            .unwrap();
+
+        assert_eq!(*actual, expected)
+    });
+}
diff --git a/src/tools/rustfmt/tests/target/issue_4032.rs b/src/tools/rustfmt/tests/target/issue_4032.rs
new file mode 100644 (file)
index 0000000..2e7e624
--- /dev/null
@@ -0,0 +1,18 @@
+fn a1(
+    #[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
+    a: u8,
+) {
+}
+fn b1(
+    #[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
+    bb: u8,
+) {
+}
+fn a2(
+    #[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] a: u8,
+) {
+}
+fn b2(
+    #[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] bb: u8,
+) {
+}
diff --git a/src/tools/rustfmt/tests/target/issue_4110.rs b/src/tools/rustfmt/tests/target/issue_4110.rs
new file mode 100644 (file)
index 0000000..4a58c39
--- /dev/null
@@ -0,0 +1,55 @@
+fn bindings() {
+    let err = match (place_desc, explanation) {
+        (
+            Some(ref name),
+            BorrowExplanation::MustBeValidFor {
+                category:
+                    category @ (ConstraintCategory::Return
+                    | ConstraintCategory::CallArgument
+                    | ConstraintCategory::OpaqueType),
+                from_closure: false,
+                ref region_name,
+                span,
+                ..
+            },
+        ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self
+            .report_escaping_closure_capture(
+                borrow_spans,
+                borrow_span,
+                region_name,
+                category,
+                span,
+                &format!("`{}`", name),
+            ),
+        (
+            ref name,
+            BorrowExplanation::MustBeValidFor {
+                category: ConstraintCategory::Assignment,
+                from_closure: false,
+                region_name:
+                    RegionName {
+                        source: RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name),
+                        ..
+                    },
+                span,
+                ..
+            },
+        ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
+        (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
+            location,
+            &name,
+            &borrow,
+            drop_span,
+            borrow_spans,
+            explanation,
+        ),
+        (None, explanation) => self.report_temporary_value_does_not_live_long_enough(
+            location,
+            &borrow,
+            drop_span,
+            borrow_spans,
+            proper_span,
+            explanation,
+        ),
+    };
+}
diff --git a/src/tools/rustfmt/tests/target/issue_4257.rs b/src/tools/rustfmt/tests/target/issue_4257.rs
new file mode 100644 (file)
index 0000000..1ebaaf2
--- /dev/null
@@ -0,0 +1,18 @@
+#![feature(generic_associated_types)]
+#![allow(incomplete_features)]
+
+trait Trait<T> {
+    type Type<'a>
+    where
+        T: 'a;
+    fn foo(x: &T) -> Self::Type<'_>;
+}
+impl<T> Trait<T> for () {
+    type Type<'a>
+    where
+        T: 'a,
+    = &'a T;
+    fn foo(x: &T) -> Self::Type<'_> {
+        x
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/issue_4322.rs b/src/tools/rustfmt/tests/target/issue_4322.rs
new file mode 100644 (file)
index 0000000..0ec0547
--- /dev/null
@@ -0,0 +1,5 @@
+trait Bar {
+    type X<'a>
+    where
+        Self: 'a;
+}
diff --git a/src/tools/rustfmt/tests/target/issue_4579.rs b/src/tools/rustfmt/tests/target/issue_4579.rs
new file mode 100644 (file)
index 0000000..7b0a5f3
--- /dev/null
@@ -0,0 +1,16 @@
+// rustfmt-hard_tabs: true
+
+#[macro_export]
+macro_rules! main {
+       () => {
+               #[spirv(fragment)]
+               pub fn main_fs(
+                       mut out_color: ::spirv_std::storage_class::Output<Vec4>,
+                       #[spirv(descriptor_set = 1)]
+                       iChannelResolution: ::spirv_std::storage_class::UniformConstant<
+                               [::spirv_std::glam::Vec3A; 4],
+                       >,
+               ) {
+               }
+       };
+}
diff --git a/src/tools/rustfmt/tests/target/issue_4911.rs b/src/tools/rustfmt/tests/target/issue_4911.rs
new file mode 100644 (file)
index 0000000..890a622
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(generic_associated_types)]
+#![feature(min_type_alias_impl_trait)]
+
+impl SomeTrait for SomeType {
+    type SomeGAT<'a>
+    where
+        Self: 'a,
+    = impl SomeOtherTrait;
+}
diff --git a/src/tools/rustfmt/tests/target/issue_4936.rs b/src/tools/rustfmt/tests/target/issue_4936.rs
new file mode 100644 (file)
index 0000000..c19e505
--- /dev/null
@@ -0,0 +1,10 @@
+#[discard_params_doc]
+trait Trait {
+    fn foo(
+        &self,
+        /// some docs
+        bar: String,
+        /// another docs
+        baz: i32,
+    );
+}
diff --git a/src/tools/rustfmt/tests/target/issue_4943.rs b/src/tools/rustfmt/tests/target/issue_4943.rs
new file mode 100644 (file)
index 0000000..318f7eb
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(generic_associated_types)]
+
+impl SomeStruct {
+    fn process<T>(v: T) -> <Self as GAT>::R<T>
+    where
+        Self: GAT<R<T> = T>,
+    {
+        SomeStruct::do_something(v)
+    }
+}
diff --git a/src/tools/rustfmt/tests/target/issue_4954.rs b/src/tools/rustfmt/tests/target/issue_4954.rs
new file mode 100644 (file)
index 0000000..aa5e79b
--- /dev/null
@@ -0,0 +1,7 @@
+trait Foo {
+    type Arg<'a>;
+}
+
+struct Bar<T>(T)
+where
+    for<'a> T: Foo<Arg<'a> = ()>;
diff --git a/src/tools/rustfmt/tests/target/issue_4963.rs b/src/tools/rustfmt/tests/target/issue_4963.rs
new file mode 100644 (file)
index 0000000..0c3c135
--- /dev/null
@@ -0,0 +1,9 @@
+mod test {
+    extern "C" {
+        fn test();
+    }
+}
+
+extern "C" {
+    fn test();
+}
index 44d1f289f8e0f9b541fab7394493e4c4be2c274e..5ab433a2e6cf65d8fff85bbbf19a136e7b181e51 100644 (file)
@@ -8,6 +8,16 @@ fn foo() {
             "line1";
             "line2"
         },
+        ThisIsA::Guard if true => {
+            "line1";
+            "line2"
+        },
+        ThisIsA::ReallyLongPattern(ThatWillForce::TheGuard, ToWrapOnto::TheFollowingLine)
+            if true =>
+        {
+            "line1";
+            "line2"
+        },
         b => (
             aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
             bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
index 620046a71b29bea84f343141ff15836c40dfddaa..7f067991b267b6e905ccdc23299b78b59ccd8552 100644 (file)
@@ -211,3 +211,10 @@ trait B<'a, 'b, 'c, T> = Debug<'a, T>
         + DDDDDDDD
         + DDDDDDDDD
         + EEEEEEE;
+
+trait Visible {
+    pub const C: i32;
+    pub type T;
+    pub fn f();
+    pub fn g() {}
+}
diff --git a/src/tools/rustfmt/triagebot.toml b/src/tools/rustfmt/triagebot.toml
new file mode 100644 (file)
index 0000000..fa0824a
--- /dev/null
@@ -0,0 +1 @@
+[assign]
index b5e9ceddbafd166832874a26c34009ae1b363f60..3f59fefd041ebd9b70852d82fda4fb8f49ed68d9 100644 (file)
@@ -18,21 +18,13 @@ pub fn check(path: &Path, bad: &mut bool) {
         &mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
         &mut |entry, contents| {
             let file = entry.path();
-            let filestr = file.to_string_lossy().replace("\\", "/");
             let filename = file.file_name().unwrap();
             if filename != "Cargo.toml" {
                 return;
             }
 
             // Library crates are not yet ready to migrate to 2021.
-            //
-            // The reference and rustc-dev-guide are submodules, so are left at
-            // 2018 for now. They should be removed from this exception list
-            // when bumped.
-            if path.components().any(|c| c.as_os_str() == "library")
-                || filestr.contains("src/doc/reference/style-check/Cargo.toml")
-                || filestr.contains("src/doc/rustc-dev-guide/ci/date-check/Cargo.toml")
-            {
+            if path.components().any(|c| c.as_os_str() == "library") {
                 let has = contents.lines().any(is_edition_2018);
                 if !has {
                     tidy_error!(
index 338dfd11310aaa0e17d14ac63ef5b115dc00ceff..129237775fe3f803c561c47886048987a92a4170 100644 (file)
@@ -97,6 +97,7 @@ pub fn check(
             &src_path.join("test/ui"),
             &src_path.join("test/ui-fulldeps"),
             &src_path.join("test/rustdoc-ui"),
+            &src_path.join("test/rustdoc"),
         ],
         &mut |path| super::filter_dirs(path),
         &mut |entry, contents| {
index a341527c84cf065d3b6774cc63b3b21a8a7acf8f..4afa36502aca1c063e2caec6a225df919a7e0c5d 100644 (file)
@@ -7,7 +7,7 @@
 
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 1330;
+const ROOT_ENTRY_LIMIT: usize = 1331;
 const ISSUES_ENTRY_LIMIT: usize = 2488;
 
 fn check_entries(path: &Path, bad: &mut bool) {
index 373aea97570a799f495d563956060f172be596a1..79f82f6b8e0ceb99fe26d976bae0285f53a07473 100644 (file)
@@ -1 +1 @@
-1.57.0
+1.58.0
index 1e4df4d3fb79a58185907d63c0574bdeb779ec16..7a9908fe8c0758fcc3047c04b21aa786741d0468 100644 (file)
@@ -2,11 +2,13 @@
 allow-unauthenticated = [
     "C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", "F-*",
     "D-*",
+    "needs-fcp",
+    "relnotes",
     "requires-nightly",
     "regression-*",
     "perf-*",
-    # I-* without I-nominated
-    "I-*", "!I-nominated",
+    # I-* without I-*nominated
+    "I-*", "!I-*nominated",
     "AsyncAwait-OnDeck",
 ]