]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #90202 - matthewjasper:xcrate-hygiene, r=petrochenkov
authorGuillaume Gomez <guillaume1.gomez@gmail.com>
Sat, 30 Oct 2021 18:30:27 +0000 (20:30 +0200)
committerGitHub <noreply@github.com>
Sat, 30 Oct 2021 18:30:27 +0000 (20:30 +0200)
Improve and test cross-crate hygiene

- Decode the parent expansion for traits and enums in `rustc_resolve`, this was already being used for resolution in typeck
- Avoid suggesting importing names with def-site hygiene, since it's often not useful
- Add more tests

r? `@petrochenkov`

868 files changed:
.github/workflows/ci.yml
.mailmap
Cargo.lock
Cargo.toml
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/tokenstream.rs
compiler/rustc_ast_lowering/src/asm.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/index.rs
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_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/lib.rs
compiler/rustc_borrowck/src/type_check/canonical.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_codegen_gcc/src/asm.rs
compiler/rustc_codegen_gcc/src/builder.rs
compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
compiler/rustc_codegen_llvm/src/asm.rs
compiler/rustc_codegen_llvm/src/back/write.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/symbol_export.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/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/machine.rs
compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.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/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/src/lib.rs
compiler/rustc_data_structures/src/sorted_map.rs
compiler/rustc_data_structures/src/stable_hasher.rs
compiler/rustc_error_codes/src/error_codes/E0637.md
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/emitter.rs
compiler/rustc_expand/src/mbe/transcribe.rs
compiler/rustc_expand/src/mut_visit/tests.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_hir/Cargo.toml
compiler/rustc_hir/src/hir.rs
compiler/rustc_index/src/vec.rs
compiler/rustc_infer/src/infer/combine.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
compiler/rustc_infer/src/infer/opaque_types.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_lint/src/array_into_iter.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
compiler/rustc_macros/src/query.rs
compiler/rustc_metadata/Cargo.toml
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/mir/pretty.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/error.rs
compiler/rustc_middle/src/ty/mod.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/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/lib.rs
compiler/rustc_mir_transform/src/dump_mir.rs
compiler/rustc_mir_transform/src/lib.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_parse/src/parser/item.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_privacy/src/lib.rs
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/ich/hcx.rs
compiler/rustc_query_system/src/ich/impls_hir.rs
compiler/rustc_query_system/src/query/config.rs
compiler/rustc_query_system/src/query/mod.rs
compiler/rustc_query_system/src/query/plumbing.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_resolve/src/lib.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/symbol.rs
compiler/rustc_symbol_mangling/src/lib.rs
compiler/rustc_symbol_mangling/src/v0.rs
compiler/rustc_target/src/spec/aarch64_apple_darwin.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/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_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/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/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/check/_match.rs
compiler/rustc_typeck/src/check/check.rs
compiler/rustc_typeck/src/check/coercion.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/regionck.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/variance/constraints.rs
config.toml.example
library/alloc/src/collections/binary_heap.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/set.rs
library/alloc/src/lib.rs
library/alloc/src/string.rs
library/core/src/array/mod.rs
library/core/src/clone.rs
library/core/src/fmt/mod.rs
library/core/src/internal_macros.rs
library/core/src/intrinsics.rs
library/core/src/lib.rs
library/core/src/marker.rs
library/core/src/num/int_macros.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/panicking.rs
library/core/src/slice/iter.rs
library/core/src/slice/mod.rs
library/core/src/slice/raw.rs
library/core/src/str/mod.rs
library/core/src/str/traits.rs
library/core/src/str/validations.rs
library/core/src/time.rs
library/core/tests/array.rs
library/core/tests/lib.rs
library/core/tests/slice.rs
library/std/src/collections/hash/set.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/fs/tests.rs
library/std/src/lib.rs
library/std/src/os/unix/process.rs
library/std/src/panicking.rs
library/std/src/path.rs
library/std/src/path/tests.rs
library/std/src/sync/mpsc/cache_aligned.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_common/wtf8.rs
library/std/src/thread/mod.rs
src/bootstrap/builder.rs
src/bootstrap/config.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/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/run.sh
src/ci/github-actions/ci.yml
src/ci/run.sh
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/exploit-mitigations.md
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/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/rustdoc.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/css/themes/dark.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/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/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/stripper.rs
src/librustdoc/scrape_examples.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/alloc-optimisation.rs
src/test/codegen/asm-powerpc-clobbers.rs
src/test/codegen/binary-search-index-no-bound-check.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/hashes/for_loops.rs
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/obtain-borrowck/driver.rs
src/test/run-make-fulldeps/split-debuginfo/Makefile
src/test/run-make-fulldeps/split-dwarf/Makefile
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/headings.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.goml
src/test/rustdoc-gui/src/test_docs/lib.rs
src/test/rustdoc-js/generics.js
src/test/rustdoc-js/generics.rs
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/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/recursive-deref-sidebar.rs
src/test/rustdoc/recursive-deref.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.stderr
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/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/migrations/issue-90024-adt-correct-subst.rs [new file with mode: 0644]
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/precise-drop-with-promoted.rs [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/did_you_mean/issue-42764.stderr
src/test/ui/entry-point/imported_main_conflict.rs
src/test/ui/entry-point/imported_main_conflict.stderr
src/test/ui/error-codes/E0283.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/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-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/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-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/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/no-method-suggested-traits.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-29147.stderr
src/test/ui/issues/issue-40827.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/rsplit-clone.rs [new file with mode: 0644]
src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.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/methods/method-ambig-one-trait-unknown-int-type.rs
src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr
src/test/ui/mut/mutable-enum-indirect.stderr
src/test/ui/nll/issue-78561.rs [new file with mode: 0644]
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/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/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/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/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/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/block-scoped-shadow-nested.stderr
src/test/ui/rust-2018/uniform-paths/block-scoped-shadow.stderr
src/test/ui/rust-2018/uniform-paths/issue-56596.stderr
src/test/ui/rust-2018/uniform-paths/macro-rules.stderr
src/test/ui/rust-2021/future-prelude-collision-shadow.stderr
src/test/ui/suggestions/core-std-import-order-issue-83564.stderr
src/test/ui/suggestions/into-str.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/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/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/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-impl-trait/auto-trait-leakage2.stderr
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/unsized-locals/unsized-exprs.stderr
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/CHANGELOG.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/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/disallowed_type.rs
src/tools/clippy/clippy_lints/src/doc.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/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_then_panic.rs
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/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.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/mod.rs
src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
src/tools/clippy/clippy_lints/src/missing_inline.rs
src/tools/clippy/clippy_lints/src/mut_mut.rs
src/tools/clippy/clippy_lints/src/no_effect.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/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/uninit_vec.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/unnecessary_sort_by.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/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/higher.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/paths.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/clippy/doc/basics.md
src/tools/clippy/rust-toolchain
src/tools/clippy/tests/compile-test.rs
src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.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/auxiliary/macro_rules.rs
src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed
src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs
src/tools/clippy/tests/ui/doc_unsafe.rs
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/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/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_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/implicit_saturating_sub.fixed
src/tools/clippy/tests/ui/implicit_saturating_sub.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/mut_mut.rs
src/tools/clippy/tests/ui/mut_mut.stderr
src/tools/clippy/tests/ui/no_effect.rs
src/tools/clippy/tests/ui/no_effect.stderr
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/question_mark.fixed
src/tools/clippy/tests/ui/question_mark.rs
src/tools/clippy/tests/ui/question_mark.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/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/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/wildcard_imports.fixed
src/tools/clippy/tests/ui/wildcard_imports.rs
src/tools/clippy/tests/ui/wildcard_imports.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/main.rs
src/tools/linkchecker/main.rs
src/tools/miri
src/tools/rust-analyzer
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/ui_tests.rs
triagebot.toml

index d921286ba3489be2e54814cfc434b3762991e15b..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
@@ -274,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
@@ -287,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
@@ -303,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:
@@ -313,6 +315,7 @@ 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:
@@ -324,6 +327,7 @@ jobs:
               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
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 8385f1a18e5cd86a5a5cafaae67bc3f36a840df0..59885472ae9c48d582bfd1ac2e5329d6bfae71bc 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,7 +574,7 @@ dependencies = [
 
 [[package]]
 name = "clippy"
-version = "0.1.57"
+version = "0.1.58"
 dependencies = [
  "cargo_metadata 0.12.0",
  "clippy_lints",
@@ -582,6 +601,7 @@ version = "0.0.1"
 dependencies = [
  "bytecount",
  "clap",
+ "indoc",
  "itertools 0.10.1",
  "opener",
  "regex",
@@ -591,7 +611,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.57"
+version = "0.1.58"
 dependencies = [
  "cargo_metadata 0.12.0",
  "clippy_utils",
@@ -612,7 +632,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.57"
+version = "0.1.58"
 dependencies = [
  "if_chain",
  "rustc-semver",
@@ -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"
@@ -2329,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",
 ]
@@ -4595,8 +4615,8 @@ dependencies = [
  "itertools 0.9.0",
  "minifier",
  "pulldown-cmark 0.8.0",
+ "rayon",
  "regex",
- "rustc-rayon",
  "rustdoc-json-types",
  "serde",
  "serde_json",
@@ -4663,19 +4683,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",
@@ -4758,23 +4778,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",
 ]
 
@@ -4787,12 +4797,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"
@@ -5593,6 +5597,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 f673ab2f3efde30221843fb59968b5f80d4cdd09..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);
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 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 22f93f5078817cbcec8856c57f92bced0a148349..405e9035c4c1922f392a6b6502ff7d36d6cec885 100644 (file)
@@ -1332,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);
 
@@ -1354,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)
         };
 
@@ -1416,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,
         );
@@ -1429,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),
@@ -1442,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,
         );
 
@@ -1458,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,
index dc2b1a730fbd6bc2625fbb1296fabd0ad468fb07..8a9dad2cdd7d86635425ed9853b012abe1003f37 100644 (file)
@@ -1,4 +1,5 @@
 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_span::source_map::SourceMap;
 use rustc_span::{Span, DUMMY_SP};
 
-use std::iter::repeat;
 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 IndexVec<ItemLocalId, Option<&'hir Body<'hir>>>,
+    bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>,
 
     /// Outputs
     nodes: IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>,
@@ -30,21 +30,11 @@ pub(super) struct NodeCollector<'a, 'hir> {
     definitions: &'a definitions::Definitions,
 }
 
-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);
-}
-
 pub(super) fn index_hir<'hir>(
     sess: &Session,
     definitions: &definitions::Definitions,
     item: hir::OwnerNode<'hir>,
-    bodies: &IndexVec<ItemLocalId, Option<&'hir Body<'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
@@ -94,11 +84,7 @@ fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
             }
         }
 
-        insert_vec_map(
-            &mut self.nodes,
-            hir_id.local_id,
-            ParentedNode { parent: self.parent_node, node: node },
-        );
+        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) {
@@ -144,7 +130,7 @@ fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
 
     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].unwrap();
+        let body = self.bodies[&id.hir_id.local_id];
         self.visit_body(body);
     }
 
index e8747f2c5f8f9d06bd03a49ca35c587254b1287d..63b20cd320b37b60ef04f67f0acd4b81f1c79625 100644 (file)
@@ -974,8 +974,7 @@ fn record_body(
         let body = hir::Body { generator_kind: self.generator_kind, params, value };
         let id = body.id();
         debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
-        self.bodies.ensure_contains_elem(id.hir_id.local_id, || None);
-        self.bodies[id.hir_id.local_id] = Some(self.arena.alloc(body));
+        self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
         id
     }
 
index 92e08da7a97abdf9a23ecfa00ad8b6641ba85e5d..79464a751721751ddfcce69776513184901395dd 100644 (file)
@@ -44,6 +44,7 @@
 use rustc_data_structures::captures::Captures;
 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};
@@ -66,7 +67,6 @@
 use rustc_span::{Span, DUMMY_SP};
 
 use smallvec::SmallVec;
-use std::collections::BTreeMap;
 use tracing::{debug, trace};
 
 macro_rules! arena_vec {
@@ -103,9 +103,9 @@ struct LoweringContext<'a, 'hir: 'a> {
     /// The items being lowered are collected here.
     owners: IndexVec<LocalDefId, Option<hir::OwnerInfo<'hir>>>,
     /// Bodies inside the owner being lowered.
-    bodies: IndexVec<hir::ItemLocalId, Option<&'hir hir::Body<'hir>>>,
+    bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
     /// Attributes inside the owner being lowered.
-    attrs: BTreeMap<hir::ItemLocalId, &'hir [Attribute]>,
+    attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
 
     generator_kind: Option<hir::GeneratorKind>,
 
@@ -300,8 +300,8 @@ pub fn lower_crate<'a, 'hir>(
         nt_to_tokenstream,
         arena,
         owners,
-        bodies: IndexVec::new(),
-        attrs: BTreeMap::default(),
+        bodies: Vec::new(),
+        attrs: SortedMap::new(),
         catch_scope: None,
         loop_scope: None,
         is_in_loop_condition: false,
@@ -478,7 +478,7 @@ fn with_hir_id_owner(
 
     fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir> {
         let attrs = std::mem::take(&mut self.attrs);
-        let bodies = std::mem::take(&mut self.bodies);
+        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()
@@ -490,13 +490,15 @@ fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir
             .collect();
 
         #[cfg(debug_assertions)]
-        for (&id, attrs) in attrs.iter() {
+        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);
@@ -517,7 +519,7 @@ fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir
     fn hash_owner(
         &mut self,
         node: hir::OwnerNode<'hir>,
-        bodies: &IndexVec<hir::ItemLocalId, Option<&'hir hir::Body<'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();
index e30d6c7fca73191a66468303cacbbf94d9396d70..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> },
 }
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 08df87e0488b8c0006d633be3dc45ba3771dddd0..aca7d3174f6cd567080aafd61b38949ba1154439 100644 (file)
@@ -2,7 +2,6 @@
 
 #![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)]
@@ -64,7 +63,7 @@
 
 use self::path_utils::*;
 
-mod borrow_set;
+pub mod borrow_set;
 mod borrowck_errors;
 mod constraint_generation;
 mod constraints;
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 7e69e710d68681ffed9ff5265bf22527661a1fdc..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::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;
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 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 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 d5deacf3811304c972fb0cc5919b833c23ac0f97..0707faf610cf3e4edc312bf9f3b8d0cac413adcf 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())
     }
index 257a0ac89d86ffff881fd814b631841fba8d26dc..cda766039c16728f9b4c70433bed31a191266fc0 100644 (file)
@@ -221,6 +221,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 +788,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..baa257069aa1ce156b0ae22d9736dac39a838dd6 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);
         }
 
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 f78196d7ec58e25bc00797df2308c7709288cad8..4c87d4d896e2ec8129362eb05464504d68108a26 100644 (file)
@@ -27,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;
@@ -169,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..297dcde99b3d4e950fcd728db3addc55ff864ddb 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.clone());
+
+            // 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..1cd400eecfbd2b0253d9af93a443174cfe6fc086 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.clone());
+    }
 }
 
 /// Produces, for each argument, a `Value` pointing at the
index 8d7e9612f4749d63c0fbb9e6388520627ac85374..dbffb266be88c3a320738c11eac3546fb2e2e465 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)),
@@ -90,7 +91,7 @@
     // 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)),
     // FEAT_F64MM
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 8efe3eb868b941d48318863742aaeadec93964e8..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
@@ -274,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 03e60deea2783c9def30a57f04f538ec2f9b4155..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 super::ops::{self, NonConstOp, Status};
 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>>;
 
@@ -41,36 +34,9 @@ pub struct Qualifs<'mir, 'tcx> {
     has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
     needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
     needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
-    indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>,
 }
 
 impl Qualifs<'mir, 'tcx> {
-    pub fn indirectly_mutable(
-        &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()
-                .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)
-    }
-
     /// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
     ///
     /// Only updates the cursor if absolutely necessary
@@ -95,7 +61,7 @@ pub fn needs_drop(
         });
 
         needs_drop.seek_before_primary_effect(location);
-        needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+        needs_drop.get().contains(local)
     }
 
     /// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`.
@@ -122,7 +88,7 @@ pub fn needs_non_const_drop(
         });
 
         needs_non_const_drop.seek_before_primary_effect(location);
-        needs_non_const_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+        needs_non_const_drop.get().contains(local)
     }
 
     /// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
@@ -149,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(
@@ -195,7 +161,7 @@ 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)
             }
         };
 
@@ -854,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,
                         }),
                     );
 
@@ -917,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),
                     }
                 }
 
index 58d0f1a3ad88ebaf13eaae87686acb9ce5fc21da..dc44409d500a04384f3910b24200f34d34895151 100644 (file)
@@ -72,24 +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()
-}
-
-/// 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 5418f6fc007ca12050d8baa7eb117e8842267c46..0fdb772c262dddbbe774fa948551a5c1a5e9e565 100644 (file)
@@ -46,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;
 
@@ -129,6 +132,7 @@ fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tc
 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_non_const_drop
@@ -158,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,
             }),
         );
 
@@ -253,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...
@@ -310,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..38576230883cd8b87f514312c4fbab2bea021b0b 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,29 @@ 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 {
+        match mt {
+            mir::Mutability::Mut => true,
+            mir::Mutability::Not => self.shared_borrow_allows_mutation(place),
+        }
+    }
+
+    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)
+            }
+        }
+    }
+
+    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 +133,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 +149,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 +160,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 +219,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 +228,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 +251,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 ebcc8213c604b889187c00e17d13d5f1e6b3c658..67664d2ede1dd657ca7c78ed0a5b4f72434318f5 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.
@@ -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 {
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 20e2a3b9696e8560cb80d71d50cd9d8d6a0c281d..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.
     ///
@@ -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 354f9dd93cc4d4e491f6a15feffcdbf491a837dd..f800ec6a6a12c49425d69ae8fbe8d3c65cae82c4 100644 (file)
@@ -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 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 849ffa881df7d72c238cb34d15046ebf94402a54..e17604740f0319eedad22501bae4622fc1f2bedc 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,
 };
 
@@ -523,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.
index 4663dd80fa8bbed095b1203feebf4e02bc94a7cf..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)
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 f7c0597909e8bfb805d31a8863329885c0b54f76..2bbfb561ba59461a6ea310f6417673d5c497ffc0 100644 (file)
@@ -684,6 +684,10 @@ 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),
+
     // -------------------------------------------------------------------------
     // 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 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 6f25715fbecc47b4829c0b660f07b878361d5246..a441a635c1eb37ce6b0e3474eeefd97eba449243 100644 (file)
@@ -12,6 +12,7 @@
 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;
@@ -22,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)]
@@ -676,13 +676,13 @@ pub struct ParentedNode<'tcx> {
 /// Attributes owned by a HIR owner.
 #[derive(Debug)]
 pub struct AttributeMap<'tcx> {
-    pub map: BTreeMap<ItemLocalId, &'tcx [Attribute]>,
+    pub map: SortedMap<ItemLocalId, &'tcx [Attribute]>,
     pub hash: Fingerprint,
 }
 
 impl<'tcx> AttributeMap<'tcx> {
     pub const EMPTY: &'static AttributeMap<'static> =
-        &AttributeMap { map: BTreeMap::new(), hash: Fingerprint::ZERO };
+        &AttributeMap { map: SortedMap::new(), hash: Fingerprint::ZERO };
 
     #[inline]
     pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] {
@@ -705,7 +705,7 @@ pub struct OwnerNodes<'tcx> {
     // used.
     pub nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
     /// Content of local bodies.
-    pub bodies: IndexVec<ItemLocalId, Option<&'tcx Body<'tcx>>>,
+    pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>,
 }
 
 /// Full information resulting from lowering an AST node.
index 66399d2999848d1b6380362853bb61f19aec1016..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)
                 }
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 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 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 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 eea320835685cd5066039057601fd3a6f7b4fb08..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 {
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 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 a93d18950dba9256364c077fcd85d32afe2504b1..f35ca2659fd65661eae69ac75c8aa58e4f886729 100644 (file)
     /// [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>",
     /// [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>",
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 6d2e7d25336de4af2fd86f6f2c3844f58e5bc1cd..32b866e81b131eca15e114368170038fa9d8e0e1 100644 (file)
@@ -54,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();
@@ -466,6 +462,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat,
     bool FunctionSections,
     bool DataSections,
+    bool UniqueSectionNames,
     bool TrapUnreachable,
     bool Singlethread,
     bool AsmComments,
@@ -495,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;
@@ -685,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();
@@ -703,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) {
@@ -782,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){
@@ -821,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);
@@ -857,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(
@@ -896,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)
@@ -907,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)
@@ -933,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>());
@@ -967,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)
@@ -1003,14 +915,6 @@ LLVMRustOptimizeWithNewPassManager(
 #endif
         }
       );
-#else
-      PipelineStartEPCallbacks.push_back(
-        [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
-          MPM.addPass(HWAddressSanitizerPass(
-              /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
-        }
-      );
-#endif
     }
   }
 
@@ -1025,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)
@@ -1033,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);
@@ -1077,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.
@@ -1085,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;
       }
     }
@@ -1552,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
@@ -1563,7 +1409,6 @@ clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) {
       Mod.getPIELevel() == PIELevel::Default;
   return ClearDSOLocalOnDeclarations;
 }
-#endif
 
 extern "C" bool
 LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
@@ -1571,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");
@@ -1645,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 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 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 e12f049a90bdf54cee9d9e2cc62470fc7490bc60..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
             };
index fad7e875fa1c025ac4a6434aab0c109d76aece10..8f52e16c2ebe41e7873d6893dc0917be4e1a37a4 100644 (file)
@@ -376,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[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>> {
@@ -495,13 +495,10 @@ pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir {
             .iter_enumerated()
             .flat_map(move |(owner, owner_info)| {
                 let bodies = &owner_info.as_ref()?.nodes.bodies;
-                Some(bodies.iter_enumerated().filter_map(move |(local_id, body)| {
-                    if body.is_none() {
-                        return None;
-                    }
+                Some(bodies.iter().map(move |&(local_id, _)| {
                     let hir_id = HirId { owner, local_id };
                     let body_id = BodyId { hir_id };
-                    Some(self.body_owner_def_id(body_id))
+                    self.body_owner_def_id(body_id)
                 }))
             })
             .flatten()
@@ -515,13 +512,10 @@ pub fn par_body_owners<F: Fn(LocalDefId) + Sync + Send>(self, f: F) {
         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.raw).enumerate().for_each(|(local_id, body)| {
-                    if body.is_some() {
-                        let local_id = ItemLocalId::new(local_id);
-                        let hir_id = HirId { owner, local_id };
-                        let body_id = BodyId { hir_id };
-                        f(self.body_owner_def_id(body_id))
-                    }
+                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))
                 })
             }
         });
@@ -578,8 +572,8 @@ pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) {
         let krate = self.krate();
         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 };
+                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)
                     }
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 18be9817c5fa794e53bd29a1f5722ee4bd5bf658..06041bbb02d355537240c012aefb6835520036d4 100644 (file)
     /// 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) }
+        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>]) {
             |tcx| "determining which generic parameters are unused by `{}`",
                 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 bac681bd96fb184d331b20cd9c6b20b9c93670e2..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(_)
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 6c1175ebdb4ee8b60115d25d15a2114eff8652e9..34f806271979af7ec3bef7af3d4e99438fc6862b 100644 (file)
@@ -123,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])*
@@ -214,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 {
@@ -228,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 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 2f3de52965db1dbe6d3f70bae30a9b3c54115ca4..77a72ce63ce5ee53ccc2ed8e74ce159fcafc1d27 100644 (file)
@@ -2,7 +2,6 @@
 #![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)]
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 ab1fe6fe077a74b3b72c2bf8a03cac720b9aa425..f9ef31462780731a9375aa0ec7f4f379c17da875 100644 (file)
@@ -1,7 +1,6 @@
 #![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)]
@@ -28,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};
@@ -66,6 +65,7 @@
 mod remove_unneeded_drops;
 mod remove_zsts;
 mod required_consts;
+mod reveal_all;
 mod separate_const_switch;
 mod shim;
 mod simplify;
@@ -188,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);
@@ -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 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 1d9c3a4f3cf2b207292c9498de795584ad2f8a96..d2167c7a5db0c8f642f61c047f5b3b54b39372eb 100644 (file)
@@ -279,9 +279,9 @@ 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);
@@ -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?
@@ -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 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 4d4e9432e876dc21f9d88cfd9019735a0175d425..fa34b9abc1e6c9314288ae045f6d1e71dde8ec03 100644 (file)
@@ -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)
index b216d78da945cd64921bd0f27571c5720b1f0bbf..440b6f1983e6eee7d8e7cbfcf3784268412de789 100644 (file)
 #[macro_use]
 extern crate rustc_middle;
 
-use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_errors::DiagnosticBuilder;
 use rustc_middle::arena::Arena;
-use rustc_middle::dep_graph::{self, DepKindStruct};
+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]
@@ -39,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 86b12b3586a9be142dbd58c27ee34a191dd1f8e7..552906aac31a7f5ac79b3abd45e612dd981f8de4 100644 (file)
@@ -1018,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
@@ -1033,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 8c3fbb2071c043e46f2e93e7ccbdb745950ad3a6..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 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;
 
@@ -218,6 +215,22 @@ macro_rules! hash_result {
     };
 }
 
+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)*]) => {
+        get_provider!([$($modifiers)*][$($args)*])
+    };
+}
+
 macro_rules! define_queries {
     (<$tcx:tt>
      $($(#[$attr:meta])*
@@ -290,11 +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;
-            const HASH_RESULT: Option<fn(&mut StableHashingContext<'_>, &Self::Value) -> Fingerprint> = hash_result!([$($modifiers)*]);
+        impl<$tcx> QueryDescription<QueryCtxt<$tcx>> for queries::$name<$tcx> {
+            rustc_query_description! { $name<$tcx> }
 
             type Cache = query_storage::$name<$tcx>;
 
@@ -313,22 +323,22 @@ 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 handle_cycle_error(
-                tcx: QueryCtxt<'tcx>,
-                mut error: DiagnosticBuilder<'_>,
-            ) -> Self::Value {
-                handle_cycle_error!([$($modifiers)*][tcx, error])
-            }
         })*
 
         #[allow(nonstandard_style)]
@@ -417,8 +427,7 @@ 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));
-                    let tcx = QueryCtxt::from_tcx(tcx);
-                    if queries::$name::cache_on_disk(tcx, &key, None) {
+                    if queries::$name::cache_on_disk(tcx, &key) {
                         let _ = tcx.$name(key);
                     }
                 }
@@ -447,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>>,
 
@@ -460,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 {
@@ -518,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 cfef2073373cc93c71bdbc91ec22735361ad323d..5f31fa04b8a6e1c099a846cf76a28ffa09462e65 100644 (file)
@@ -1,12 +1,12 @@
 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;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::definitions::{DefPathHash, Definitions};
-use rustc_index::vec::IndexVec;
 use rustc_session::cstore::CrateStore;
 use rustc_session::Session;
 use rustc_span::source_map::SourceMap;
@@ -51,7 +51,7 @@ pub(super) enum BodyResolver<'tcx> {
     Traverse {
         hash_bodies: bool,
         owner: LocalDefId,
-        bodies: &'tcx IndexVec<hir::ItemLocalId, Option<&'tcx hir::Body<'tcx>>>,
+        bodies: &'tcx SortedMap<hir::ItemLocalId, &'tcx hir::Body<'tcx>>,
     },
 }
 
@@ -122,7 +122,7 @@ pub fn with_hir_bodies(
         &mut self,
         hash_bodies: bool,
         owner: LocalDefId,
-        bodies: &'a IndexVec<hir::ItemLocalId, Option<&'a hir::Body<'a>>>,
+        bodies: &'a SortedMap<hir::ItemLocalId, &'a hir::Body<'a>>,
         f: impl FnOnce(&mut Self),
     ) {
         let prev = self.body_resolver;
index 24f3a2e7de0a9926945fe569a37a4104d27219c1..3a0aab81fdb7b257b32908ba0aaf26482bc8195e 100644 (file)
@@ -33,7 +33,7 @@ fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) {
             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].unwrap().hash_stable(hcx, hasher);
+                bodies[&id.hir_id.local_id].hash_stable(hcx, hasher);
             }
         }
     }
index fc3b7980dfb17f4584f92975e15222d6a04355de..d2b102b6f89681358bca92bfb1cd9b3bf8d53b87 100644 (file)
@@ -19,16 +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 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> {
@@ -43,25 +43,21 @@ pub(crate) fn compute(&self, tcx: CTX::DepContext, key: K) -> V {
         (self.compute)(tcx, key)
     }
 
-    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 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;
-    const HASH_RESULT: Option<
-        fn(hcx: &mut StableHashingContext<'_>, result: &Self::Value) -> Fingerprint,
-    >;
+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 handle_cycle_error(tcx: CTX, diag: DiagnosticBuilder<'_>) -> Self::Value;
-}
-
-pub trait QueryDescription<CTX: QueryContext>: QueryAccessors<CTX> {
-    fn describe(tcx: CTX, key: Self::Key) -> String;
+    fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVtable<CTX, Self::Key, Self::Value>;
 
-    #[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> {
-    fn make_vtable(tcx: CTX, key: &K) -> QueryVtable<CTX, K, V>;
-}
-
-impl<CTX, Q> QueryVtableExt<CTX, Q::Key, Q::Value> for Q
-where
-    CTX: QueryContext,
-    Q: QueryDescription<CTX>,
-{
-    fn make_vtable(tcx: CTX, key: &Q::Key) -> 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,
-            compute: Q::compute_fn(tcx, key),
-            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 e2b0a65ab77b17e013cc3c088aa87efb13474955..a2f7843baaa680b2c1b52cf679646d470102f0ae 100644 (file)
@@ -12,7 +12,7 @@
 };
 
 mod config;
-pub use self::config::{QueryAccessors, QueryConfig, QueryDescription};
+pub use self::config::{QueryConfig, QueryDescription, QueryVtable};
 
 use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
 
index 056611317dcf18cb601e6fa0f2b62a8966efedf1..238b92a61342b451ce842a09e46a8fc925a00de2 100644 (file)
@@ -4,7 +4,7 @@
 
 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,
 };
@@ -512,7 +512,7 @@ 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());
@@ -713,8 +713,6 @@ pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, dep_node: DepNode<CTX::DepKind
     Q::Key: DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
-    assert!(!Q::ANON);
-
     // 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);
@@ -731,5 +729,7 @@ pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, dep_node: DepNode<CTX::DepKind
 
     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 aefb3f2cb9c8399d25be44f42d7f20a58249bca0..163acebcceacffe792a1238f13a014e71a6858c5 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
@@ -829,6 +831,15 @@ 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
@@ -865,11 +876,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,
                             });
                         }
                     }
@@ -1158,14 +1196,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);
@@ -1762,12 +1795,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 +1825,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 +1857,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,12 +1869,15 @@ 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)
             {
                 descr_first.to_string()
             } else {
@@ -1846,7 +1888,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 +1908,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 1748a9be8e13e80cd0194e76ceafc14e2cb405b5..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 {
index 98c1355d05b25a16317b0f5b815e0ecd7131a28d..23eb2d1aebb7ce9be13f8f2720b50cc0969f69d2 100644 (file)
@@ -727,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"
             }
         }
     }
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 059b5dc51756ec4cefbf240d1169a8f2604f5e38..e894e46a301424615848d78db424d789691e16f2 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],
@@ -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],
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 c25bd9bfa80df876d5bae8bfdf0a93d44d8ca81d..1b4315896321f9fc77b2302c8432dfc985a65254 100644 (file)
         cfg_target_thread_local,
         cfg_target_vendor,
         cfg_version,
+        cfi,
         char,
         client,
         clippy,
         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,
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 dc91f1230964921d22bd30924373df7fc78744cf..2c71fb8afeedeb54cb3339e22169e71a7c3c7f1d 100644 (file)
@@ -6,7 +6,7 @@ pub fn target() -> Target {
     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 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..c8d46adbfd92ba17b8358aad26430538dffa1005 100644 (file)
@@ -10,6 +10,7 @@ pub fn target() -> Target {
             mcount: "\u{1}_mcount".to_string(),
             max_atomic_width: Some(128),
             supported_sanitizers: SanitizerSet::ADDRESS
+                | SanitizerSet::CFI
                 | SanitizerSet::LEAK
                 | SanitizerSet::MEMORY
                 | SanitizerSet::THREAD
index ff5dfa3f746254b0364c4faf37b17f81e941346b..484593dcf4d785073feb7427d64f22c47b900714 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,
@@ -1522,6 +1525,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 +1556,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 +1807,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(),
index 6c5e6b1cfc385fbc0b5e2e9daa8d55ce649726da..75d57d78e3b0294be8d2138590248c775ddb6048 100644 (file)
@@ -1,45 +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::opaque_types::OpaqueTypeDecl;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{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;
-
 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(&self);
-
-    fn constrain_opaque_type(
-        &self,
-        opaque_type_key: OpaqueTypeKey<'tcx>,
-        opaque_defn: &OpaqueTypeDecl<'tcx>,
-    );
-
-    /*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>,
@@ -49,305 +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(&self) {
-        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);
-        }
-    }
-
-    /// See `constrain_opaque_types` for documentation.
-    #[instrument(level = "debug", skip(self))]
-    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,
-        };
-
-        // The regions that appear in the hidden type must be equal to
-        // one of the regions in scope for the opaque type.
-        self.generate_member_constraint(
-            concrete_ty,
-            opaque_defn,
-            opaque_type_key,
-            first_own_region,
-        );
-    }
-
-    /// 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
@@ -363,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
     ///
@@ -409,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>,
 
@@ -728,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 225ff5e597ed03a097d6f94fb584a41488261a83..5d17693dc0820dd9336aa803167cee7243e42089 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 970fb30487963bb7854e362fc1a825d14a2ff536..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(
@@ -1425,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) => {
@@ -1463,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)
@@ -1477,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!(
@@ -1495,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()
@@ -1545,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,
@@ -1620,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>>,
     ) {
@@ -1831,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);
                     }
@@ -1852,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);
@@ -1868,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..428873b8d3dda8ae2676f93c3527f030deb8bbad 100644 (file)
@@ -804,6 +804,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 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 74e132097cc5588b11e33080841332d525cce521..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())));
             }
         }
 
@@ -913,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..84721922c8dd738493f79e10186638894a32c9a4 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) => {
index 85502a399dedac0bbc74781160255accebbba09d..1b26e38fe0e4d437b0f5245d16949e8c6c72fc87 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,
         );
@@ -1523,10 +1579,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 +1597,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 +1627,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 +1647,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 bc77c94809eb58ca47c0f47932b3c6a0f20e08d0..af3706f886e9cbce53fb4e6be54c5ee1872432e4 100644 (file)
@@ -247,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) {
@@ -274,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))
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 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 40f456de18332bf736ef0285fa1db0ee52e70695..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() {
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..28b19981c2d40766f4442dbed32fca63481e827d 100644 (file)
@@ -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
index f945a2e506301c5fd337dde43d6d49a927584933..230a576046a479c9dcf5d296bd7209789bd6d753 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();
     }
 
     fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
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..96211be8cdcf7576984a2791ef08a50bfc8e3004 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
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 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 2128fdea2eb460e3144b4ba7265119f8434238b9..4dd953a495d675a0499149dbfc3537a881dfb9d8 100644 (file)
@@ -609,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 9bded6c0f1cf213f5212c6a426f5614da9598277..d7620c68f2cae7cb62c8210f27ccc369d577a8b4 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
 ///
index fa86e611565e64b0b7ab0a5cb7099bd385c3fa5c..e1d5ec97678fa18441575a334eb7e306aafea6c1 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
index d732f65b0d05f152174ab10f005a2acc6b7c5b35..237e0107f247585c169202c1c6afa5b5d35b174a 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
index 285d7755c0689c69d817439a65a0a3795650caee..5e6fe3b9b32b93efe9c64567fa12613418e0e51d 100644 (file)
 //
 // Rustdoc features:
 #![feature(doc_cfg)]
-#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))]
+#![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
index f479bf231b37681402bfb410926c81ec6d835716..85ee7ea943882ffa7d365813753c2d0cdc26bd5c 100644 (file)
@@ -1500,10 +1500,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
     ///
index b27c36baf37c5f44f5ee1a3034e65e0a7262b887..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]>() }
 }
@@ -500,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 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 b8ad7720e0c554590226f08f3d3da7dcbc4b307e..9258b4d0818f5ff929d4256bcfef78bf291e6ffc 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.
     ///
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 58a170401e7c123c5f08c97b164877022dfd2133..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_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 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 9b1a4de5d80378ce7016c058f575f6f481241cff..7708094e1fceab656457dbd297339a35f914319e 100644 (file)
@@ -92,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 {
@@ -103,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 {
@@ -115,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 {
@@ -127,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;
@@ -135,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;
@@ -257,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.
@@ -270,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..691d0891b144888dc0f8d11a44f9930848977f2a 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]
@@ -1530,7 +1525,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 +1606,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..776cea2ef791fbb128566a06cce9f2a048dcc8a9 100644 (file)
@@ -24,7 +24,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);
 /// ```
 #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
 #[derive(Debug, Clone, Copy, PartialEq)]
index a12447acf7ec3c3221b92f563369ed033d71d71b..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));
 }
 
@@ -89,7 +87,8 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
 #[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 dbf97851b03e4e78294871ae94ba0d92f9836529..07ecae7830351eac72860ea614923af9ab9d8ec1 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
index 664875a8773eddf596737137fc4f0cadd3322907..a6370a4513bb5a8138fc142751feb7f5e6fbf92c 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.
     ///
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 607a0179ff4b9a515ca69bd02522291ea1e42788..7939ea3bb7fb25c1f753d70063c6d644675c5b1a 100644 (file)
@@ -1663,7 +1663,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
     ///
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..f2d1c7378088090da22c9d8f17b5becf1a640b68 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;
                         }
                     }
index 5a74f39e8bc8b58469e6214909e99d92272ab797..80220a1ecb2bafe388273baee42ec177f98dd8af 100644 (file)
@@ -737,7 +737,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 +755,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 +798,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 +816,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 +1256,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 +1271,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 +1287,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 ab0295c63143d3eaa3cce8b622b5d8b6fc49fc72..1c63070874aa062d3b0c9847994cedeeef641ecc 100644 (file)
@@ -11,7 +11,6 @@
 #![feature(const_cell_into_inner)]
 #![feature(const_convert)]
 #![feature(const_maybe_uninit_assume_init)]
-#![cfg_attr(bootstrap, feature(const_panic))]
 #![feature(const_ptr_read)]
 #![feature(const_ptr_write)]
 #![feature(const_ptr_offset)]
 #![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 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 5804701892e6e447641ea8144b1a815c42799648..546c43faecfdc6f5f3bbc5b15d16028bcfdd5361 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
 ///
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 cb09717bde577f1eb623505fc67a0670db12597b..b7822b40a7ccf69a97165b9a46b9625638fed7fd 100644 (file)
@@ -1171,6 +1171,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 {
@@ -1256,7 +1257,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).
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 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 4d23805e479ba067e4eb5c00dabc13db24566a2a..9b94615d24773b002c31129dfccaa51b78a31574 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;
 }
 
index 56646b72dd54f089cdc13e379a3fcb4e846a331f..437fcbb317601c188e80b5b8dd77492fe8736b19 100644 (file)
@@ -512,7 +512,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..8f00d2260e4c60b42b7827b5a382be20c640c334 100644 (file)
@@ -1208,6 +1208,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 +1257,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 {
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 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 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 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..1a5cf5ab8226a3b76d06fffae566afbe4274c790 100644 (file)
@@ -1449,6 +1449,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 ac1841b691334638538f29942f57718060ef1273..d5656f0f37e0389f336276d4942016847e60bc3a 100644 (file)
@@ -972,8 +972,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`,
index 8d03aade3413a42a0e59d717d853114f9ed3e8db..68e20f90b7fa4e3043193721d5f832d335c9b69a 100644 (file)
@@ -141,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>,
@@ -874,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);
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 6bfaeffa80705e65419d562a42ed2c9abcd8bb64..37578e30f6d0f698a4185ac5d23e0c410c5a063c 100644 (file)
@@ -378,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 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 e42b4748fdc78787cc6b78e4062246e8590cc21d..b1dacf79d269598d593a3429f567c49b471e549c 100755 (executable)
@@ -70,8 +70,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 eb16cf3c7620a57617bc7b30987f8e30a3fd4085..fbb3042d0d6ad1683d5365af46ecdcb208e9a7d0 100644 (file)
@@ -284,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
@@ -431,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
@@ -448,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
 
@@ -467,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
@@ -478,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
@@ -499,6 +504,7 @@ jobs:
               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
               #
@@ -666,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 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
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 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 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..51f365be922fa3225746cccbfa4e6c2723389819 100644 (file)
@@ -455,3 +455,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..bd7234522e1fec2f73d130aa6b8b1e7102de3a0c 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.
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 05817e1b1d99e7a45bb9c2d581bc7a3dd8273721..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());
@@ -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 075efd29b5969839251e8f3cf70a4a109c730f69..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_,
         }
@@ -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 d25e166629fa261ef78b59c26f4c178f442c5991..6ae057abb3d367c52478058440ae061b9e1839c2 100644 (file)
@@ -204,7 +204,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 +238,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 +304,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 +381,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 +562,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() {
@@ -820,9 +820,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 +934,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 +1061,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 +1079,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
     }
@@ -1370,17 +1370,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,
         }
     }
@@ -1458,34 +1451,6 @@ fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Type, 72);
 
-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))
-    }
-}
-
 impl Type {
     crate fn primitive_type(&self) -> Option<PrimitiveType> {
         match *self {
@@ -1564,17 +1529,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)
     }
 }
 
@@ -2092,16 +2067,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..0573a1ada3a84080182a0198a8517524aca85b0d 100644 (file)
@@ -171,8 +171,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 +217,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 +233,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 +507,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 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..a33bb3479cea7603a4a7c8e2d95a1030d55dfe9f 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,24 @@ 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 {
+        let (starts, ends) = info
+            .0
+            .into_iter()
+            .map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi)))
+            .flatten()
+            .unzip();
+        Decorations { starts, ends }
+    }
+}
+
 /// Processes program tokens, classifying strings of text by highlighting
 /// category (`Class`).
 struct Classifier<'a> {
@@ -259,13 +291,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 +314,7 @@ fn new(src: &str, edition: Edition, file_span: Span) -> Classifier<'_> {
             byte_pos: 0,
             file_span,
             src,
+            decorations,
         }
     }
 
@@ -356,6 +396,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 +469,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 +725,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 +733,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 c46439b85105070215e051af0ae0d64ec0e5da8b..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
@@ -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..37b2cf0262403638820dc550a8eb4b9d8f825343 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) {
@@ -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..826e7782db1e96420756258f3c68846699cadef7 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,6 +404,7 @@ fn init(
             generate_redirect_map,
             show_type_layout,
             generate_link_to_definition,
+            call_locations,
             ..
         } = options;
 
@@ -412,6 +429,7 @@ fn init(
             krate: krate.name.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;
@@ -474,6 +492,7 @@ fn init(
             templates,
             span_correspondance_map: matches,
             cache,
+            call_locations,
         };
 
         // Add the default themes to the `Vec` of stylepaths
@@ -497,6 +516,7 @@ 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,
         };
@@ -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..f78129050d7ec6124b67e97374c5e7501ab96f0c 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;
+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,221 @@ 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
+    );
+
+    // 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 (anchor, line_title) = if line_lo == line_hi {
+                    (format!("{}", line_lo + 1), format!("line {}", line_lo + 1))
+                } else {
+                    (
+                        format!("{}-{}", line_lo + 1, line_hi + 1),
+                        format!("lines {}-{}", line_lo + 1, line_hi + 1),
+                    )
+                };
+                let line_url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor);
+
+                (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)| {
+                write!(
+                    w,
+                    r#"<li><a href="{root}{url}">{name}</a></li>"#,
+                    root = cx.root_path(),
+                    url = call_data.url,
+                    name = call_data.display_name
+                );
+            });
+            write!(w, "</ul></div>");
+        }
+
+        write!(w, "</div></div></details>");
+    }
+
+    write!(w, "</div>");
+}
index 58cd1018c316fa986dcc6c9db45be634459c146e..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)]
@@ -742,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>) =
@@ -761,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,
@@ -983,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();
@@ -1094,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;
@@ -1134,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!(),
                     }
@@ -1159,6 +1159,7 @@ 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)
@@ -1285,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);
             }
         }
     }
@@ -1496,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..1a8562d05eab7cb3b13cac8b7d964aedcd220151 100644 (file)
@@ -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..27277015cd13f902674551d756c576ddda58d30e 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.
index 71c64231a210eb48e92e2b7739b7bc08362df134..667bbc24ba5edb5deac643d0514f3543e6ac99d0 100644 (file)
@@ -67,7 +67,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('/');
         });
@@ -168,7 +168,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 +204,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 +250,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 +277,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 +296,6 @@ fn print_src(
         edition,
         Some(line_numbers),
         Some(highlight::ContextInfo { context, file_span, root_path }),
+        decoration_info,
     );
 }
index e41c993a5285d6f4381d58b47925d1f8969a23b3..93cbc0debb945378213a53e68a42b68fa61d7054 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;
@@ -134,7 +134,7 @@ h1, h2, h3, h4 {
        margin: 20px 0 15px 0;
        padding-bottom: 6px;
 }
-h5, h6 {
+.docblock h3, .docblock h4, h5, h6 {
        margin: 15px 0 5px 0;
 }
 h1.fqn {
@@ -149,13 +149,25 @@ 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 {
        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;
 }
@@ -174,12 +186,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;
@@ -197,7 +203,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 {
@@ -467,6 +473,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;
 }
@@ -528,7 +539,7 @@ nav.sub {
        position: relative;
 }
 
-.docblock > * {
+.docblock > :not(.information) {
        max-width: 100%;
        overflow-x: auto;
 }
@@ -669,13 +680,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;
 }
@@ -746,7 +750,7 @@ a {
 .anchor {
        display: none;
        position: absolute;
-       left: 0;
+       left: -0.5em;
        background: none !important;
 }
 .anchor.field {
@@ -1579,14 +1583,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
@@ -1980,3 +1984,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 ccb1a707032bb1c0198ea9b177863cd8caa76313..f9c84dc3e318dc9e5023131c8c76e39143eb65b3 100644 (file)
@@ -613,3 +613,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 93801af46ecc5d3e267fb72ef68defc9b061f4ad..9a38277d55905ca7a56e8b79b4d134c0059da7a8 100644 (file)
@@ -485,3 +485,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;
+}
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
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..b0174d59a7be21463e999fccd92f968c8a9c066d 100644 (file)
          data-search-js="{{static_root_path | safe}}search{{page.resource_suffix}}.js"> {#- -#}
     </div>
     <script src="{{static_root_path | safe}}main{{page.resource_suffix}}.js"></script> {#- -#}
+    {%- if layout.scrape_examples_extension -%}
+    <script src="{{static_root_path | safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#}
+    {%- endif -%}
     {%- for script in page.static_extra_scripts -%}
     <script src="{{static_root_path | safe}}{{script}}.js"></script> {#- -#}
     {% endfor %}
index 924275dc1858885bd7e7a2cb6d6ef148d101479d..f740ecdbded74a9a2ed9cdfe01ca99f2f6b5fce4 100644 (file)
@@ -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..b50fbf58bae29f025a19147bc4cc39a083c06311 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,6 +119,7 @@ macro_rules! map {
 crate mod lint;
 mod markdown;
 mod passes;
+mod scrape_examples;
 mod theme;
 mod visit_ast;
 mod visit_lib;
@@ -619,6 +619,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 +756,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 +772,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 +793,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..4501914fe0c07e178ab681bbc00ce852ff4f888e 100644 (file)
@@ -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(
index d2b3c5239c778f4b5c83b1b327e8e95b5a810f33..b18208d26e2c478d3088c04288e8e90ff502828a 100644 (file)
@@ -36,7 +36,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 +77,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 +123,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();
@@ -150,8 +150,8 @@ 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);
             }
         }
 
index 1f7d6054233dd987b5bb8e0f05b858d3b7791226..69a526d461810e99c421c27047a8e21b677a6d70 100644 (file)
@@ -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..9b2fe0c77e6cfe71985687d3ab5ec3e4eeb27bb6 100644 (file)
@@ -289,7 +289,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 +437,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 +543,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),
@@ -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..7a4198198fa694ca15f2883e039972fe5a8a8410 100644 (file)
@@ -3,7 +3,8 @@
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 
-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;
 
@@ -31,9 +32,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
@@ -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 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..fc54e55
--- /dev/null
@@ -0,0 +1,266 @@
+//! 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},
+    HirId,
+};
+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(
+        tcx: TyCtxt<'_>,
+        expr_span: rustc_span::Span,
+        expr_id: HirId,
+        source_file: &SourceFile,
+    ) -> Self {
+        let enclosing_item_span =
+            tcx.hir().span_with_body(tcx.hir().get_parent_item(expr_id)).source_callsite();
+        assert!(enclosing_item_span.contains(expr_span));
+
+        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);
+
+        // Get type of function if expression is a function call
+        let tcx = self.tcx;
+        let (ty, span) = match ex.kind {
+            hir::ExprKind::Call(f, _) => {
+                let types = tcx.typeck(ex.hir_id.owner);
+                (types.node_type(f.hir_id), ex.span)
+            }
+            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() {
+            return;
+        }
+
+        // Save call site if the function resolves to a concrete definition
+        if let ty::FnDef(def_id, _) = ty.kind() {
+            // Ignore functions not from the crate being documented
+            if self.target_crates.iter().all(|krate| *krate != def_id.krate) {
+                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();
+
+                let location = CallLocation::new(tcx, span, ex.hir_id, &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());
+
+        // 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
+    })
+}
index 3e853456fad77d48ee20e74dd20ab5d2ad862b0c..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};
@@ -277,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
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 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
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;
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 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
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
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..bd59584
--- /dev/null
@@ -0,0 +1,4 @@
+// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]//*[@class="prev"]' ''
+// @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' ''
+
+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..d6d5982
--- /dev/null
@@ -0,0 +1,9 @@
+fn main() {
+    foobar::ok();
+
+    // 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..a113311
--- /dev/null
@@ -0,0 +1,4 @@
+fn main() {
+    foobar::ok();
+    // small item
+}
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..f1b7686
--- /dev/null
@@ -0,0 +1,4 @@
+// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]' 'ex2'
+// @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' 'ex1'
+
+pub fn ok() {}
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"})
diff --git a/src/test/rustdoc-gui/headings.goml b/src/test/rustdoc-gui/headings.goml
new file mode 100644 (file)
index 0000000..35d7721
--- /dev/null
@@ -0,0 +1,153 @@
+// 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"})
+
+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"})
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)
index 62dc76a40bcf5a315904a5f0ee031a5813caad05..eacc9f6c15fe1eb8c42abcff9424c0934668fce2 100644 (file)
@@ -13,7 +13,8 @@ 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)", "Keywords")
+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"
 
index 652308a71cb8501d6deb791d9cd33c2e80408799..14d8b18613087caf1d8c311cc7e4648f17ca109a 100644 (file)
@@ -131,3 +131,129 @@ 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 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) {}
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
+
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'
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 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 472fffa61b791e5f07ef0cd97939383ac41a5188..7125c62dbaf9ad2da33782abe04979925f8fe542 100644 (file)
@@ -1,8 +1,8 @@
 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:21: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
index 8903c09c17f0dbb186105e309e33bf87f5f39856..ac254346c08a63841c9420354dcac1399e482732 100644 (file)
@@ -1,8 +1,8 @@
 error: future cannot be sent between threads safely
-  --> $DIR/issue-71137.rs:20:3
+  --> $DIR/issue-71137.rs:20: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
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 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/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 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/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;
+}
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..cedead0
--- /dev/null
@@ -0,0 +1,44 @@
+// compile-flags: --crate-type=lib
+#![feature(const_mut_refs)]
+#![feature(const_precise_live_drops)]
+#![feature(const_swap)]
+
+// 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
+}
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..aa6ed46
--- /dev/null
@@ -0,0 +1,33 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/qualif-indirect-mutation-fail.rs:8: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:14: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:30:9
+   |
+LL |     let _z = x;
+   |         ^^ constants cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/qualif-indirect-mutation-fail.rs:35: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:43:9
+   |
+LL |     let _y = x;
+   |         ^^ constant functions cannot evaluate destructors
+
+error: aborting due to 5 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..35a9b70
--- /dev/null
@@ -0,0 +1,16 @@
+// compile-flags: --crate-type=lib
+// check-pass
+#![feature(const_mut_refs)]
+#![feature(const_precise_live_drops)]
+
+pub const fn f() {
+    let mut x: (Option<String>, u32) = (None, 0);
+    let mut a = 10;
+    *(&mut a) = 11;
+    x.1 = a;
+}
+
+pub const fn g() {
+    let mut a: (u32, Option<String>) = (0, None);
+    let _ = &mut a.0;
+}
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 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 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
    |
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 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
    |
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
 
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/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![]);
+}
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
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`.
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
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 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 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`
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
 
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();
+}
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 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 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`.
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`
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 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
+
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 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 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 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 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
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
    |
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
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 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 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 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`
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`.
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/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,
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 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`
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 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
    |
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 7fbbf4e8f23e3c24b8afff541dcb17e53eb5ff88..6c1bc24b8b49d4bc965f67d7037906dc199c72b7 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 7fbbf4e8f23e3c24b8afff541dcb17e53eb5ff88
+Subproject commit 6c1bc24b8b49d4bc965f67d7037906dc199c72b7
index e700e5f0d736e7ca056dc0fdf0a355c429c07d38..3b4c687209e11dfa8ebb9454ad8c4af571a9677f 100644 (file)
@@ -2730,11 +2730,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
@@ -2836,6 +2838,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 +2899,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
@@ -3012,16 +3016,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,10 +3038,12 @@ 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_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
index ba3ed3053ac743466be07b2fdf04c97911dcc0f1..ed7fb1440139f7d199f5632cb54525633c0d48a1 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"
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..25320907bb492767f36da58f48e97d0b2d366477 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,12 @@ 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_lint(&lint, msrv).context("Unable to create lint implementation")?;
     create_test(&lint).context("Unable to create a test for the new lint")
 }
 
-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())
@@ -122,12 +106,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 +125,143 @@ 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 pass_name = lint.pass;
+    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: Register the lint pass in `clippy_lints/src/lib.rs`,
+                //       e.g. store.register_{pass_name}_pass(move || Box::new({module_name}::{name_camel}::new(msrv)));
+                // 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,
+            pass_name = pass_name,
+            name_upper = name_upper,
+            name_camel = name_camel,
+            module_name = lint_name,
+            context_import = context_import,
+        )
+    } else {
+        format!(
+            indoc! {"
+                declare_lint_pass!({name_camel} => [{name_upper}]);
+
+                impl {pass_type}{pass_lifetimes} for {name_camel} {{}}
+                //
+                // TODO: Register the lint pass in `clippy_lints/src/lib.rs`,
+                //       e.g. store.register_{pass_name}_pass(|| Box::new({module_name}::{name_camel}));
+            "},
+            pass_type = pass_type,
+            pass_lifetimes = pass_lifetimes,
+            pass_name = pass_name,
+            name_upper = name_upper,
+            name_camel = name_camel,
+            module_name = lint_name,
+        )
+    });
+
+    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..aaf9ac83d49005dad0df8a05de2dc7818dcedd06 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"
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..f0800c6a6f18f788bbb2804b20aaba1b8b362fc6 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,6 +423,7 @@ 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) {
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 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..5511c3ea9b6889701a2dbdfaf015fdec0fa5b987 100644 (file)
@@ -1,3 +1,4 @@
+use clippy_utils::attrs::is_doc_hidden;
 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::ty::{implements_trait, is_type_diagnostic_item};
@@ -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,
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 37d9ea3bdc117cae4b4e917425751ec27e155213..c22f9d0e170326c79fbdd0df8cc2228b27822aaf 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};
@@ -69,8 +68,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,
@@ -101,47 +100,3 @@ fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicabi
         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
-}
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 10bca59e6d06ab5da76ebe19bbba10020f50f9a8..e8cea5529e889100e88514becadc89e37aedec5e 100644 (file)
@@ -78,10 +78,10 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
                     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())
+                       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().to_string())
+                   format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par())
                 };
 
                 span_lint_and_sugg(
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 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..c949ee23ecc7a94858ce40214e496a881c8a08fd 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),
     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(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_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..ff56a6081fb57f8cbc44c08f785b2981900147f4 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,7 @@
     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_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
     LintId::of(unit_types::UNIT_CMP),
     LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
index b0be3b653664cd8f51ad4ea09b2bc6d77d7188ae..e8dd3708c8ed406dc3f92b6bff81332d49d9757e 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,
     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,
     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,
     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_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
     unit_types::LET_UNIT_VALUE,
     unit_types::UNIT_ARG,
index 96e0b421094d622f4495a3a9be49085127a5841a..1e54482a8dafdc7b5f73d3798f5fd5a04864cc2b 100644 (file)
@@ -25,6 +25,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..268349d28481182fdbac33fe20ba0d0312430fbf 100644 (file)
@@ -72,6 +72,7 @@
     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),
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..3d68a6e900958fbcfcd886007abc15c468b5ceef 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),
@@ -56,6 +57,7 @@
     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(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
     LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
     LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
index 5534f9c94f367fe6a2de3d1aab5fa91846534c17..ed7e827702395dc72336e5f2adaf24709324e6ac 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;
@@ -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,16 @@ 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_return_expecting_ord;
 mod unit_types;
 mod unnamed_address;
@@ -516,6 +521,7 @@ 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_return_expecting_ord::UnitReturnExpectingOrd));
     store.register_late_pass(|| Box::new(strings::StringAdd));
     store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn));
@@ -754,8 +760,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();
@@ -767,6 +773,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic));
     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));
+
 }
 
 #[rustfmt::skip]
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..a83f38e
--- /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(char::is_lowercase) },
+        CaseMethod::AsciiLowerCase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'a'..='z')) },
+        CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(char::is_uppercase) },
+        CaseMethod::AsciiUppercase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'A'..='Z')) },
+    };
+
+    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_lower_case", 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..b643fba5d328865baded5f1192cca02fa6ae979a 100644 (file)
@@ -1187,7 +1187,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;
     }
 
@@ -1693,12 +1693,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 +1706,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 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 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 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 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 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 d180d6f922710ddc01f1e822184a4630c0e08048..92a4801a8468ae3d3e592212280e8dd7959c9bc5 100644 (file)
     /// unsafe { std::slice::from_raw_parts(ptr::null(), 0); }
     /// ```
     ///
+    /// ```ignore
     /// // Good
     /// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); }
     /// ```
index aa6d254e7a54476acc0c109a431ae6b33d01f388..4d616e26bfc1da1dab23a26aaaf0dcbc3b009cf5 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,27 @@ fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool
         }
     }
 
+    fn expression_returns_unmodified_err(
+        cx: &LateContext<'_>,
+        expression: &Expr<'_>,
+        origin_hir_id: &Expr<'_>,
+    ) -> bool {
+        match expression.kind {
+            ExprKind::Block(block, _) => {
+                if let Some(return_expression) = Self::return_expression(block) {
+                    return Self::expression_returns_unmodified_err(cx, return_expression, origin_hir_id);
+                }
+
+                false
+            },
+            ExprKind::Ret(Some(expr)) | ExprKind::Call(expr, _) => {
+                Self::expression_returns_unmodified_err(cx, expr, origin_hir_id)
+            },
+            ExprKind::Path(_) => path_to_local(expression) == path_to_local(origin_hir_id),
+            _ => 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 +221,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 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..e08e4d0
--- /dev/null
@@ -0,0 +1,225 @@
+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 + 1) as usize;
+        let src_str = source_file.src.as_ref()?[lex_start..between_span.hi().0 as usize].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,
+            );
+        }
+    }
+}
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,
+    }
+}
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 6cbada4c1505b5374758d951ca2df152eec9a4d7..d05c52122d5ee518ab1d00f0349851909026151b 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.
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 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
 
index 74cf323720cbb400528a0cd416a361315f1288cb..60c4cb361aa6c0dfbc2d9ff534ca2569d9e7db18 100644 (file)
@@ -2,13 +2,16 @@
 
 #![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, 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, 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)`.
@@ -569,6 +572,106 @@ 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;
+                            then {
+                                let i = usize::try_from(position).unwrap();
+                                Some(FormatArgsArg { value: self.value_args[i], arg: &self.args[i], 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.
@@ -631,3 +734,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 8e94d16a33a0e41b1a167447e50b098bca917cf6..9bc380ca6caa6501c526c4edd18b2faa11df4a5c 100644 (file)
 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 {
@@ -1285,10 +1283,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 +1312,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 +1335,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 +1464,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
@@ -2062,27 +2057,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 appelied, 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 81aff585ded1be868421a758467c3a6ec84065f3..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 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"];
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 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..67eaf286004f9515cabbfefe3d889ec4b9c74b3f 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-10-07"
+channel = "nightly-2021-10-21"
 components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
index e8b1640c8693e5907cf93e491a713658b17e6a63..c15835ef2995687327d9227c861b1decd8b3f85d 100644 (file)
@@ -149,6 +149,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 +325,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 8e04d447fbcaaa3de92c81f26ff4cc450c5f39cd..12e05eaa7a09ab1070681f50275dbffff46e065d 100644 (file)
@@ -27,12 +27,13 @@ error: unnecessary `Symbol` to string conversion
   --> $DIR/unnecessary_symbol_str.rs:14:5
    |
 LL |     &*Ident::empty().as_str() == "clippy";
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::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::empty().to_string();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name`
 
 error: aborting due to 5 previous errors
+
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 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 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
index 8f823f1672ba2d30e868414cdf87104a39caa175..03bb30f9083ac4f3c21ab23a635747ef8ba128fd 100644 (file)
@@ -115,3 +115,13 @@ 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() {}
+    }
+}
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 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 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..73fc750511c78684cdd8650d03e6ce1dc40582b1 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);
index 4599fb5207ea85c280f07b863d39f798f6262eaa..2f4595650cbf3c8d3cdd716e3ea32a0e24113b58 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);
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..8376566
--- /dev/null
@@ -0,0 +1,105 @@
+// run-rustfix
+
+#![allow(unreachable_code)]
+#![allow(unused_macros)]
+#![allow(unused_variables)]
+#![allow(clippy::assertions_on_constants)]
+#![allow(clippy::eq_op)]
+#![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);
+
+    println!("error: something failed at {}", Somewhere.to_string());
+    println!("{} and again {0}", x.to_string());
+    my_macro!();
+    println!("error: something failed at {}", my_other_macro!());
+}
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..164cc07
--- /dev/null
@@ -0,0 +1,105 @@
+// run-rustfix
+
+#![allow(unreachable_code)]
+#![allow(unused_macros)]
+#![allow(unused_variables)]
+#![allow(clippy::assertions_on_constants)]
+#![allow(clippy::eq_op)]
+#![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());
+
+    println!("error: something failed at {}", Somewhere.to_string());
+    println!("{} and again {0}", x.to_string());
+    my_macro!();
+    println!("error: something failed at {}", my_other_macro!());
+}
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..9cfc97e
--- /dev/null
@@ -0,0 +1,106 @@
+error: `to_string` applied to a type that implements `Display` in `format!` args
+  --> $DIR/format_args.rs:75: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:79: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:84: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:86: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:87: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:88: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:89: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:90: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:91: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:92: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:93: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:94: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:95: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:96: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:97: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:98: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:99:20
+   |
+LL |     println!("{}", x_ref.to_string());
+   |                    ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref`
+
+error: aborting due to 17 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..a8c06c2
--- /dev/null
@@ -0,0 +1,60 @@
+#![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()));
+
+    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 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 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..ff91c4498ec62afd43c12497579a6a66925fd42a 100644 (file)
@@ -10,98 +10,95 @@ 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"),
         _ => (),
     }
-    */
 
     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..50246486bb6fc9371206f17adfe284b5e722a566 100644 (file)
@@ -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..208a4bb
--- /dev/null
@@ -0,0 +1,98 @@
+#![warn(clippy::match_str_case_mismatch)]
+
+// Valid
+
+fn as_str_match() {
+    let var = "BAR";
+
+    match var.to_ascii_lowercase().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 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..fa02347
--- /dev/null
@@ -0,0 +1,36 @@
+error: this `match` arm has a differing case than its expression
+  --> $DIR/match_str_case_mismatch.rs:68: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:78: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:93:9
+   |
+LL |         "bAR" => {},
+   |         ^^^^^
+   |
+help: consider changing the case of this arm to respect `to_ascii_uppercase`
+   |
+LL |         "BAR" => {},
+   |         ~~~~~
+
+error: aborting due to 3 previous errors
+
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 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 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..4077f1920a3837758a6f02f6f5b5ea8c6a2b078e 100644 (file)
@@ -1,8 +1,7 @@
 // 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..2f414e129d5a77c9952b88bd8e9efa5d0acc4249 100644 (file)
@@ -1,8 +1,7 @@
 // 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..803d941c36df8b2d8aa80ca7fa381ee8c35c780a 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:7: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:25: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:26: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:27: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:33: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:34: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:40: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:49: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:62: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:71: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:100: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:109: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:137: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:141:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
index 0b5746cb52270ed7e59d4126b7664151d1d39e95..ccb2e5a302e91590feb0ba2af50ae467e00e8115 100644 (file)
@@ -104,6 +104,21 @@ fn func() -> Option<i32> {
     Some(0)
 }
 
+fn result_func(x: Result<i32, &str>) -> Result<i32, &str> {
+    let _ = x?;
+
+    x?;
+
+    // No warning
+    let y = if let Ok(x) = x {
+        x
+    } else {
+        return Err("some error");
+    };
+
+    Ok(y)
+}
+
 fn main() {
     some_func(Some(42));
     some_func(None);
@@ -123,4 +138,6 @@ fn main() {
     returns_something_similar_to_option(so);
 
     func();
+
+    let _ = result_func(Ok(42));
 }
index 0f0825c9334679d185e9bc711dc86f05df0466d8..ca3722371f524b53b27ca94f15fd1a46e7d867ca 100644 (file)
@@ -134,6 +134,23 @@ fn f() -> Option<String> {
     Some(0)
 }
 
+fn result_func(x: Result<i32, &str>) -> Result<i32, &str> {
+    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("some error");
+    };
+
+    Ok(y)
+}
+
 fn main() {
     some_func(Some(42));
     some_func(None);
@@ -153,4 +170,6 @@ fn main() {
     returns_something_similar_to_option(so);
 
     func();
+
+    let _ = result_func(Ok(42));
 }
index 6f330cfa385dddeaab2c9473fb9c684f381aea27..161588cb73cba06797561917e4ee5fe6fa3710d9 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:138: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:140:5
+   |
+LL | /     if x.is_err() {
+LL | |         return x;
+LL | |     }
+   | |_____^ help: replace it with: `x?;`
+
+error: aborting due to 13 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 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
+
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 ee9c9045fff55940b42177b9eecef25bebe2b780..98bc1e80731ff3934643d2c565f70ad241ddd7f1 100644 (file)
@@ -230,4 +230,12 @@ mod super_imports {
             let _ = foofoo();
         }
     }
+
+    mod attestation_should_be_replaced {
+        use super::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
 }
index efaa8f9ef664186b0ba5e70a6d9cd4143bb31460..4ef61f9245b58f9420daded6c79a1d84e201edb9 100644 (file)
@@ -231,4 +231,12 @@ fn with_super_explicit() {
             let _ = foofoo();
         }
     }
+
+    mod attestation_should_be_replaced {
+        use super::*;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
 }
index 66267dd27b84fcf4da55e265ed164709a6e6647e..d7af0c046e88694f34a1ff399931fe346cc8904c 100644 (file)
@@ -122,5 +122,11 @@ error: usage of wildcard import
 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:236:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
 
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..98d1ee19f69a1ca8bdfb88a533d2d6c41eb5a34b 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,6 +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));
+                    has_edition = true;
                     if edition == "2021" {
                         self.compile_flags.push("-Zunstable-options".to_string());
                     }
@@ -391,6 +393,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 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 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 91cbda43c2af82b9377eff70a21f59ade18cd23c..1f47693e02809c97db61b51247ae4e4d46744c61 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 91cbda43c2af82b9377eff70a21f59ade18cd23c
+Subproject commit 1f47693e02809c97db61b51247ae4e4d46744c61
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 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 1e4df4d3fb79a58185907d63c0574bdeb779ec16..48c7a00de7830c83e4659f49f35358049949fea1 100644 (file)
@@ -5,8 +5,8 @@ allow-unauthenticated = [
     "requires-nightly",
     "regression-*",
     "perf-*",
-    # I-* without I-nominated
-    "I-*", "!I-nominated",
+    # I-* without I-*nominated
+    "I-*", "!I-*nominated",
     "AsyncAwait-OnDeck",
 ]