]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #106829 - compiler-errors:more-alias-combine, r=spastorino
authorMatthias Krüger <matthias.krueger@famsik.de>
Tue, 17 Jan 2023 04:25:22 +0000 (05:25 +0100)
committerGitHub <noreply@github.com>
Tue, 17 Jan 2023 04:25:22 +0000 (05:25 +0100)
Unify `Opaque`/`Projection` handling in region outlives code

They share basically identical paths in most places which are even easier to unify now that they're both `ty::Alias`

r? types

388 files changed:
.github/ISSUE_TEMPLATE/diagnostics.md [deleted file]
.github/ISSUE_TEMPLATE/diagnostics.yaml [new file with mode: 0644]
.github/ISSUE_TEMPLATE/documentation.md [deleted file]
.github/ISSUE_TEMPLATE/documentation.yaml [new file with mode: 0644]
.github/ISSUE_TEMPLATE/ice.md [deleted file]
.github/ISSUE_TEMPLATE/ice.yaml [new file with mode: 0644]
Cargo.lock
compiler/rustc_abi/src/lib.rs
compiler/rustc_ast/src/ast.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
compiler/rustc_borrowck/src/places_conflict.rs
compiler/rustc_borrowck/src/region_infer/opaque_types.rs
compiler/rustc_borrowck/src/session_diagnostics.rs
compiler/rustc_borrowck/src/type_check/canonical.rs
compiler/rustc_codegen_llvm/Cargo.toml
compiler/rustc_codegen_ssa/Cargo.toml
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/metadata.rs
compiler/rustc_driver/src/lib.rs
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0792.md [new file with mode: 0644]
compiler/rustc_error_messages/locales/en-US/borrowck.ftl
compiler/rustc_error_messages/locales/en-US/interface.ftl
compiler/rustc_error_messages/locales/en-US/mir_build.ftl
compiler/rustc_expand/src/base.rs
compiler/rustc_hir_analysis/src/astconv/mod.rs
compiler/rustc_hir_analysis/src/check/check.rs
compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
compiler/rustc_hir_analysis/src/check/wfcheck.rs
compiler/rustc_hir_analysis/src/coherence/builtin.rs
compiler/rustc_hir_analysis/src/coherence/mod.rs
compiler/rustc_hir_analysis/src/coherence/orphan.rs
compiler/rustc_hir_analysis/src/coherence/unsafety.rs
compiler/rustc_hir_analysis/src/collect.rs
compiler/rustc_hir_analysis/src/collect/predicates_of.rs
compiler/rustc_hir_analysis/src/impl_wf_check.rs
compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
compiler/rustc_hir_typeck/src/callee.rs
compiler/rustc_hir_typeck/src/cast.rs
compiler/rustc_hir_typeck/src/demand.rs
compiler/rustc_hir_typeck/src/expr_use_visitor.rs
compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
compiler/rustc_hir_typeck/src/method/confirm.rs
compiler/rustc_hir_typeck/src/method/probe.rs
compiler/rustc_hir_typeck/src/method/suggest.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/note.rs
compiler/rustc_infer/src/traits/util.rs
compiler/rustc_interface/Cargo.toml
compiler/rustc_interface/src/errors.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_lint/src/internal.rs
compiler/rustc_lint/src/pass_by_value.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_log/Cargo.toml
compiler/rustc_log/src/lib.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_middle/src/hir/mod.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/ty/consts.rs
compiler/rustc_middle/src/ty/diagnostics.rs
compiler/rustc_middle/src/ty/generics.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/parameterized.rs
compiler/rustc_middle/src/ty/print/mod.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/subst.rs
compiler/rustc_middle/src/ty/typeck_results.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_middle/src/values.rs
compiler/rustc_mir_build/src/errors.rs
compiler/rustc_mir_build/src/thir/pattern/check_match.rs
compiler/rustc_mir_transform/src/inline.rs
compiler/rustc_monomorphize/src/collector.rs
compiler/rustc_parse/src/lexer/mod.rs
compiler/rustc_parse/src/lexer/unicode_chars.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/pat.rs
compiler/rustc_parse/src/parser/stmt.rs
compiler/rustc_parse/src/parser/ty.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/options.rs
compiler/rustc_span/Cargo.toml
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/source_map/tests.rs
compiler/rustc_target/src/asm/mod.rs
compiler/rustc_trait_selection/src/solve/assembly.rs
compiler/rustc_trait_selection/src/solve/cache.rs
compiler/rustc_trait_selection/src/solve/fulfill.rs
compiler/rustc_trait_selection/src/solve/mod.rs
compiler/rustc_trait_selection/src/solve/overflow.rs
compiler/rustc_trait_selection/src/solve/project_goals.rs
compiler/rustc_trait_selection/src/solve/trait_goals.rs
compiler/rustc_trait_selection/src/traits/coherence.rs
compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/project.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/specialize/specialization_graph.rs
compiler/rustc_trait_selection/src/traits/vtable.rs
compiler/rustc_trait_selection/src/traits/wf.rs
compiler/rustc_traits/src/chalk/db.rs
compiler/rustc_traits/src/type_op.rs
compiler/rustc_ty_utils/src/implied_bounds.rs
compiler/rustc_ty_utils/src/ty.rs
library/alloc/src/alloc.rs
library/alloc/src/collections/binary_heap.rs [deleted file]
library/alloc/src/collections/binary_heap/mod.rs [new file with mode: 0644]
library/alloc/src/collections/binary_heap/tests.rs
library/alloc/src/lib.rs
library/alloc/src/rc.rs
library/alloc/src/sync.rs
library/alloc/src/vec/into_iter.rs
library/alloc/src/vec/is_zero.rs
library/alloc/src/vec/mod.rs
library/alloc/tests/vec.rs
library/core/src/array/iter.rs
library/core/src/fmt/mod.rs
library/core/src/iter/range.rs
library/core/src/iter/sources/from_generator.rs
library/core/src/num/dec2flt/fpu.rs
library/core/src/num/int_macros.rs
library/core/src/option.rs
library/core/src/pin.rs
library/core/src/ptr/mod.rs
library/core/src/slice/iter.rs
library/core/src/slice/iter/macros.rs
library/core/src/slice/mod.rs
library/core/src/slice/sort.rs
library/core/src/sync/atomic.rs
library/core/tests/slice.rs
library/std/src/fs.rs
library/std/src/io/buffered/tests.rs
library/std/src/os/fd/mod.rs
library/std/src/os/fd/owned.rs
library/std/src/panicking.rs
library/std/src/path.rs
library/std/src/sync/mpmc/array.rs
library/std/src/sync/mpmc/list.rs
library/std/src/sync/mpmc/mod.rs
library/std/src/sync/mpmc/utils.rs
library/std/src/sync/mpmc/zero.rs
library/std/src/sync/mpsc/mod.rs
library/std/src/sync/mpsc/sync_tests.rs
library/std/src/sys/itron/thread.rs
library/std/src/sys/unix/fs.rs
library/std/src/sys/unix/kernel_copy.rs
library/std/src/sys/unix/process/process_fuchsia.rs
library/std/src/sys/unix/process/process_unix.rs
library/std/src/sys/unix/process/process_unix/tests.rs
library/std/src/sys/unix/process/process_vxworks.rs
library/std/src/sys/unix/thread.rs
library/std/src/sys/windows/os.rs
library/std/src/sys/windows/thread.rs
library/test/src/lib.rs
library/test/src/term/terminfo/searcher.rs
src/README.md
src/bootstrap/bin/rustc.rs
src/bootstrap/builder.rs
src/bootstrap/check.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh
src/ci/docker/host-x86_64/mingw-check/Dockerfile
src/doc/book
src/doc/nomicon
src/doc/reference
src/doc/rust-by-example
src/doc/rustc-dev-guide
src/doc/rustc/src/instrument-coverage.md
src/doc/rustdoc/src/lints.md
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/blanket_impl.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/simplify.rs
src/librustdoc/formats/cache.rs
src/librustdoc/html/format.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/context.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/render/search_index.rs
src/librustdoc/html/render/write_shared.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/settings.css
src/librustdoc/html/static/js/main.js
src/librustdoc/html/static/js/settings.js
src/librustdoc/html/templates/print_item.html
src/librustdoc/lib.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_intra_doc_links/early.rs
src/librustdoc/passes/stripper.rs
src/tools/cargo
src/tools/clippy/clippy_lints/src/derive.rs
src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
src/tools/clippy/clippy_lints/src/from_over_into.rs
src/tools/clippy/clippy_lints/src/missing_inline.rs
src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
src/tools/clippy/clippy_lints/src/use_self.rs
src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs
src/tools/rustbook/Cargo.toml
src/tools/rustbook/src/main.rs
src/tools/tidy/Cargo.toml
src/tools/tidy/src/deps.rs
src/tools/tidy/src/lib.rs
src/tools/tidy/src/main.rs
src/tools/tidy/src/rustdoc_gui_tests.rs [new file with mode: 0644]
tests/codegen/issue-45964-bounds-check-slice-pos.rs
tests/mir-opt/building/custom/consts.rs
tests/mir-opt/building/custom/consts.statics.built.after.mir
tests/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff
tests/mir-opt/const_prop/mutable_variable_no_prop.rs
tests/mir-opt/inline/inline_into_box_place.main.Inline.diff
tests/mir-opt/inline/issue_106141.outer.Inline.diff [new file with mode: 0644]
tests/mir-opt/inline/issue_106141.rs [new file with mode: 0644]
tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
tests/mir-opt/issues/issue_75439.rs
tests/rustdoc-gui/anchors.goml
tests/rustdoc-gui/basic-code.goml
tests/rustdoc-gui/headings.goml
tests/rustdoc-gui/method-margins.goml
tests/rustdoc-gui/scrape-examples-button-focus.goml
tests/rustdoc-gui/search-result-go-to-first.goml
tests/rustdoc-gui/settings.goml
tests/rustdoc-gui/toggle-click-deadspace.goml
tests/rustdoc-gui/toggle-docs.goml
tests/rustdoc-gui/toggled-open-implementations.goml
tests/rustdoc-ui/invalid-syntax.stderr
tests/rustdoc-ui/z-help.stdout
tests/rustdoc/doc-notable_trait-slice.bare_fn_matches.html
tests/rustdoc/doc-notable_trait.bare-fn.html
tests/rustdoc/doc-notable_trait.some-struct-new.html
tests/rustdoc/doc-notable_trait.wrap-me.html
tests/rustdoc/index-page.rs
tests/rustdoc/issue-41783.rs
tests/rustdoc/keyword.rs
tests/rustdoc/local-reexport-doc.rs
tests/rustdoc/mixing-doc-comments-and-attrs.rs
tests/rustdoc/multiple-import-levels.rs
tests/rustdoc/primitive-reference.rs
tests/rustdoc/primitive-slice-auto-trait.rs
tests/rustdoc/primitive-tuple-auto-trait.rs
tests/rustdoc/primitive-unit-auto-trait.rs
tests/rustdoc/primitive.rs
tests/rustdoc/spotlight-from-dependency.odd.html
tests/rustdoc/strip-block-doc-comments-stars.rs
tests/rustdoc/toggle-item-contents.rs
tests/rustdoc/toggle-method.rs
tests/rustdoc/toggle-trait-fn.rs
tests/ui/associated-item/ambiguous-associated-type-with-generics.fixed [new file with mode: 0644]
tests/ui/associated-item/ambiguous-associated-type-with-generics.rs [new file with mode: 0644]
tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr [new file with mode: 0644]
tests/ui/associated-item/associated-item-duplicate-names-3.stderr
tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
tests/ui/associated-types/issue-43784-associated-type.stderr
tests/ui/attributes/log-backtrace.rs [new file with mode: 0644]
tests/ui/borrowck/issue-92157.rs [new file with mode: 0644]
tests/ui/borrowck/issue-92157.stderr [new file with mode: 0644]
tests/ui/cast/cast-as-bool.rs
tests/ui/cast/cast-as-bool.stderr
tests/ui/cast/issue-106883-is-empty.rs [new file with mode: 0644]
tests/ui/cast/issue-106883-is-empty.stderr [new file with mode: 0644]
tests/ui/chalkify/bugs/async.rs
tests/ui/chalkify/bugs/async.stderr
tests/ui/closures/issue-84128.stderr
tests/ui/closures/issue-87461.stderr
tests/ui/const-generics/unused_braces.fixed
tests/ui/const-generics/unused_braces.rs
tests/ui/const-generics/unused_braces.stderr
tests/ui/consts/const-match-check.eval1.stderr
tests/ui/consts/const-match-check.eval2.stderr
tests/ui/consts/const-match-check.matchck.stderr
tests/ui/dep-graph/dep-graph-dump.rs [new file with mode: 0644]
tests/ui/dep-graph/dep-graph-dump.stderr [new file with mode: 0644]
tests/ui/derives/issue-91550.stderr
tests/ui/did_you_mean/bad-assoc-ty.stderr
tests/ui/error-codes/E0223.rs
tests/ui/error-codes/E0223.stderr
tests/ui/errors/auxiliary/remapped_dep.rs [new file with mode: 0644]
tests/ui/errors/remap-path-prefix-reverse.local-self.stderr [new file with mode: 0644]
tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr [new file with mode: 0644]
tests/ui/errors/remap-path-prefix-reverse.rs [new file with mode: 0644]
tests/ui/errors/remap-path-prefix.rs [new file with mode: 0644]
tests/ui/errors/remap-path-prefix.stderr [new file with mode: 0644]
tests/ui/generic-associated-types/issue-74824.stderr
tests/ui/generic-associated-types/missing-bounds.stderr
tests/ui/generics/issue-106694.rs [new file with mode: 0644]
tests/ui/generics/issue-106694.stderr [new file with mode: 0644]
tests/ui/higher-rank-trait-bounds/issue-42114.rs [new file with mode: 0644]
tests/ui/impl-trait/impl_trait_projections.rs
tests/ui/impl-trait/impl_trait_projections.stderr
tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr
tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr
tests/ui/inference/cannot-infer-partial-try-return.stderr
tests/ui/inference/question-mark-type-infer.stderr
tests/ui/issues/issue-23073.stderr
tests/ui/issues/issue-69455.stderr
tests/ui/issues/issue-78622.stderr
tests/ui/lint/bare-trait-objects-path.stderr
tests/ui/lint/unused_braces.fixed
tests/ui/lint/unused_braces.rs
tests/ui/lint/unused_braces.stderr
tests/ui/mismatched_types/issue-35030.stderr
tests/ui/missing-trait-bounds/issue-35677.stderr
tests/ui/parser/issues/issue-66473.stderr
tests/ui/parser/issues/issue-68629.stderr
tests/ui/parser/issues/issue-68730.stderr
tests/ui/parser/unicode-chars.rs
tests/ui/parser/unicode-chars.stderr
tests/ui/pattern/issue-106552.rs [new file with mode: 0644]
tests/ui/pattern/issue-106552.stderr [new file with mode: 0644]
tests/ui/proc-macro/panic-abort.rs [new file with mode: 0644]
tests/ui/proc-macro/panic-abort.stderr [new file with mode: 0644]
tests/ui/proc-macro/pretty-print-hack-show.local.stderr [new file with mode: 0644]
tests/ui/proc-macro/pretty-print-hack-show.local.stdout [new file with mode: 0644]
tests/ui/proc-macro/pretty-print-hack-show.remapped.stderr [new file with mode: 0644]
tests/ui/proc-macro/pretty-print-hack-show.remapped.stdout [new file with mode: 0644]
tests/ui/proc-macro/pretty-print-hack-show.rs
tests/ui/proc-macro/pretty-print-hack-show.stderr [deleted file]
tests/ui/proc-macro/pretty-print-hack-show.stdout [deleted file]
tests/ui/qualified/qualified-path-params-2.stderr
tests/ui/remap-path-prefix.rs [deleted file]
tests/ui/remap-path-prefix.stderr [deleted file]
tests/ui/resolve/issue-103202.stderr
tests/ui/self/self-impl.stderr
tests/ui/structs/struct-path-associated-type.stderr
tests/ui/suggestions/args-instead-of-tuple-errors.stderr
tests/ui/suggestions/call-on-unimplemented-with-autoderef.rs [new file with mode: 0644]
tests/ui/suggestions/call-on-unimplemented-with-autoderef.stderr [new file with mode: 0644]
tests/ui/suggestions/constrain-suggest-ice.stderr
tests/ui/suggestions/issue-105761-suggest-self-for-closure.fixed [new file with mode: 0644]
tests/ui/suggestions/issue-105761-suggest-self-for-closure.rs [new file with mode: 0644]
tests/ui/suggestions/issue-105761-suggest-self-for-closure.stderr [new file with mode: 0644]
tests/ui/suggestions/let-binding-init-expr-as-ty.stderr
tests/ui/suggestions/sugg-else-for-closure.stderr
tests/ui/suggestions/type-mismatch-byte-literal.rs [new file with mode: 0644]
tests/ui/suggestions/type-mismatch-byte-literal.stderr [new file with mode: 0644]
tests/ui/traits/fn-trait-cast-diagnostic.rs [new file with mode: 0644]
tests/ui/traits/fn-trait-cast-diagnostic.stderr [new file with mode: 0644]
tests/ui/traits/issue-106072.rs [new file with mode: 0644]
tests/ui/traits/issue-106072.stderr [new file with mode: 0644]
tests/ui/traits/issue-43784-supertrait.stderr
tests/ui/traits/issue-52893.stderr
tests/ui/traits/issue-99875.stderr
tests/ui/traits/item-privacy.stderr
tests/ui/traits/track-obligations.rs [new file with mode: 0644]
tests/ui/traits/track-obligations.stderr [new file with mode: 0644]
tests/ui/type-alias-impl-trait/bound_reduction2.rs
tests/ui/type-alias-impl-trait/bound_reduction2.stderr
tests/ui/type-alias-impl-trait/generic_nondefining_use.rs
tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr
tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs
tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
tests/ui/type-alias-impl-trait/issue-60564.rs
tests/ui/type-alias-impl-trait/issue-60564.stderr
tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs
tests/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr
tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs
tests/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr
tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs
tests/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr
tests/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr
tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs [new file with mode: 0644]
tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr [new file with mode: 0644]
tests/ui/typeck/issue-104513-ice.stderr
tests/ui/typeck/issue-46112.stderr
tests/ui/typeck/issue-84768.stderr
tests/ui/ufcs/ufcs-partially-resolved.stderr
tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr
triagebot.toml

diff --git a/.github/ISSUE_TEMPLATE/diagnostics.md b/.github/ISSUE_TEMPLATE/diagnostics.md
deleted file mode 100644 (file)
index a7b70ce..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
----
-name: Diagnostic issue
-about: Create a bug report or feature request for a change to `rustc`'s error output
-labels: A-diagnostics, T-compiler
----
-<!--
-Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
-along with any information you feel relevant to replicating the bug.
-
-If you cannot produce a minimal reproduction case (something that would work in
-isolation), please provide the steps or even link to a repository that causes
-the problematic output to occur.
--->
-
-Given the following code: <!-- Please provide a link to play.rust-lang.org -->
-
-```rust
-<code>
-```
-
-The current output is:
-
-```
-<rustc output>
-```
-
-<!-- The following is not always necessary. -->
-Ideally the output should look like:
-
-```
-<proposed output>
-```
-
-<!--
-If the problem is not self-explanatory, please provide a rationale for the
-change.
--->
-
-<!--
-If dramatically different output is caused by small changes, consider also
-adding them here.
-
-If you're using the stable version of the compiler, you should also check if the
-bug also exists in the beta or nightly versions. The output might also be
-different depending on the Edition.
--->
diff --git a/.github/ISSUE_TEMPLATE/diagnostics.yaml b/.github/ISSUE_TEMPLATE/diagnostics.yaml
new file mode 100644 (file)
index 0000000..873fbaa
--- /dev/null
@@ -0,0 +1,65 @@
+name: Diagnostic issue
+description: Create a bug report or feature request for a change to `rustc`'s error output
+labels: ["A-diagnostics", "T-compiler"]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        Thank you for filing a diagnostics bug report! 🐛
+
+        Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug.
+
+        If you cannot produce a minimal reproduction case (something that would work in isolation), please provide the steps or even link to a repository that causes the problematic output to occur.
+  - type: textarea
+    id: code
+    attributes:
+      label: Code
+      description: Please provide code that can reproduce the problem
+      placeholder: code
+      render: Rust
+    validations:
+      required: true
+  - type: textarea
+    id: output
+    attributes:
+      label: Current output
+      description: Please provide the `rustc` output you see
+      placeholder: rustc output
+      render: Shell
+    validations:
+      required: true
+  - type: textarea
+    id: desired-output
+    attributes:
+      label: Desired output
+      description: Please provide what the output *should* be
+      placeholder: proposed output
+      render: Shell
+    validations:
+      required: false
+  - type: textarea
+    id: rationale
+    attributes:
+      label: Rationale and extra context
+      description: If the problem is not self-explanatory, please provide a rationale for the change.
+    validations:
+      required: false
+  - type: textarea
+    id: other-output
+    attributes:
+      label: Other cases
+      description: If dramatically different output is caused by small changes, consider also adding them here.
+      render: Rust
+    validations:
+      required: false
+  - type: markdown
+    attributes:
+      value: |
+        If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. The output might also be different depending on the Edition.
+  - type: textarea
+    id: extra
+    attributes:
+      label: Anything else?
+      description: If you have more details you want to give us to reproduce this issue, please add it here
+    validations:
+      required: false
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md
deleted file mode 100644 (file)
index 9ccda17..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
----
-name: Documentation problem
-about: Create a report for a documentation problem.
-labels: A-docs
----
-<!--
-
-Thank you for finding a documentation problem! 📚
-
-Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present.
-
-Note: If your issue is for one of these, please use their dedicated issue tracker instead:
-
-- The Rust Book: https://github.com/rust-lang/book/issues
-- Rust by Example: https://github.com/rust-lang/rust-by-example/issues
-- The Edition Guide: https://github.com/rust-lang/edition-guide/issues
-- The Cargo Book: https://github.com/rust-lang/cargo/issues
-- The Clippy Book: https://github.com/rust-lang/rust-clippy/issues
-- The Reference: https://github.com/rust-lang/reference/issues
-- The Rustonomicon: https://github.com/rust-lang/nomicon/issues
-- The Embedded Book: https://github.com/rust-embedded/book/issues
-
-All other documentation issues should be filed here.
-
-Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead.
-
--->
-
-### Location
-
-### Summary
diff --git a/.github/ISSUE_TEMPLATE/documentation.yaml b/.github/ISSUE_TEMPLATE/documentation.yaml
new file mode 100644 (file)
index 0000000..712b327
--- /dev/null
@@ -0,0 +1,38 @@
+name: Documentation problem
+description: Create a report for a documentation problem.
+labels: ["A-docs"]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        Thank you for finding a documentation problem! 📚
+
+        Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present.
+
+        Note: If your issue is for one of these, please use their dedicated issue tracker instead:
+        - [The Rust Book](https://github.com/rust-lang/book/issues)
+        - [Rust by Example](https://github.com/rust-lang/rust-by-example/issues)
+        - [The Edition Guide](https://github.com/rust-lang/edition-guide/issues)
+        - [The Cargo Book](https://github.com/rust-lang/cargo/issues)
+        - [The Clippy Book](https://github.com/rust-lang/rust-clippy/issues)
+        - [The Reference](https://github.com/rust-lang/reference/issues)
+        - [The Rustonomicon](https://github.com/rust-lang/nomicon/issues)
+        - [The Embedded Book](https://github.com/rust-embedded/book/issues)
+
+        All other documentation issues should be filed here.
+
+        Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead.
+
+  - type: textarea
+    id: location
+    attributes:
+      label: Location
+    validations:
+      required: true 
+
+  - type: textarea
+    id: summary
+    attributes:
+      label: Summary
+    validations:
+      required: true 
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/ice.md b/.github/ISSUE_TEMPLATE/ice.md
deleted file mode 100644 (file)
index 03bc4ba..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
----
-name: Internal Compiler Error
-about: Create a report for an internal compiler error in rustc.
-labels: C-bug, I-ICE, T-compiler
----
-<!--
-Thank you for finding an Internal Compiler Error! 🧊  If possible, try to provide
-a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for
-how to create smaller examples.
-
-http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
-
--->
-
-### Code
-
-```Rust
-<code>
-```
-
-
-### Meta
-<!--
-If you're using the stable version of the compiler, you should also check if the
-bug also exists in the beta or nightly versions.
--->
-
-`rustc --version --verbose`:
-```
-<version>
-```
-
-### Error output
-
-```
-<output>
-```
-
-<!--
-Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
-environment. E.g. `RUST_BACKTRACE=1 cargo build`.
--->
-<details><summary><strong>Backtrace</strong></summary>
-<p>
-
-```
-<backtrace>
-```
-
-</p>
-</details>
-
diff --git a/.github/ISSUE_TEMPLATE/ice.yaml b/.github/ISSUE_TEMPLATE/ice.yaml
new file mode 100644 (file)
index 0000000..54136cc
--- /dev/null
@@ -0,0 +1,82 @@
+name: Internal Compiler Error
+description: Create a report for an internal compiler error in `rustc`
+labels: ["C-bug", "I-ICE", "T-compiler"]
+title: "[ICE]: "
+body:
+  - type: markdown
+    attributes:
+      value: |
+        Thank you for finding an Internal Compiler Error! 🧊
+
+        If possible, try to provide a minimal verifiable example.
+
+        You can read "[Rust Bug Minimization Patterns](http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/)" for how to create smaller examples.
+
+  - type: textarea
+    id: code
+    attributes:
+      label: Code
+      description: Please provide code or a link to a repository that can reproduce the problem
+      placeholder: code
+      render: Rust
+    validations:
+      required: false
+
+  - type: checkboxes
+    attributes:
+      label: Affected release channels
+      description: If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions
+      options:
+        - label: Previous Stable
+          required: false
+        - label: Current Stable
+          required: false
+        - label: Current Beta
+          required: false
+        - label: Current Nightly
+          required: false
+
+  - type: textarea
+    id: version
+    attributes:
+      label: Rust Version
+      description: Please provide the `rustc` version, `rustc --version --verbose`
+      placeholder: |
+        $ rustc --version --verbose
+        rustc 1.XX.Y (SHORTHASH DATE)
+        binary: rustc
+        commit-hash: LONGHASHVALUE
+        commit-date: DATE
+        host: PLATFORMTRIPLE
+        release: 1.XX.Y
+        LLVM version: XX.YY.ZZ
+      render: Shell
+    validations:
+      required: true
+
+  - type: textarea
+    id: output
+    attributes:
+      label: Current error output
+      description: Please provide the `rustc` output you see
+      placeholder: output
+      render: Shell
+    validations:
+      required: false
+
+  - type: textarea
+    id: backtrace
+    attributes:
+      label: Backtrace
+      description: Include a backtrace in the code block by setting `RUST_BACKTRACE=full` in your environment, e.g. `RUST_BACKTRACE=full cargo build`
+      render: Shell
+    validations:
+      required: true
+
+  - type: textarea
+    id: extra
+    attributes:
+      label: Anything else?
+      description: If you have more details you want to give us to reproduce this issue, please add it here
+    validations:
+      required: false
\ No newline at end of file
index 4bea3af7f3bfa111809d367b6a651d37d2e51910..5511d301775590f8f9cec20e81a88d0b4afdae2c 100644 (file)
@@ -35,6 +35,17 @@ dependencies = [
  "version_check",
 ]
 
+[[package]]
+name = "ahash"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+]
+
 [[package]]
 name = "aho-corasick"
 version = "0.7.18"
@@ -107,7 +118,7 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "276881980556fdadeb88aa1ffc667e4d2e8fe72531dfabcb7a82bb3c9ea9ba31"
 dependencies = [
- "object",
+ "object 0.29.0",
 ]
 
 [[package]]
@@ -193,7 +204,7 @@ dependencies = [
  "cfg-if",
  "libc",
  "miniz_oxide",
- "object",
+ "object 0.29.0",
  "rustc-demangle",
 ]
 
@@ -340,7 +351,7 @@ dependencies = [
  "cargo-test-macro",
  "cargo-test-support",
  "cargo-util",
- "clap 4.0.15",
+ "clap 4.0.32",
  "crates-io",
  "curl",
  "curl-sys",
@@ -644,26 +655,27 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.0.15"
+version = "4.0.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bf8832993da70a4c6d13c581f4463c2bdda27b9bf1c5498dc4365543abe6d6f"
+checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
 dependencies = [
- "atty",
  "bitflags",
- "clap_derive 4.0.13",
+ "clap_derive 4.0.21",
  "clap_lex 0.3.0",
+ "is-terminal",
  "once_cell",
  "strsim",
  "termcolor",
+ "terminal_size",
 ]
 
 [[package]]
 name = "clap_complete"
-version = "3.1.1"
+version = "4.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df6f3613c0a3cddfd78b41b10203eb322cb29b600cbdf808a7d3db95691b8e25"
+checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
 dependencies = [
- "clap 3.2.20",
+ "clap 4.0.32",
 ]
 
 [[package]]
@@ -681,9 +693,9 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "4.0.13"
+version = "4.0.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c42f169caba89a7d512b5418b09864543eeb4d497416c917d7137863bd2076ad"
+checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
 dependencies = [
  "heck",
  "proc-macro-error",
@@ -1773,9 +1785,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.26.1"
+version = "0.26.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
+checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
 dependencies = [
  "compiler_builtins",
  "fallible-iterator",
@@ -1886,12 +1898,21 @@ version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 dependencies = [
- "ahash",
+ "ahash 0.7.4",
  "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
 
+[[package]]
+name = "hashbrown"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038"
+dependencies = [
+ "ahash 0.8.2",
+]
+
 [[package]]
 name = "heck"
 version = "0.4.0"
@@ -2128,12 +2149,12 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
 
 [[package]]
 name = "indexmap"
-version = "1.9.1"
+version = "1.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
+checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
 dependencies = [
  "autocfg",
- "hashbrown",
+ "hashbrown 0.12.3",
  "rustc-rayon",
  "serde",
 ]
@@ -2273,7 +2294,7 @@ name = "jsondoclint"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "clap 4.0.15",
+ "clap 4.0.32",
  "fs-err",
  "rustdoc-json-types",
  "serde",
@@ -2529,21 +2550,21 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.21"
+version = "0.4.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23f3e133c6d515528745ffd3b9f0c7d975ae039f0b6abb099f2168daa2afb4f9"
+checksum = "d1ed28d5903dde77bd5182645078a37ee57014cac6ccb2d54e1d6496386648e4"
 dependencies = [
  "ammonia",
  "anyhow",
  "chrono",
- "clap 3.2.20",
+ "clap 4.0.32",
  "clap_complete",
  "elasticlunr-rs",
- "env_logger 0.9.0",
+ "env_logger 0.10.0",
  "handlebars 4.3.3",
- "lazy_static",
  "log",
  "memchr",
+ "once_cell",
  "opener",
  "pulldown-cmark 0.9.2",
  "regex",
@@ -2739,13 +2760,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
 dependencies = [
  "compiler_builtins",
+ "memchr",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
+]
+
+[[package]]
+name = "object"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d864c91689fdc196779b98dba0aceac6118594c2df6ee5d943eb6a8df4d107a"
+dependencies = [
  "crc32fast",
  "flate2",
- "hashbrown",
+ "hashbrown 0.13.1",
  "indexmap",
  "memchr",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
 ]
 
 [[package]]
@@ -3013,9 +3043,9 @@ dependencies = [
 
 [[package]]
 name = "pest"
-version = "2.3.0"
+version = "2.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4"
+checksum = "0f6e86fb9e7026527a0d46bc308b841d73170ef8f443e1807f6ef88526a816d4"
 dependencies = [
  "thiserror",
  "ucd-trie",
@@ -3023,9 +3053,9 @@ dependencies = [
 
 [[package]]
 name = "pest_derive"
-version = "2.3.0"
+version = "2.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "905708f7f674518498c1f8d644481440f476d39ca6ecae83319bba7c6c12da91"
+checksum = "96504449aa860c8dcde14f9fba5c58dc6658688ca1fe363589d6327b8662c603"
 dependencies = [
  "pest",
  "pest_generator",
@@ -3033,9 +3063,9 @@ dependencies = [
 
 [[package]]
 name = "pest_generator"
-version = "2.3.0"
+version = "2.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad"
+checksum = "798e0220d1111ae63d66cb66a5dcb3fc2d986d520b98e49e1852bfdb11d7c5e7"
 dependencies = [
  "pest",
  "pest_meta",
@@ -3046,13 +3076,13 @@ dependencies = [
 
 [[package]]
 name = "pest_meta"
-version = "2.3.0"
+version = "2.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04"
+checksum = "984298b75898e30a843e278a9f2452c31e349a073a0ce6fd950a12a74464e065"
 dependencies = [
  "once_cell",
  "pest",
- "sha-1",
+ "sha1",
 ]
 
 [[package]]
@@ -3498,7 +3528,7 @@ dependencies = [
 name = "rustbook"
 version = "0.1.0"
 dependencies = [
- "clap 3.2.20",
+ "clap 4.0.32",
  "env_logger 0.7.1",
  "mdbook",
 ]
@@ -3790,7 +3820,7 @@ dependencies = [
  "cstr",
  "libc",
  "measureme",
- "object",
+ "object 0.30.1",
  "rustc-demangle",
  "rustc_ast",
  "rustc_attr",
@@ -3825,7 +3855,7 @@ dependencies = [
  "itertools",
  "jobserver",
  "libc",
- "object",
+ "object 0.30.1",
  "pathdiff",
  "regex",
  "rustc_arena",
@@ -4273,6 +4303,7 @@ version = "0.0.0"
 dependencies = [
  "rustc_span",
  "tracing",
+ "tracing-core",
  "tracing-subscriber",
  "tracing-tree",
 ]
@@ -4683,7 +4714,7 @@ dependencies = [
  "rustc_macros",
  "rustc_serialize",
  "scoped-tls",
- "sha-1",
+ "sha1",
  "sha2",
  "tracing",
  "unicode-width",
@@ -5092,17 +5123,6 @@ dependencies = [
  "serde",
 ]
 
-[[package]]
-name = "sha-1"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
-dependencies = [
- "cfg-if",
- "cpufeatures",
- "digest",
-]
-
 [[package]]
 name = "sha1"
 version = "0.10.5"
@@ -5305,11 +5325,11 @@ dependencies = [
  "core",
  "dlmalloc",
  "fortanix-sgx-abi",
- "hashbrown",
+ "hashbrown 0.12.3",
  "hermit-abi 0.2.6",
  "libc",
  "miniz_oxide",
- "object",
+ "object 0.29.0",
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
@@ -5477,6 +5497,16 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "terminal_size"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
+dependencies = [
+ "rustix",
+ "windows-sys",
+]
+
 [[package]]
 name = "termize"
 version = "0.1.1"
@@ -5528,18 +5558,18 @@ checksum = "ceb05e71730d396f960f8f3901cdb41be2d339b303e9d7d3a07c5ff0536e671b"
 
 [[package]]
 name = "thiserror"
-version = "1.0.33"
+version = "1.0.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.33"
+version = "1.0.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5548,13 +5578,13 @@ dependencies = [
 
 [[package]]
 name = "thorin-dwp"
-version = "0.3.0"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6cb0c7868d7f90407531108ab03263d9452a8811b7cdd87675343a40d4aa254"
+checksum = "da8fbf660a019b6bf11ea95762041464aa9099cc293b6a66d77cea5107619671"
 dependencies = [
  "gimli",
- "hashbrown",
- "object",
+ "hashbrown 0.12.3",
+ "object 0.30.1",
  "tracing",
 ]
 
@@ -5571,6 +5601,7 @@ dependencies = [
 name = "tidy"
 version = "0.1.0"
 dependencies = [
+ "cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "cargo_metadata 0.14.0",
  "ignore",
  "lazy_static",
@@ -5692,9 +5723,9 @@ dependencies = [
 
 [[package]]
 name = "topological-sort"
-version = "0.1.0"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa7c7f42dea4b1b99439786f5633aeb9c14c1b53f75e282803c2ec2ad545873c"
+checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
 
 [[package]]
 name = "tracing"
@@ -5820,9 +5851,9 @@ dependencies = [
 
 [[package]]
 name = "ucd-trie"
-version = "0.1.3"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
+checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
 
 [[package]]
 name = "ui_test"
@@ -6089,9 +6120,9 @@ checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
 
 [[package]]
 name = "version_check"
-version = "0.9.3"
+version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
 [[package]]
 name = "vte"
index 4582d3c6badf99491254930d6e7c0f3ee6d7cff8..b48654d1ac36a44fa39aa059709b4b9dcbfd5dac 100644 (file)
@@ -1100,7 +1100,7 @@ pub enum FieldsShape {
         /// named `inverse_memory_index`.
         ///
         // FIXME(eddyb) build a better abstraction for permutations, if possible.
-        // FIXME(camlorn) also consider small vector  optimization here.
+        // FIXME(camlorn) also consider small vector optimization here.
         memory_index: Vec<u32>,
     },
 }
index 7de594719ddc44568872ea3ee2516da728a96ada..9317579f70dd5967cb5e80382c8cab541c58ecea 100644 (file)
@@ -2032,7 +2032,8 @@ fn clone(&self) -> Self {
 impl Ty {
     pub fn peel_refs(&self) -> &Self {
         let mut final_ty = self;
-        while let TyKind::Ref(_, MutTy { ty, .. }) = &final_ty.kind {
+        while let TyKind::Ref(_, MutTy { ty, .. }) | TyKind::Ptr(MutTy { ty, .. }) = &final_ty.kind
+        {
             final_ty = ty;
         }
         final_ty
index 6658ee89ad6f1bd0c86c011afc14e83be2413d0b..e512099b93b136b4478d56517246867fc94833ec 100644 (file)
@@ -6,6 +6,7 @@
     struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
 };
 use rustc_hir as hir;
+use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
 use rustc_infer::infer::TyCtxtInferExt;
@@ -20,7 +21,7 @@
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::DesugaringKind;
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{kw, sym};
 use rustc_span::{BytePos, Span, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt;
 
@@ -29,6 +30,7 @@
 
 use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
 use crate::diagnostics::find_all_local_uses;
+use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref;
 use crate::{
     borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
     InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
@@ -356,7 +358,7 @@ fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) {
         if let Some(hir::Node::Item(hir::Item {
             kind: hir::ItemKind::Fn(_, _, body_id),
             ..
-        })) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_id()))
+        })) = hir.find(self.mir_hir_id())
             && let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
         {
             let place = &self.move_data.move_paths[mpi].place;
@@ -671,40 +673,34 @@ fn suggest_borrow_fn_like(
         let tcx = self.infcx.tcx;
 
         // Find out if the predicates show that the type is a Fn or FnMut
-        let find_fn_kind_from_did = |predicates: ty::EarlyBinder<
-            &[(ty::Predicate<'tcx>, Span)],
-        >,
-                                     substs| {
-            predicates.0.iter().find_map(|(pred, _)| {
-                    let pred = if let Some(substs) = substs {
-                        predicates.rebind(*pred).subst(tcx, substs).kind().skip_binder()
-                    } else {
-                        pred.kind().skip_binder()
-                    };
-                    if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred && pred.self_ty() == ty {
-                    if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
-                        return Some(hir::Mutability::Not);
-                    } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
-                        return Some(hir::Mutability::Mut);
-                    }
+        let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| {
+            if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder()
+                && pred.self_ty() == ty
+            {
+                if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
+                    return Some(hir::Mutability::Not);
+                } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
+                    return Some(hir::Mutability::Mut);
                 }
-                    None
-                })
+            }
+            None
         };
 
         // If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
         // borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
         // These types seem reasonably opaque enough that they could be substituted with their
         // borrowed variants in a function body when we see a move error.
-        let borrow_level = match ty.kind() {
-            ty::Param(_) => find_fn_kind_from_did(
-                tcx.bound_explicit_predicates_of(self.mir_def_id().to_def_id())
-                    .map_bound(|p| p.predicates),
-                None,
-            ),
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
-                find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*def_id), Some(*substs))
-            }
+        let borrow_level = match *ty.kind() {
+            ty::Param(_) => tcx
+                .explicit_predicates_of(self.mir_def_id().to_def_id())
+                .predicates
+                .iter()
+                .copied()
+                .find_map(find_fn_kind_from_did),
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
+                .bound_explicit_item_bounds(def_id)
+                .subst_iter_copied(tcx, substs)
+                .find_map(find_fn_kind_from_did),
             ty::Closure(_, substs) => match substs.as_closure().kind() {
                 ty::ClosureKind::Fn => Some(hir::Mutability::Not),
                 ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
@@ -948,7 +944,7 @@ pub(crate) fn report_conflicting_borrow(
             }
             (BorrowKind::Mut { .. }, BorrowKind::Shared) => {
                 first_borrow_desc = "immutable ";
-                self.cannot_reborrow_already_borrowed(
+                let mut err = self.cannot_reborrow_already_borrowed(
                     span,
                     &desc_place,
                     &msg_place,
@@ -958,7 +954,13 @@ pub(crate) fn report_conflicting_borrow(
                     "immutable",
                     &msg_borrow,
                     None,
-                )
+                );
+                self.suggest_binding_for_closure_capture_self(
+                    &mut err,
+                    issued_borrow.borrowed_place,
+                    &issued_spans,
+                );
+                err
             }
 
             (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
@@ -1240,6 +1242,138 @@ fn suggest_split_at_mut_if_applicable(
         }
     }
 
+    fn suggest_binding_for_closure_capture_self(
+        &self,
+        err: &mut Diagnostic,
+        borrowed_place: Place<'tcx>,
+        issued_spans: &UseSpans<'tcx>,
+    ) {
+        let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
+        let hir = self.infcx.tcx.hir();
+
+        // check whether the borrowed place is capturing `self` by mut reference
+        let local = borrowed_place.local;
+        let Some(_) = self
+            .body
+            .local_decls
+            .get(local)
+            .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) else { return };
+
+        struct ExpressionFinder<'hir> {
+            capture_span: Span,
+            closure_change_spans: Vec<Span>,
+            closure_arg_span: Option<Span>,
+            in_closure: bool,
+            suggest_arg: String,
+            hir: rustc_middle::hir::map::Map<'hir>,
+            closure_local_id: Option<hir::HirId>,
+            closure_call_changes: Vec<(Span, String)>,
+        }
+        impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
+            fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
+                if e.span.contains(self.capture_span) {
+                    if let hir::ExprKind::Closure(&hir::Closure {
+                            movability: None,
+                            body,
+                            fn_arg_span,
+                            fn_decl: hir::FnDecl{ inputs, .. },
+                            ..
+                        }) = e.kind &&
+                        let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) {
+                            self.suggest_arg = "this: &Self".to_string();
+                            if inputs.len() > 0 {
+                                self.suggest_arg.push_str(", ");
+                            }
+                            self.in_closure = true;
+                            self.closure_arg_span = fn_arg_span;
+                            self.visit_expr(body);
+                            self.in_closure = false;
+                    }
+                }
+                if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e {
+                    if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
+                        seg.ident.name == kw::SelfLower && self.in_closure {
+                            self.closure_change_spans.push(e.span);
+                    }
+                }
+                hir::intravisit::walk_expr(self, e);
+            }
+
+            fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
+                if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat &&
+                    let Some(init) = local.init
+                {
+                    if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure {
+                            movability: None,
+                            ..
+                        }), .. } = init &&
+                        init.span.contains(self.capture_span) {
+                            self.closure_local_id = Some(*hir_id);
+                    }
+                }
+                hir::intravisit::walk_local(self, local);
+            }
+
+            fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) {
+                if let hir::StmtKind::Semi(e) = s.kind &&
+                    let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind &&
+                    let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
+                    let Res::Local(hir_id) = seg.res &&
+                        Some(hir_id) == self.closure_local_id {
+                        let (span, arg_str) = if args.len() > 0 {
+                            (args[0].span.shrink_to_lo(), "self, ".to_string())
+                        } else {
+                            let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span);
+                            (span, "(self)".to_string())
+                        };
+                        self.closure_call_changes.push((span, arg_str));
+                }
+                hir::intravisit::walk_stmt(self, s);
+            }
+        }
+
+        if let Some(hir::Node::ImplItem(
+                    hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. }
+                )) = hir.find(self.mir_hir_id()) &&
+            let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) {
+            let mut finder = ExpressionFinder {
+                capture_span: *capture_kind_span,
+                closure_change_spans: vec![],
+                closure_arg_span: None,
+                in_closure: false,
+                suggest_arg: String::new(),
+                closure_local_id: None,
+                closure_call_changes: vec![],
+                hir,
+            };
+            finder.visit_expr(expr);
+
+            if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() {
+                return;
+            }
+
+            let mut sugg = vec![];
+            let sm = self.infcx.tcx.sess.source_map();
+
+            if let Some(span) = finder.closure_arg_span {
+                sugg.push((sm.next_point(span.shrink_to_lo()).shrink_to_hi(), finder.suggest_arg));
+            }
+            for span in finder.closure_change_spans {
+                sugg.push((span, "this".to_string()));
+            }
+
+            for (span, suggest) in finder.closure_call_changes {
+                sugg.push((span, suggest));
+            }
+
+            err.multipart_suggestion_verbose(
+                "try explicitly pass `&Self` into the Closure as an argument",
+                sugg,
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
     /// Returns the description of the root place for a conflicting borrow and the full
     /// descriptions of the places that caused the conflict.
     ///
index b9cfc7e69610e5d83aed21b6198f245e122757a6..45b15c2c5bd7062451a9b947584ecacb2f504d0f 100644 (file)
@@ -1094,7 +1094,7 @@ fn expected_fn_found_fn_mut_call(&self, err: &mut Diagnostic, sp: Span, act: &st
     }
 }
 
-fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
+pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
     debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
 
     match local_decl.local_info.as_deref() {
index 89ac0dfa4d6f51c2e61225b7d27b8fda4895bb57..918fb2d69237e4cb48b125a85daab2a60f8635dc 100644 (file)
@@ -209,7 +209,7 @@ fn place_components_conflict<'tcx>(
             match (elem, &base_ty.kind(), access) {
                 (_, _, Shallow(Some(ArtificialField::ArrayLength)))
                 | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
-                    // The array length is like  additional fields on the
+                    // The array length is like additional fields on the
                     // type; it does not overlap any existing data there.
                     // Furthermore, if cannot actually be a prefix of any
                     // borrowed place (at least in MIR as it is currently.)
index 767f9fe39c68b7162092c6b53e2cb00383373a84..9d8812b7eeaac5e03c8d13001a027ef0d24f67a1 100644 (file)
@@ -12,6 +12,8 @@
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::ObligationCtxt;
 
+use crate::session_diagnostics::NonGenericOpaqueTypeParam;
+
 use super::RegionInferenceContext;
 
 impl<'tcx> RegionInferenceContext<'tcx> {
@@ -235,7 +237,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
     /// # Parameters
     ///
     /// - `def_id`, the `impl Trait` type
-    /// - `substs`, the substs  used to instantiate this opaque type
+    /// - `substs`, the substs used to instantiate this opaque type
     /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
     ///   `opaque_defn.concrete_ty`
     #[instrument(level = "debug", skip(self))]
@@ -389,17 +391,13 @@ fn check_opaque_type_parameter_valid(
         } else {
             // Prevent `fn foo() -> Foo<u32>` from being defining.
             let opaque_param = opaque_generics.param_at(i, tcx);
-            tcx.sess
-                .struct_span_err(span, "non-defining opaque type use in defining scope")
-                .span_note(
-                    tcx.def_span(opaque_param.def_id),
-                    &format!(
-                        "used non-generic {} `{}` for generic parameter",
-                        opaque_param.kind.descr(),
-                        arg,
-                    ),
-                )
-                .emit();
+            let kind = opaque_param.kind.descr();
+            tcx.sess.emit_err(NonGenericOpaqueTypeParam {
+                ty: arg,
+                kind,
+                span,
+                param_span: tcx.def_span(opaque_param.def_id),
+            });
             return false;
         }
     }
index 577332c0744b84dd8447af7ab3519a33ef18abe0..23acf159240fa7bf509b44ee9683a6bac6acd87c 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_errors::{IntoDiagnosticArg, MultiSpan};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{GenericArg, Ty};
 use rustc_span::Span;
 
 use crate::diagnostics::RegionName;
@@ -240,3 +240,14 @@ pub(crate) struct MoveBorrow<'a> {
     #[label]
     pub borrow_span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(borrowck_opaque_type_non_generic_param, code = "E0792")]
+pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
+    pub ty: GenericArg<'tcx>,
+    pub kind: &'a str,
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub param_span: Span,
+}
index 02222c0a03cb350f9dcfdebc2b963db3f1edfcd5..11729e2c83f0b9d098788e495a6db5ea5b271ce5 100644 (file)
@@ -107,11 +107,7 @@ pub(super) fn normalize_and_prove_instantiated_predicates(
         instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
         locations: Locations,
     ) {
-        for (predicate, span) in instantiated_predicates
-            .predicates
-            .into_iter()
-            .zip(instantiated_predicates.spans.into_iter())
-        {
+        for (predicate, span) in instantiated_predicates {
             debug!(?predicate);
             let category = ConstraintCategory::Predicate(span);
             let predicate = self.normalize_with_category(predicate, locations, category);
index 93d6234dc884550875cf4aef0b3ce89dc2250f5d..9c1bcd431ec4933b2d858b5d6eb21bcffbfabe69 100644 (file)
@@ -11,7 +11,10 @@ bitflags = "1.0"
 cstr = "0.2"
 libc = "0.2"
 measureme = "10.0.0"
-object = { version = "0.29.0", default-features = false, features = ["std", "read"] }
+object = { version = "0.30.1", default-features = false, features = [
+    "std",
+    "read",
+] }
 tracing = "0.1"
 rustc_middle = { path = "../rustc_middle" }
 rustc-demangle = "0.1.21"
index d1ad687e6aee32a2b3e30c17557e58e366efce87..0d2d2ec68a23f3adf9ac9d928d0a435bb67c6c9b 100644 (file)
@@ -15,7 +15,7 @@ tracing = "0.1"
 libc = "0.2.50"
 jobserver = "0.1.22"
 tempfile = "3.2"
-thorin-dwp = "0.3"
+thorin-dwp = "0.4"
 pathdiff = "0.2.0"
 serde_json = "1.0.59"
 snap = "1"
@@ -44,6 +44,6 @@ rustc_session = { path = "../rustc_session" }
 rustc_const_eval = { path = "../rustc_const_eval" }
 
 [dependencies.object]
-version = "0.29.0"
+version = "0.30.1"
 default-features = false
 features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
index 8ca7103ed482cc5f7646537165823a4dbcf2041d..342abf81f6a7c0d6b465ce23375dcecd80868297 100644 (file)
@@ -1231,12 +1231,21 @@ fn infer_from(
                     sess.emit_fatal(errors::LinkerFileStem);
                 });
 
+                // Remove any version postfix.
+                let stem = stem
+                    .rsplit_once('-')
+                    .and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
+                    .unwrap_or(stem);
+
+                // GCC can have an optional target prefix.
                 let flavor = if stem == "emcc" {
                     LinkerFlavor::EmCc
                 } else if stem == "gcc"
                     || stem.ends_with("-gcc")
+                    || stem == "g++"
+                    || stem.ends_with("-g++")
                     || stem == "clang"
-                    || stem.ends_with("-clang")
+                    || stem == "clang++"
                 {
                     LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target)
                 } else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
index 51c5c375d51913fabe116d1a52b6245224ab0006..7d3c14fec5fbf91e26146346386c3faf4c38c724 100644 (file)
@@ -100,7 +100,13 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
     };
     let architecture = match &sess.target.arch[..] {
         "arm" => Architecture::Arm,
-        "aarch64" => Architecture::Aarch64,
+        "aarch64" => {
+            if sess.target.pointer_width == 32 {
+                Architecture::Aarch64_Ilp32
+            } else {
+                Architecture::Aarch64
+            }
+        }
         "x86" => Architecture::I386,
         "s390x" => Architecture::S390x,
         "mips" => Architecture::Mips,
@@ -165,11 +171,23 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
                 };
             e_flags
         }
-        Architecture::Riscv64 if sess.target.options.features.contains("+d") => {
-            // copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
-            // that the `+d` target feature represents whether the double
-            // float abi is enabled.
-            let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
+        Architecture::Riscv32 | Architecture::Riscv64 => {
+            // Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc
+            let mut e_flags: u32 = 0x0;
+            let features = &sess.target.options.features;
+            // Check if compressed is enabled
+            if features.contains("+c") {
+                e_flags |= elf::EF_RISCV_RVC;
+            }
+
+            // Select the appropriate floating-point ABI
+            if features.contains("+d") {
+                e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE;
+            } else if features.contains("+f") {
+                e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE;
+            } else {
+                e_flags |= elf::EF_RISCV_FLOAT_ABI_SOFT;
+            }
             e_flags
         }
         _ => 0,
index 16f64235562f119d3f020e487e51a5f5b3c046fd..a62e5dec4b8643aba7ebc69ff4ffc5c6e67e1db5 100644 (file)
@@ -231,6 +231,10 @@ fn run_compiler(
         registry: diagnostics_registry(),
     };
 
+    if !tracing::dispatcher::has_been_set() {
+        init_rustc_env_logger_with_backtrace_option(&config.opts.unstable_opts.log_backtrace);
+    }
+
     match make_input(config.opts.error_format, &matches.free) {
         Err(reported) => return Err(reported),
         Ok(Some((input, input_file_path))) => {
@@ -1300,7 +1304,14 @@ pub fn install_ice_hook() {
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version.
 pub fn init_rustc_env_logger() {
-    if let Err(error) = rustc_log::init_rustc_env_logger() {
+    init_rustc_env_logger_with_backtrace_option(&None);
+}
+
+/// This allows tools to enable rust logging without having to magically match rustc's
+/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to
+/// choose a target module you wish to show backtraces along with its logging.
+pub fn init_rustc_env_logger_with_backtrace_option(backtrace_target: &Option<String>) {
+    if let Err(error) = rustc_log::init_rustc_env_logger_with_backtrace_option(backtrace_target) {
         early_error(ErrorOutputType::default(), &error.to_string());
     }
 }
@@ -1366,7 +1377,6 @@ pub(super) fn install() {}
 pub fn main() -> ! {
     let start_time = Instant::now();
     let start_rss = get_resident_set_size();
-    init_rustc_env_logger();
     signal_handler::install();
     let mut callbacks = TimePassesCallbacks::default();
     install_ice_hook();
index 24258974bb97c67e05cabf9d649757f5d5d4ebf6..5c77448f908ede209440e084060a346d57b57f23 100644 (file)
 E0788: include_str!("./error_codes/E0788.md"),
 E0790: include_str!("./error_codes/E0790.md"),
 E0791: include_str!("./error_codes/E0791.md"),
+E0792: include_str!("./error_codes/E0792.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
diff --git a/compiler/rustc_error_codes/src/error_codes/E0792.md b/compiler/rustc_error_codes/src/error_codes/E0792.md
new file mode 100644 (file)
index 0000000..bad2b5a
--- /dev/null
@@ -0,0 +1,60 @@
+A type alias impl trait can only have its hidden type assigned
+when used fully generically (and within their defining scope).
+This means
+
+```compile_fail,E0792
+#![feature(type_alias_impl_trait)]
+
+type Foo<T> = impl std::fmt::Debug;
+
+fn foo() -> Foo<u32> {
+    5u32
+}
+```
+
+is not accepted. If it were accepted, one could create unsound situations like
+
+```compile_fail,E0792
+#![feature(type_alias_impl_trait)]
+
+type Foo<T> = impl Default;
+
+fn foo() -> Foo<u32> {
+    5u32
+}
+
+fn main() {
+    let x = Foo::<&'static mut String>::default();
+}
+```
+
+
+Instead you need to make the function generic:
+
+```
+#![feature(type_alias_impl_trait)]
+
+type Foo<T> = impl std::fmt::Debug;
+
+fn foo<U>() -> Foo<U> {
+    5u32
+}
+```
+
+This means that no matter the generic parameter to `foo`,
+the hidden type will always be `u32`.
+If you want to link the generic parameter to the hidden type,
+you can do that, too:
+
+
+```
+#![feature(type_alias_impl_trait)]
+
+use std::fmt::Debug;
+
+type Foo<T: Debug> = impl Debug;
+
+fn foo<U: Debug>() -> Foo<U> {
+    Vec::<U>::new()
+}
+```
index 2cd4733220e829ce4d68d0dc4bb3aee962277608..9e4332c428386ff068dd0a2f49ba859cd3b758d4 100644 (file)
@@ -120,3 +120,7 @@ borrowck_cannot_move_when_borrowed =
         [value] value
         *[other] {$value_place}
     } occurs here
+
+borrowck_opaque_type_non_generic_param =
+    expected generic {$kind} parameter, found `{$ty}`
+    .label = this generic parameter must be used with a generic {$kind} parameter
index bbcb8fc28cffa1a24a5f5f0d7d44303185562703..688b044722260ce0dc7070b425cd43e79f22aaf1 100644 (file)
@@ -41,3 +41,6 @@ interface_rustc_error_unexpected_annotation =
 
 interface_failed_writing_file =
     failed to write file {$path}: {$error}"
+
+interface_proc_macro_crate_panic_abort =
+    building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
index a082c0b61fa7ed293b873b9e054f7f9e1481957e..224855fff8b56f35a7e02214a87749dd8cc89890 100644 (file)
@@ -364,3 +364,5 @@ mir_build_suggest_let_else = you might want to use `let else` to handle the {$co
         [one] variant that isn't
         *[other] variants that aren't
     } matched
+
+mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
index 00453f78287efb8ab9067dbbf1fae3a27e43984e..ffde8480c02117283c3ac7c47d96f4c48dcabe58 100644 (file)
 use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, FileName, RealFileName, Span, DUMMY_SP};
+use rustc_span::{BytePos, FileName, Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
 
 use std::iter;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use std::rc::Rc;
 
 pub(crate) use rustc_span::hygiene::MacroKind;
@@ -1423,8 +1423,10 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &ParseSess) -> bool {
             if let [variant] = &*enum_def.variants {
                 if variant.ident.name == sym::Input {
                     let filename = sess.source_map().span_to_filename(item.ident.span);
-                    if let FileName::Real(RealFileName::LocalPath(path)) = filename {
-                        if let Some(c) = path
+                    if let FileName::Real(real) = filename {
+                        if let Some(c) = real
+                            .local_path()
+                            .unwrap_or(Path::new(""))
                             .components()
                             .flat_map(|c| c.as_os_str().to_str())
                             .find(|c| c.starts_with("rental") || c.starts_with("allsorts-rental"))
index 9fa0e6e8eaa646d396ca2049b9fc69c59587862e..7ac4f65049042b9aaa9864e0809c0a8aa3fb59af 100644 (file)
@@ -27,6 +27,7 @@
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{walk_generics, Visitor as _};
 use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
@@ -510,9 +511,7 @@ fn inferred_kind(
                             return tcx.const_error(ty).into();
                         }
                         if !infer_args && has_default {
-                            tcx.bound_const_param_default(param.def_id)
-                                .subst(tcx, substs.unwrap())
-                                .into()
+                            tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
                         } else {
                             if infer_args {
                                 self.astconv.ct_infer(ty, Some(param), self.span).into()
@@ -1643,8 +1642,8 @@ trait here instead: `trait NewTrait: {} {{}}`",
     fn report_ambiguous_associated_type(
         &self,
         span: Span,
-        type_str: &str,
-        trait_str: &str,
+        types: &[String],
+        traits: &[String],
         name: Symbol,
     ) -> ErrorGuaranteed {
         let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
@@ -1655,19 +1654,92 @@ fn report_ambiguous_associated_type(
             .keys()
             .any(|full_span| full_span.contains(span))
         {
-            err.span_suggestion(
+            err.span_suggestion_verbose(
                 span.shrink_to_lo(),
                 "you are looking for the module in `std`, not the primitive type",
                 "std::",
                 Applicability::MachineApplicable,
             );
         } else {
-            err.span_suggestion(
-                span,
-                "use fully-qualified syntax",
-                format!("<{} as {}>::{}", type_str, trait_str, name),
-                Applicability::HasPlaceholders,
-            );
+            match (types, traits) {
+                ([], []) => {
+                    err.span_suggestion_verbose(
+                        span,
+                        &format!(
+                            "if there were a type named `Type` that implements a trait named \
+                             `Trait` with associated type `{name}`, you could use the \
+                             fully-qualified path",
+                        ),
+                        format!("<Type as Trait>::{name}"),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                ([], [trait_str]) => {
+                    err.span_suggestion_verbose(
+                        span,
+                        &format!(
+                            "if there were a type named `Example` that implemented `{trait_str}`, \
+                             you could use the fully-qualified path",
+                        ),
+                        format!("<Example as {trait_str}>::{name}"),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                ([], traits) => {
+                    err.span_suggestions(
+                        span,
+                        &format!(
+                            "if there were a type named `Example` that implemented one of the \
+                             traits with associated type `{name}`, you could use the \
+                             fully-qualified path",
+                        ),
+                        traits
+                            .iter()
+                            .map(|trait_str| format!("<Example as {trait_str}>::{name}"))
+                            .collect::<Vec<_>>(),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                ([type_str], []) => {
+                    err.span_suggestion_verbose(
+                        span,
+                        &format!(
+                            "if there were a trait named `Example` with associated type `{name}` \
+                             implemented for `{type_str}`, you could use the fully-qualified path",
+                        ),
+                        format!("<{type_str} as Example>::{name}"),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                (types, []) => {
+                    err.span_suggestions(
+                        span,
+                        &format!(
+                            "if there were a trait named `Example` with associated type `{name}` \
+                             implemented for one of the types, you could use the fully-qualified \
+                             path",
+                        ),
+                        types
+                            .into_iter()
+                            .map(|type_str| format!("<{type_str} as Example>::{name}")),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                (types, traits) => {
+                    let mut suggestions = vec![];
+                    for type_str in types {
+                        for trait_str in traits {
+                            suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
+                        }
+                    }
+                    err.span_suggestions(
+                        span,
+                        "use the fully-qualified path",
+                        suggestions,
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
         }
         err.emit()
     }
@@ -1994,7 +2066,7 @@ pub fn associated_path_to_ty(
                 };
 
                 self.one_bound_for_assoc_type(
-                    || traits::supertraits(tcx, ty::Binder::dummy(trait_ref)),
+                    || traits::supertraits(tcx, ty::Binder::dummy(trait_ref.subst_identity())),
                     || "Self".to_string(),
                     assoc_ident,
                     span,
@@ -2050,12 +2122,64 @@ pub fn associated_path_to_ty(
                     err.emit()
                 } else if let Err(reported) = qself_ty.error_reported() {
                     reported
+                } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
+                    // `<impl Trait as OtherTrait>::Assoc` makes no sense.
+                    struct_span_err!(
+                        tcx.sess,
+                        tcx.def_span(alias_ty.def_id),
+                        E0667,
+                        "`impl Trait` is not allowed in path parameters"
+                    )
+                    .emit() // Already reported in an earlier stage.
                 } else {
+                    // Find all the `impl`s that `qself_ty` has for any trait that has the
+                    // associated type, so that we suggest the right one.
+                    let infcx = tcx.infer_ctxt().build();
+                    // We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()`
+                    // to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`.
+                    let param_env = ty::ParamEnv::empty();
+                    let traits: Vec<_> = self
+                        .tcx()
+                        .all_traits()
+                        .filter(|trait_def_id| {
+                            // Consider only traits with the associated type
+                            tcx.associated_items(*trait_def_id)
+                                .in_definition_order()
+                                .any(|i| {
+                                    i.kind.namespace() == Namespace::TypeNS
+                                        && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
+                                        && matches!(i.kind, ty::AssocKind::Type)
+                                })
+                            // Consider only accessible traits
+                            && tcx.visibility(*trait_def_id)
+                                .is_accessible_from(self.item_def_id(), tcx)
+                            && tcx.all_impls(*trait_def_id)
+                                .any(|impl_def_id| {
+                                    let trait_ref = tcx.impl_trait_ref(impl_def_id);
+                                    trait_ref.map_or(false, |trait_ref| {
+                                        let impl_ = trait_ref.subst(
+                                            tcx,
+                                            infcx.fresh_substs_for_item(span, impl_def_id),
+                                        );
+                                        infcx
+                                            .can_eq(
+                                                param_env,
+                                                tcx.erase_regions(impl_.self_ty()),
+                                                tcx.erase_regions(qself_ty),
+                                            )
+                                            .is_ok()
+                                    })
+                                    && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
+                                })
+                        })
+                        .map(|trait_def_id| tcx.def_path_str(trait_def_id))
+                        .collect();
+
                     // Don't print `TyErr` to the user.
                     self.report_ambiguous_associated_type(
                         span,
-                        &qself_ty.to_string(),
-                        "Trait",
+                        &[qself_ty.to_string()],
+                        &traits,
                         assoc_ident.name,
                     )
                 };
@@ -2173,16 +2297,30 @@ fn qpath_to_ty(
             let is_part_of_self_trait_constraints = def_id == trait_def_id;
             let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
 
-            let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
-                "Self"
+            let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
+                vec!["Self".to_string()]
             } else {
-                "Type"
+                // Find all the types that have an `impl` for the trait.
+                tcx.all_impls(trait_def_id)
+                    .filter(|impl_def_id| {
+                        // Consider only accessible traits
+                        tcx.visibility(*impl_def_id).is_accessible_from(self.item_def_id(), tcx)
+                            && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
+                    })
+                    .filter_map(|impl_def_id| tcx.impl_trait_ref(impl_def_id))
+                    .map(|impl_| impl_.subst_identity().self_ty())
+                    // We don't care about blanket impls.
+                    .filter(|self_ty| !self_ty.has_non_region_param())
+                    .map(|self_ty| tcx.erase_regions(self_ty).to_string())
+                    .collect()
             };
-
+            // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
+            // references the trait. Relevant for the first case in
+            // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
             let reported = self.report_ambiguous_associated_type(
                 span,
-                type_name,
-                &path_str,
+                &type_names,
+                &[path_str],
                 item_segment.ident.name,
             );
             return tcx.ty_error_with_guaranteed(reported)
@@ -3167,7 +3305,13 @@ fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
                 let label = "add `dyn` keyword before this trait";
                 let mut diag =
                     rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
-                diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
+                if self_ty.span.can_be_used_for_suggestions() {
+                    diag.multipart_suggestion_verbose(
+                        label,
+                        sugg,
+                        Applicability::MachineApplicable,
+                    );
+                }
                 // check if the impl trait that we are considering is a impl of a local trait
                 self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
                 diag.emit();
index 43795cfba3fd81edc85efcd69526445e26c82a54..e58669433e2189c501620fd0af3f826f2accd333 100644 (file)
@@ -540,7 +540,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
                     tcx,
                     it.span,
                     it.owner_id.def_id,
-                    impl_trait_ref,
+                    impl_trait_ref.subst_identity(),
                     &impl_.items,
                 );
                 check_on_unimplemented(tcx, it);
index 7af89934d1420eea5e4461e267710b54f589204d..c43bfd16ab1e4496d35ffcd81162d71d6c99d9b4 100644 (file)
@@ -2,7 +2,9 @@
 use crate::errors::LifetimesOrBoundsMismatchOnTrait;
 use hir::def_id::{DefId, LocalDefId};
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
-use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
+use rustc_errors::{
+    pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan,
+};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit;
@@ -207,9 +209,11 @@ fn compare_method_predicate_entailment<'tcx>(
     //
     // We then register the obligations from the impl_m and check to see
     // if all constraints hold.
-    hybrid_preds
-        .predicates
-        .extend(trait_m_predicates.instantiate_own(tcx, trait_to_placeholder_substs).predicates);
+    hybrid_preds.predicates.extend(
+        trait_m_predicates
+            .instantiate_own(tcx, trait_to_placeholder_substs)
+            .map(|(predicate, _)| predicate),
+    );
 
     // Construct trait parameter environment and then shift it into the placeholder viewpoint.
     // The key step here is to update the caller_bounds's predicates to be
@@ -228,7 +232,7 @@ fn compare_method_predicate_entailment<'tcx>(
     debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
 
     let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
-    for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
+    for (predicate, span) in impl_m_own_bounds {
         let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
         let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
 
@@ -320,15 +324,6 @@ fn compare_method_predicate_entailment<'tcx>(
             ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
         ));
     }
-    let emit_implied_wf_lint = || {
-        infcx.tcx.struct_span_lint_hir(
-            rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
-            impl_m_hir_id,
-            infcx.tcx.def_span(impl_m.def_id),
-            "impl method assumes more implied bounds than the corresponding trait method",
-            |lint| lint,
-        );
-    };
 
     // Check that all obligations are satisfied by the implementation's
     // version.
@@ -346,7 +341,7 @@ fn compare_method_predicate_entailment<'tcx>(
                 )
                 .map(|()| {
                     // If the skip-mode was successful, emit a lint.
-                    emit_implied_wf_lint();
+                    emit_implied_wf_lint(infcx.tcx, impl_m, impl_m_hir_id, vec![]);
                 });
             }
             CheckImpliedWfMode::Skip => {
@@ -382,8 +377,16 @@ fn compare_method_predicate_entailment<'tcx>(
                     CheckImpliedWfMode::Skip,
                 )
                 .map(|()| {
+                    let bad_args = extract_bad_args_for_implies_lint(
+                        tcx,
+                        &errors,
+                        (trait_m, trait_sig),
+                        // Unnormalized impl sig corresponds to the HIR types written
+                        (impl_m, unnormalized_impl_sig),
+                        impl_m_hir_id,
+                    );
                     // If the skip-mode was successful, emit a lint.
-                    emit_implied_wf_lint();
+                    emit_implied_wf_lint(tcx, impl_m, impl_m_hir_id, bad_args);
                 });
             }
             CheckImpliedWfMode::Skip => {
@@ -400,6 +403,141 @@ fn compare_method_predicate_entailment<'tcx>(
     Ok(())
 }
 
+fn extract_bad_args_for_implies_lint<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    errors: &[infer::RegionResolutionError<'tcx>],
+    (trait_m, trait_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
+    (impl_m, impl_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
+    hir_id: hir::HirId,
+) -> Vec<(Span, Option<String>)> {
+    let mut blame_generics = vec![];
+    for error in errors {
+        // Look for the subregion origin that contains an input/output type
+        let origin = match error {
+            infer::RegionResolutionError::ConcreteFailure(o, ..) => o,
+            infer::RegionResolutionError::GenericBoundFailure(o, ..) => o,
+            infer::RegionResolutionError::SubSupConflict(_, _, o, ..) => o,
+            infer::RegionResolutionError::UpperBoundUniverseConflict(.., o, _) => o,
+        };
+        // Extract (possible) input/output types from origin
+        match origin {
+            infer::SubregionOrigin::Subtype(trace) => {
+                if let Some((a, b)) = trace.values.ty() {
+                    blame_generics.extend([a, b]);
+                }
+            }
+            infer::SubregionOrigin::RelateParamBound(_, ty, _) => blame_generics.push(*ty),
+            infer::SubregionOrigin::ReferenceOutlivesReferent(ty, _) => blame_generics.push(*ty),
+            _ => {}
+        }
+    }
+
+    let fn_decl = tcx.hir().fn_decl_by_hir_id(hir_id).unwrap();
+    let opt_ret_ty = match fn_decl.output {
+        hir::FnRetTy::DefaultReturn(_) => None,
+        hir::FnRetTy::Return(ty) => Some(ty),
+    };
+
+    // Map late-bound regions from trait to impl, so the names are right.
+    let mapping = std::iter::zip(
+        tcx.fn_sig(trait_m.def_id).bound_vars(),
+        tcx.fn_sig(impl_m.def_id).bound_vars(),
+    )
+    .filter_map(|(impl_bv, trait_bv)| {
+        if let ty::BoundVariableKind::Region(impl_bv) = impl_bv
+            && let ty::BoundVariableKind::Region(trait_bv) = trait_bv
+        {
+            Some((impl_bv, trait_bv))
+        } else {
+            None
+        }
+    })
+    .collect();
+
+    // For each arg, see if it was in the "blame" of any of the region errors.
+    // If so, then try to produce a suggestion to replace the argument type with
+    // one from the trait.
+    let mut bad_args = vec![];
+    for (idx, (ty, hir_ty)) in
+        std::iter::zip(impl_sig.inputs_and_output, fn_decl.inputs.iter().chain(opt_ret_ty))
+            .enumerate()
+    {
+        let expected_ty = trait_sig.inputs_and_output[idx]
+            .fold_with(&mut RemapLateBound { tcx, mapping: &mapping });
+        if blame_generics.iter().any(|blame| ty.contains(*blame)) {
+            let expected_ty_sugg = expected_ty.to_string();
+            bad_args.push((
+                hir_ty.span,
+                // Only suggest something if it actually changed.
+                (expected_ty_sugg != ty.to_string()).then_some(expected_ty_sugg),
+            ));
+        }
+    }
+
+    bad_args
+}
+
+struct RemapLateBound<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    mapping: &'a FxHashMap<ty::BoundRegionKind, ty::BoundRegionKind>,
+}
+
+impl<'tcx> TypeFolder<'tcx> for RemapLateBound<'_, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        if let ty::ReFree(fr) = *r {
+            self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
+                bound_region: self
+                    .mapping
+                    .get(&fr.bound_region)
+                    .copied()
+                    .unwrap_or(fr.bound_region),
+                ..fr
+            }))
+        } else {
+            r
+        }
+    }
+}
+
+fn emit_implied_wf_lint<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: &ty::AssocItem,
+    hir_id: hir::HirId,
+    bad_args: Vec<(Span, Option<String>)>,
+) {
+    let span: MultiSpan = if bad_args.is_empty() {
+        tcx.def_span(impl_m.def_id).into()
+    } else {
+        bad_args.iter().map(|(span, _)| *span).collect::<Vec<_>>().into()
+    };
+    tcx.struct_span_lint_hir(
+        rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
+        hir_id,
+        span,
+        "impl method assumes more implied bounds than the corresponding trait method",
+        |lint| {
+            let bad_args: Vec<_> =
+                bad_args.into_iter().filter_map(|(span, sugg)| Some((span, sugg?))).collect();
+            if !bad_args.is_empty() {
+                lint.multipart_suggestion(
+                    format!(
+                        "replace {} type{} to make the impl signature compatible",
+                        pluralize!("this", bad_args.len()),
+                        pluralize!(bad_args.len())
+                    ),
+                    bad_args,
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            lint
+        },
+    );
+}
+
 #[derive(Debug, PartialEq, Eq)]
 enum CheckImpliedWfMode {
     /// Checks implied well-formedness of the impl method. If it fails, we will
@@ -480,7 +618,8 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
 ) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
     let impl_m = tcx.opt_associated_item(def_id).unwrap();
     let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
-    let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
+    let impl_trait_ref =
+        tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().subst_identity();
     let param_env = tcx.param_env(def_id);
 
     // First, check a few of the same things as `compare_impl_method`,
@@ -1548,7 +1687,8 @@ pub(super) fn compare_impl_const_raw(
 ) -> Result<(), ErrorGuaranteed> {
     let impl_const_item = tcx.associated_item(impl_const_item_def);
     let trait_const_item = tcx.associated_item(trait_const_item_def);
-    let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap();
+    let impl_trait_ref =
+        tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().subst_identity();
     debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
 
     let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
@@ -1690,8 +1830,7 @@ fn compare_type_predicate_entailment<'tcx>(
     check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
 
     let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs);
-
-    if impl_ty_own_bounds.is_empty() {
+    if impl_ty_own_bounds.len() == 0 {
         // Nothing to check.
         return Ok(());
     }
@@ -1706,9 +1845,11 @@ fn compare_type_predicate_entailment<'tcx>(
     // associated type in the trait are assumed.
     let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap());
     let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
-    hybrid_preds
-        .predicates
-        .extend(trait_ty_predicates.instantiate_own(tcx, trait_to_impl_substs).predicates);
+    hybrid_preds.predicates.extend(
+        trait_ty_predicates
+            .instantiate_own(tcx, trait_to_impl_substs)
+            .map(|(predicate, _)| predicate),
+    );
 
     debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
 
@@ -1724,9 +1865,7 @@ fn compare_type_predicate_entailment<'tcx>(
 
     debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
 
-    assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
-    for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
-    {
+    for (predicate, span) in impl_ty_own_bounds {
         let cause = ObligationCause::misc(span, impl_ty_hir_id);
         let predicate = ocx.normalize(&cause, param_env, predicate);
 
index 92fd4625ee83574dbe515e06928cfe2373b5878a..49dd1eb22f7fe16ebd9d97ba5b4aef83d3da612e 100644 (file)
@@ -32,7 +32,6 @@
 };
 
 use std::cell::LazyCell;
-use std::iter;
 use std::ops::{ControlFlow, Deref};
 
 pub(super) struct WfCheckingCtxt<'a, 'tcx> {
@@ -182,7 +181,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
         hir::ItemKind::Impl(ref impl_) => {
             let is_auto = tcx
                 .impl_trait_ref(def_id)
-                .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
+                .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id));
             if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
                 let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
                 let mut err =
@@ -1253,7 +1252,7 @@ fn check_impl<'tcx>(
                 // `#[rustc_reservation_impl]` impls are not real impls and
                 // therefore don't need to be WF (the trait's `Self: Trait` predicate
                 // won't hold).
-                let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap();
+                let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap().subst_identity();
                 let trait_ref = wfcx.normalize(
                     ast_trait_ref.path.span,
                     Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
@@ -1310,7 +1309,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
     let infcx = wfcx.infcx;
     let tcx = wfcx.tcx();
 
-    let predicates = tcx.bound_predicates_of(def_id.to_def_id());
+    let predicates = tcx.predicates_of(def_id.to_def_id());
     let generics = tcx.generics_of(def_id);
 
     let is_our_default = |def: &ty::GenericParamDef| match def.kind {
@@ -1350,7 +1349,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
                     // is incorrect when dealing with unused substs, for example
                     // for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
                     // we should eagerly error.
-                    let default_ct = tcx.const_param_default(param.def_id);
+                    let default_ct = tcx.const_param_default(param.def_id).subst_identity();
                     if !default_ct.needs_subst() {
                         wfcx.register_wf_obligation(
                             tcx.def_span(param.def_id),
@@ -1396,7 +1395,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
             GenericParamDefKind::Const { .. } => {
                 // If the param has a default, ...
                 if is_our_default(param) {
-                    let default_ct = tcx.const_param_default(param.def_id);
+                    let default_ct = tcx.const_param_default(param.def_id).subst_identity();
                     // ... and it's not a dependent default, ...
                     if !default_ct.needs_subst() {
                         // ... then substitute it with the default.
@@ -1411,7 +1410,6 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
 
     // Now we build the substituted predicates.
     let default_obligations = predicates
-        .0
         .predicates
         .iter()
         .flat_map(|&(pred, sp)| {
@@ -1442,13 +1440,13 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
             let mut param_count = CountParams::default();
             let has_region = pred.visit_with(&mut param_count).is_break();
-            let substituted_pred = predicates.rebind(pred).subst(tcx, substs);
+            let substituted_pred = ty::EarlyBinder(pred).subst(tcx, substs);
             // Don't check non-defaulted params, dependent defaults (including lifetimes)
             // or preds with multiple params.
             if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region
             {
                 None
-            } else if predicates.0.predicates.iter().any(|&(p, _)| p == substituted_pred) {
+            } else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) {
                 // Avoid duplication of predicates that contain no parameters, for example.
                 None
             } else {
@@ -1474,22 +1472,21 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             traits::Obligation::new(tcx, cause, wfcx.param_env, pred)
         });
 
-    let predicates = predicates.0.instantiate_identity(tcx);
+    let predicates = predicates.instantiate_identity(tcx);
 
     let predicates = wfcx.normalize(span, None, predicates);
 
     debug!(?predicates.predicates);
     assert_eq!(predicates.predicates.len(), predicates.spans.len());
-    let wf_obligations =
-        iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| {
-            traits::wf::predicate_obligations(
-                infcx,
-                wfcx.param_env.without_const(),
-                wfcx.body_id,
-                p,
-                sp,
-            )
-        });
+    let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| {
+        traits::wf::predicate_obligations(
+            infcx,
+            wfcx.param_env.without_const(),
+            wfcx.body_id,
+            p,
+            sp,
+        )
+    });
 
     let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect();
     wfcx.register_obligations(obligations);
index 2e2c1591e9b4472dffb5e39a22b33b92685fbbc7..5bdd18fcd637c7eb9b214e588f5a5e053081832d 100644 (file)
@@ -192,7 +192,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
     let source = tcx.type_of(impl_did);
     assert!(!source.has_escaping_bound_vars());
     let target = {
-        let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+        let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
         assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
 
         trait_ref.substs.type_at(1)
@@ -354,7 +354,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
     });
 
     let source = tcx.type_of(impl_did);
-    let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+    let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
     assert_eq!(trait_ref.def_id, coerce_unsized_trait);
     let target = trait_ref.substs.type_at(1);
     debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
index 1bf3768fead3619f9fb5781cb8f9314c21f6e256..2e9cd2fca01c139d366a0f1f43a06d1179c30f31 100644 (file)
@@ -128,7 +128,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) {
 
     let impls = tcx.hir().trait_impls(def_id);
     for &impl_def_id in impls {
-        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
 
         check_impl(tcx, impl_def_id, trait_ref);
         check_object_overlap(tcx, impl_def_id, trait_ref);
index e8b3f139623ed56ce750a81dc1a6765f0fc2fd62..0aadc9f311b033e4ec3983d86fd8b072c4b85f2b 100644 (file)
@@ -21,7 +21,7 @@ pub(crate) fn orphan_check_impl(
     tcx: TyCtxt<'_>,
     impl_def_id: LocalDefId,
 ) -> Result<(), ErrorGuaranteed> {
-    let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+    let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
     trait_ref.error_reported()?;
 
     let ret = do_orphan_check_impl(tcx, trait_ref, impl_def_id);
index 70cc15b2f8c543268f926a32ff79ea330acce294..a485768e37b832c551740a167bc64c20efb0df4a 100644 (file)
@@ -14,6 +14,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() };
 
     if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
+        let trait_ref = trait_ref.subst_identity();
         let trait_def = tcx.trait_def(trait_ref.def_id);
         let unsafe_attr =
             impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
index cd745ee8cab69929e714c78fa546108a30b8ca1e..35f47dfc1a5e289b038e15041e93ff421ddd5149 100644 (file)
@@ -1339,18 +1339,22 @@ fn suggest_impl_trait<'tcx>(
     None
 }
 
-fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
+fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'_>>> {
     let icx = ItemCtxt::new(tcx, def_id);
     let item = tcx.hir().expect_item(def_id.expect_local());
     match item.kind {
-        hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
-            let selfty = tcx.type_of(def_id);
-            icx.astconv().instantiate_mono_trait_ref(
-                ast_trait_ref,
-                selfty,
-                check_impl_constness(tcx, impl_.constness, ast_trait_ref),
-            )
-        }),
+        hir::ItemKind::Impl(ref impl_) => impl_
+            .of_trait
+            .as_ref()
+            .map(|ast_trait_ref| {
+                let selfty = tcx.type_of(def_id);
+                icx.astconv().instantiate_mono_trait_ref(
+                    ast_trait_ref,
+                    selfty,
+                    check_impl_constness(tcx, impl_.constness, ast_trait_ref),
+                )
+            })
+            .map(ty::EarlyBinder),
         _ => bug!(),
     }
 }
index 234253556845bf264283ec24fedcfbd8c7549a86..a7e6494c15adb4cf57198821423968c51c4b9c66 100644 (file)
@@ -87,7 +87,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
         Node::Item(item) => match item.kind {
             ItemKind::Impl(ref impl_) => {
                 if impl_.defaultness.is_default() {
-                    is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
+                    is_default_impl_trait =
+                        tcx.impl_trait_ref(def_id).map(|t| ty::Binder::dummy(t.subst_identity()));
                 }
                 &impl_.generics
             }
@@ -251,7 +252,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
     // for details.
     if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
         let self_ty = tcx.type_of(def_id);
-        let trait_ref = tcx.impl_trait_ref(def_id);
+        let trait_ref = tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::subst_identity);
         cgp::setup_constraining_predicates(
             tcx,
             &mut predicates,
index 136f6199911a0eeb9ba7ac07032bf630df2eef6a..4fe893442b9bd2987c0ed22233a1eb88a2fe5c9c 100644 (file)
@@ -85,7 +85,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
     }
     let impl_generics = tcx.generics_of(impl_def_id);
     let impl_predicates = tcx.predicates_of(impl_def_id);
-    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
+    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::subst_identity);
 
     let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
     cgp::identify_constrained_generic_params(
index 8b9034d9620e2c3debfefc0081b6f3fdcf4217c9..bcda26c4cc854156c2c7ed4fdfa75d8e1e95a2e7 100644 (file)
@@ -90,7 +90,7 @@ pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
 
 fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Option<Node> {
     let trait_ref = tcx.impl_trait_ref(impl1_def_id)?;
-    let trait_def = tcx.trait_def(trait_ref.def_id);
+    let trait_def = tcx.trait_def(trait_ref.skip_binder().def_id);
 
     let impl2_node = trait_def.ancestors(tcx, impl1_def_id.to_def_id()).ok()?.nth(1)?;
 
@@ -207,7 +207,7 @@ fn unconstrained_parent_impl_substs<'tcx>(
     let impl_generic_predicates = tcx.predicates_of(impl_def_id);
     let mut unconstrained_parameters = FxHashSet::default();
     let mut constrained_params = FxHashSet::default();
-    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
+    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::subst_identity);
 
     // Unfortunately the functions in `constrained_generic_parameters` don't do
     // what we want here. We want only a list of constrained parameters while
@@ -370,7 +370,7 @@ fn check_predicates<'tcx>(
     });
 
     // Include the well-formed predicates of the type parameters of the impl.
-    for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
+    for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity().substs {
         let infcx = &tcx.infer_ctxt().build();
         let obligations = wf::obligations(
             infcx,
index 8d417290407ed033049bbe2d48afb48b99d94c2a..b617821fbd6528bbf6feee0f9efb8ff867a34ae5 100644 (file)
@@ -375,14 +375,12 @@ fn confirm_builtin_call(
                 if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) {
                     let predicates = self.tcx.predicates_of(def_id);
                     let predicates = predicates.instantiate(self.tcx, subst);
-                    for (predicate, predicate_span) in
-                        predicates.predicates.iter().zip(&predicates.spans)
-                    {
+                    for (predicate, predicate_span) in predicates {
                         let obligation = Obligation::new(
                             self.tcx,
                             ObligationCause::dummy_with_span(callee_expr.span),
                             self.param_env,
-                            *predicate,
+                            predicate,
                         );
                         let result = self.evaluate_obligation(&obligation);
                         self.tcx
@@ -391,7 +389,7 @@ fn confirm_builtin_call(
                                 callee_expr.span,
                                 &format!("evaluate({:?}) = {:?}", predicate, result),
                             )
-                            .span_label(*predicate_span, "predicate")
+                            .span_label(predicate_span, "predicate")
                             .emit();
                     }
                 }
@@ -659,8 +657,7 @@ fn report_invalid_callee(
         };
 
         if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
-            if let Some((maybe_def, output_ty, _)) =
-                self.extract_callable_info(callee_expr, callee_ty)
+            if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty)
                 && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
             {
                 let descr = match maybe_def {
index 042a50f2fd42eb89906167fde85ed9b0e4eb1622..0a230fca107affea99ad03c0bd31a8316e59908c 100644 (file)
@@ -31,7 +31,9 @@
 use super::FnCtxt;
 
 use crate::type_error_struct;
-use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{
+    struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+};
 use rustc_hir as hir;
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::mir::Mutability;
@@ -270,6 +272,9 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                         }
                     ));
                 }
+
+                self.try_suggest_collection_to_bool(fcx, &mut err);
+
                 err.emit();
             }
             CastError::NeedViaInt => {
@@ -517,6 +522,9 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                 } else {
                     err.span_label(self.span, "invalid cast");
                 }
+
+                self.try_suggest_collection_to_bool(fcx, &mut err);
+
                 err.emit();
             }
             CastError::SizedUnsizedCast => {
@@ -1080,4 +1088,40 @@ fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
             },
         );
     }
+
+    /// Attempt to suggest using `.is_empty` when trying to cast from a
+    /// collection type to a boolean.
+    fn try_suggest_collection_to_bool(&self, fcx: &FnCtxt<'a, 'tcx>, err: &mut Diagnostic) {
+        if self.cast_ty.is_bool() {
+            let derefed = fcx
+                .autoderef(self.expr_span, self.expr_ty)
+                .silence_errors()
+                .find(|t| matches!(t.0.kind(), ty::Str | ty::Slice(..)));
+
+            if let Some((deref_ty, _)) = derefed {
+                // Give a note about what the expr derefs to.
+                if deref_ty != self.expr_ty.peel_refs() {
+                    err.span_note(
+                        self.expr_span,
+                        format!(
+                            "this expression `Deref`s to `{}` which implements `is_empty`",
+                            fcx.ty_to_string(deref_ty)
+                        ),
+                    );
+                }
+
+                // Create a multipart suggestion: add `!` and `.is_empty()` in
+                // place of the cast.
+                let suggestion = vec![
+                    (self.expr_span.shrink_to_lo(), "!".to_string()),
+                    (self.span.with_lo(self.expr_span.hi()), ".is_empty()".to_string()),
+                ];
+
+                err.multipart_suggestion_verbose(format!(
+                    "consider using the `is_empty` method on `{}` to determine if it contains anything",
+                    fcx.ty_to_string(self.expr_ty),
+                ),  suggestion, Applicability::MaybeIncorrect);
+            }
+        }
+    }
 }
index 6c128d0aa1a658ffa149a45c995d75d0c3b3c555..665dc8b6a2f2a4ed18091fb4952e550ca82ba30c 100644 (file)
@@ -85,6 +85,7 @@ pub fn emit_coerce_suggestions(
         self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
         self.check_for_range_as_method_call(err, expr, expr_ty, expected);
         self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
+        self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty);
     }
 
     /// Requires that the two types unify, and prints an error message if
@@ -1941,4 +1942,77 @@ fn check_for_binding_assigned_block_without_tail_expression(
             err.span_label(block.span, "this block is missing a tail expression");
         }
     }
+
+    fn check_wrong_return_type_due_to_generic_arg(
+        &self,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+        checked_ty: Ty<'tcx>,
+    ) {
+        let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { return; };
+        enum CallableKind {
+            Function,
+            Method,
+            Constructor,
+        }
+        let mut maybe_emit_help = |def_id: hir::def_id::DefId,
+                                   callable: rustc_span::symbol::Ident,
+                                   args: &[hir::Expr<'_>],
+                                   kind: CallableKind| {
+            let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap();
+            let fn_ty = self.tcx.bound_type_of(def_id).0;
+            if !fn_ty.is_fn() {
+                return;
+            }
+            let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder();
+            let Some(&arg) = fn_sig.inputs().get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) else { return; };
+            if matches!(arg.kind(), ty::Param(_))
+                && fn_sig.output().contains(arg)
+                && self.node_ty(args[arg_idx].hir_id) == checked_ty
+            {
+                let mut multi_span: MultiSpan = parent_expr.span.into();
+                multi_span.push_span_label(
+                    args[arg_idx].span,
+                    format!(
+                        "this argument influences the {} of `{}`",
+                        if matches!(kind, CallableKind::Constructor) {
+                            "type"
+                        } else {
+                            "return type"
+                        },
+                        callable
+                    ),
+                );
+                err.span_help(
+                    multi_span,
+                    format!(
+                        "the {} `{}` due to the type of the argument passed",
+                        match kind {
+                            CallableKind::Function => "return type of this call is",
+                            CallableKind::Method => "return type of this call is",
+                            CallableKind::Constructor => "type constructed contains",
+                        },
+                        checked_ty
+                    ),
+                );
+            }
+        };
+        match parent_expr.kind {
+            hir::ExprKind::Call(fun, args) => {
+                let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { return; };
+                let hir::def::Res::Def(kind, def_id) = path.res else { return; };
+                let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) {
+                    CallableKind::Constructor
+                } else {
+                    CallableKind::Function
+                };
+                maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind);
+            }
+            hir::ExprKind::MethodCall(method, _receiver, args, _span) => {
+                let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) else { return; };
+                maybe_emit_help(def_id, method.ident, args, CallableKind::Method)
+            }
+            _ => return,
+        }
+    }
 }
index 7774ffc9b9793ea8ac6a93a0e41b9ca196514a71..c8cda0dc90c6daf39095057859453ec164196609 100644 (file)
@@ -417,7 +417,7 @@ fn maybe_read_scrutinee<'t>(
                                 // Named constants have to be equated with the value
                                 // being matched, so that's a read of the value being matched.
                                 //
-                                // FIXME: We don't actually  reads for ZSTs.
+                                // FIXME: We don't actually reads for ZSTs.
                                 needs_to_be_read = true;
                             }
                             _ => {
index 8570715b41e59060d6ad2cbbb6e6aec20162c267..6ed8adb47425a80197d6a2453f54302953fbb376 100644 (file)
@@ -1224,9 +1224,7 @@ fn inferred_kind(
                     }
                     GenericParamDefKind::Const { has_default } => {
                         if !infer_args && has_default {
-                            tcx.bound_const_param_default(param.def_id)
-                                .subst(tcx, substs.unwrap())
-                                .into()
+                            tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
                         } else {
                             self.fcx.var_for_def(self.span, param)
                         }
index b9e13fd20092421554e9d9d3ce9899334f100d74..c9609e69439812477b27d84f3d037abe82167ea0 100644 (file)
@@ -2140,8 +2140,7 @@ fn label_fn_like(
                         // FIXME(compiler-errors): This could be problematic if something has two
                         // fn-like predicates with different args, but callable types really never
                         // do that, so it's OK.
-                        for (predicate, span) in
-                            std::iter::zip(instantiated.predicates, instantiated.spans)
+                        for (predicate, span) in instantiated
                         {
                             if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = predicate.kind().skip_binder()
                                 && pred.self_ty().peel_refs() == callee_ty
index 005bd164065d80f612a6075c2f886957796a6bef..76f33be7a389c5bb111778f7964e626aa29b1acf 100644 (file)
@@ -11,7 +11,6 @@
     Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
 };
 use rustc_hir_analysis::astconv::AstConv;
-use rustc_infer::infer;
 use rustc_infer::traits::{self, StatementAsExpression};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{
@@ -23,9 +22,9 @@
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{Span, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
 use rustc_trait_selection::traits::error_reporting::DefIdOrName;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
-use rustc_trait_selection::traits::NormalizeExt;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(crate) fn body_fn_sig(&self) -> Option<ty::FnSig<'tcx>> {
@@ -94,7 +93,7 @@ pub(crate) fn suggest_fn_call(
         found: Ty<'tcx>,
         can_satisfy: impl FnOnce(Ty<'tcx>) -> bool,
     ) -> bool {
-        let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(expr, found)
+        let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(found)
             else { return false; };
         if can_satisfy(output) {
             let (sugg_call, mut applicability) = match inputs.len() {
@@ -163,99 +162,9 @@ pub(crate) fn suggest_fn_call(
     /// because the callable type must also be well-formed to be called.
     pub(in super::super) fn extract_callable_info(
         &self,
-        expr: &Expr<'_>,
-        found: Ty<'tcx>,
+        ty: Ty<'tcx>,
     ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
-        // Autoderef is useful here because sometimes we box callables, etc.
-        let Some((def_id_or_name, output, inputs)) = self.autoderef(expr.span, found).silence_errors().find_map(|(found, _)| {
-            match *found.kind() {
-                ty::FnPtr(fn_sig) =>
-                    Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())),
-                ty::FnDef(def_id, _) => {
-                    let fn_sig = found.fn_sig(self.tcx);
-                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
-                }
-                ty::Closure(def_id, substs) => {
-                    let fn_sig = substs.as_closure().sig();
-                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..])))
-                }
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
-                    self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
-                        if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
-                        && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
-                        // args tuple will always be substs[1]
-                        && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
-                        {
-                            Some((
-                                DefIdOrName::DefId(def_id),
-                                pred.kind().rebind(proj.term.ty().unwrap()),
-                                pred.kind().rebind(args.as_slice()),
-                            ))
-                        } else {
-                            None
-                        }
-                    })
-                }
-                ty::Dynamic(data, _, ty::Dyn) => {
-                    data.iter().find_map(|pred| {
-                        if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
-                        && Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
-                        // for existential projection, substs are shifted over by 1
-                        && let ty::Tuple(args) = proj.substs.type_at(0).kind()
-                        {
-                            Some((
-                                DefIdOrName::Name("trait object"),
-                                pred.rebind(proj.term.ty().unwrap()),
-                                pred.rebind(args.as_slice()),
-                            ))
-                        } else {
-                            None
-                        }
-                    })
-                }
-                ty::Param(param) => {
-                    let def_id = self.tcx.generics_of(self.body_id.owner).type_param(&param, self.tcx).def_id;
-                    self.tcx.predicates_of(self.body_id.owner).predicates.iter().find_map(|(pred, _)| {
-                        if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
-                        && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
-                        && proj.projection_ty.self_ty() == found
-                        // args tuple will always be substs[1]
-                        && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
-                        {
-                            Some((
-                                DefIdOrName::DefId(def_id),
-                                pred.kind().rebind(proj.term.ty().unwrap()),
-                                pred.kind().rebind(args.as_slice()),
-                            ))
-                        } else {
-                            None
-                        }
-                    })
-                }
-                _ => None,
-            }
-        }) else { return None; };
-
-        let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output);
-        let inputs = inputs
-            .skip_binder()
-            .iter()
-            .map(|ty| {
-                self.replace_bound_vars_with_fresh_vars(
-                    expr.span,
-                    infer::FnCall,
-                    inputs.rebind(*ty),
-                )
-            })
-            .collect();
-
-        // We don't want to register any extra obligations, which should be
-        // implied by wf, but also because that would possibly result in
-        // erroneous errors later on.
-        let infer::InferOk { value: output, obligations: _ } =
-            self.at(&self.misc(expr.span), self.param_env).normalize(output);
-
-        if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
+        self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty)
     }
 
     pub fn suggest_two_fn_call(
@@ -267,9 +176,9 @@ pub fn suggest_two_fn_call(
         rhs_ty: Ty<'tcx>,
         can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool,
     ) -> bool {
-        let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_expr, lhs_ty)
+        let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty)
             else { return false; };
-        let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_expr, rhs_ty)
+        let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_ty)
             else { return false; };
 
         if can_satisfy(lhs_output_ty, rhs_output_ty) {
index 4a33a791e1b7f3b12db9c6e54ca541ab93b5c0fa..372ea30ebd08e4877df583a8672b7b94df1bf2ae 100644 (file)
@@ -19,7 +19,6 @@
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::traits;
 
-use std::iter;
 use std::ops::Deref;
 
 struct ConfirmContext<'a, 'tcx> {
@@ -101,7 +100,7 @@ fn confirm(
         let filler_substs = rcvr_substs
             .extend_to(self.tcx, pick.item.def_id, |def, _| self.tcx.mk_param_from_def(def));
         let illegal_sized_bound = self.predicates_require_illegal_sized_bound(
-            &self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs),
+            self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs),
         );
 
         // Unify the (adjusted) self type with what the method expects.
@@ -565,7 +564,7 @@ fn add_obligations(
 
     fn predicates_require_illegal_sized_bound(
         &self,
-        predicates: &ty::InstantiatedPredicates<'tcx>,
+        predicates: ty::InstantiatedPredicates<'tcx>,
     ) -> Option<Span> {
         let sized_def_id = self.tcx.lang_items().sized_trait()?;
 
@@ -575,10 +574,11 @@ fn predicates_require_illegal_sized_bound(
                 ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))
                     if trait_pred.def_id() == sized_def_id =>
                 {
-                    let span = iter::zip(&predicates.predicates, &predicates.spans)
+                    let span = predicates
+                        .iter()
                         .find_map(
                             |(p, span)| {
-                                if *p == obligation.predicate { Some(*span) } else { None }
+                                if p == obligation.predicate { Some(span) } else { None }
                             },
                         )
                         .unwrap_or(rustc_span::DUMMY_SP);
index dd827777df94e68c03c031b98af1594b06e72793..948a14604d4376929fe0b49c6a0d3ee347ee8701 100644 (file)
@@ -232,7 +232,7 @@ pub enum PickKind<'tcx> {
 pub enum Mode {
     // An expression of the form `receiver.method_name(...)`.
     // Autoderefs are performed on `receiver`, lookup is done based on the
-    // `self` argument  of the method, and static methods aren't considered.
+    // `self` argument of the method, and static methods aren't considered.
     MethodCall,
     // An expression of the form `Type::item` or `<T>::item`.
     // No autoderefs are performed, lookup is done based on the type each
@@ -1587,11 +1587,29 @@ fn consider_probe(
                         let o = self.resolve_vars_if_possible(o);
                         if !self.predicate_may_hold(&o) {
                             result = ProbeResult::NoMatch;
-                            possibly_unsatisfied_predicates.push((
-                                o.predicate,
-                                None,
-                                Some(o.cause),
-                            ));
+                            let parent_o = o.clone();
+                            let implied_obligations =
+                                traits::elaborate_obligations(self.tcx, vec![o]);
+                            for o in implied_obligations {
+                                let parent = if o == parent_o {
+                                    None
+                                } else {
+                                    if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id())
+                                        == self.tcx.lang_items().sized_trait()
+                                    {
+                                        // We don't care to talk about implicit `Sized` bounds.
+                                        continue;
+                                    }
+                                    Some(parent_o.predicate)
+                                };
+                                if !self.predicate_may_hold(&o) {
+                                    possibly_unsatisfied_predicates.push((
+                                        o.predicate,
+                                        parent,
+                                        Some(o.cause),
+                                    ));
+                                }
+                            }
                         }
                     }
                 }
index 8166eb8299041136a089eb92866cf4fea044dd0b..2e1fc4c38b542d5cae2f9e6b281fd652f8c409ec 100644 (file)
@@ -505,19 +505,21 @@ pub fn report_no_match_method_error(
                             }
                             _ => None,
                         };
-                        if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
-                            if let Some(g) = kind.generics() {
-                                let key = (
-                                    g.tail_span_for_predicate_suggestion(),
-                                    g.add_where_or_trailing_comma(),
-                                );
-                                type_params
-                                    .entry(key)
-                                    .or_insert_with(FxHashSet::default)
-                                    .insert(obligation.to_owned());
-                            }
+                        if let Some(hir::Node::Item(hir::Item { kind, .. })) = node
+                            && let Some(g) = kind.generics()
+                        {
+                            let key = (
+                                g.tail_span_for_predicate_suggestion(),
+                                g.add_where_or_trailing_comma(),
+                            );
+                            type_params
+                                .entry(key)
+                                .or_insert_with(FxHashSet::default)
+                                .insert(obligation.to_owned());
+                            return true;
                         }
                     }
+                    false
                 };
             let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
                 let msg = format!(
@@ -692,7 +694,20 @@ pub fn report_no_match_method_error(
                             "auto trait is invoked with no method error, but no error reported?",
                         );
                     }
-                    Some(_) => unreachable!(),
+                    Some(Node::Item(hir::Item {
+                        ident, kind: hir::ItemKind::Trait(..), ..
+                    })) => {
+                        skip_list.insert(p);
+                        let entry = spanned_predicates.entry(ident.span);
+                        let entry = entry.or_insert_with(|| {
+                            (FxHashSet::default(), FxHashSet::default(), Vec::new())
+                        });
+                        entry.0.insert(cause.span);
+                        entry.1.insert((ident.span, ""));
+                        entry.1.insert((cause.span, "unsatisfied trait bound introduced here"));
+                        entry.2.push(p);
+                    }
+                    Some(node) => unreachable!("encountered `{node:?}`"),
                     None => (),
                 }
             }
@@ -719,19 +734,39 @@ pub fn report_no_match_method_error(
                 unsatisfied_bounds = true;
             }
 
+            let mut suggested_bounds = FxHashSet::default();
             // The requirements that didn't have an `impl` span to show.
             let mut bound_list = unsatisfied_predicates
                 .iter()
                 .filter_map(|(pred, parent_pred, _cause)| {
+                    let mut suggested = false;
                     format_pred(*pred).map(|(p, self_ty)| {
-                        collect_type_param_suggestions(self_ty, *pred, &p);
+                        if let Some(parent) = parent_pred && suggested_bounds.contains(parent) {
+                            // We don't suggest `PartialEq` when we already suggest `Eq`.
+                        } else if !suggested_bounds.contains(pred) {
+                            if collect_type_param_suggestions(self_ty, *pred, &p) {
+                                suggested = true;
+                                suggested_bounds.insert(pred);
+                            }
+                        }
                         (
                             match parent_pred {
                                 None => format!("`{}`", &p),
                                 Some(parent_pred) => match format_pred(*parent_pred) {
                                     None => format!("`{}`", &p),
                                     Some((parent_p, _)) => {
-                                        collect_type_param_suggestions(self_ty, *parent_pred, &p);
+                                        if !suggested
+                                            && !suggested_bounds.contains(pred)
+                                            && !suggested_bounds.contains(parent_pred)
+                                        {
+                                            if collect_type_param_suggestions(
+                                                self_ty,
+                                                *parent_pred,
+                                                &p,
+                                            ) {
+                                                suggested_bounds.insert(pred);
+                                            }
+                                        }
                                         format!("`{}`\nwhich is required by `{}`", p, parent_p)
                                     }
                                 },
@@ -1037,7 +1072,7 @@ fn note_candidates_on_method_error(
                     // the impl, if local to crate (item may be defaulted), else nothing.
                     let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
                         let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
-                        self.associated_value(impl_trait_ref.def_id, item_name)
+                        self.associated_value(impl_trait_ref.skip_binder().def_id, item_name)
                     }) else {
                         continue;
                     };
@@ -1055,7 +1090,10 @@ fn note_candidates_on_method_error(
                     let insertion = match self.tcx.impl_trait_ref(impl_did) {
                         None => String::new(),
                         Some(trait_ref) => {
-                            format!(" of the trait `{}`", self.tcx.def_path_str(trait_ref.def_id))
+                            format!(
+                                " of the trait `{}`",
+                                self.tcx.def_path_str(trait_ref.skip_binder().def_id)
+                            )
                         }
                     };
 
@@ -1086,7 +1124,7 @@ fn note_candidates_on_method_error(
                     }
                     if let Some(sugg_span) = sugg_span
                         && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
-                        let path = self.tcx.def_path_str(trait_ref.def_id);
+                        let path = self.tcx.def_path_str(trait_ref.skip_binder().def_id);
 
                         let ty = match item.kind {
                             ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
@@ -2581,7 +2619,7 @@ enum Introducer {
                             self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative
                         })
                         .any(|imp_did| {
-                            let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
+                            let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
                             let imp_simp =
                                 simplify_type(self.tcx, imp.self_ty(), TreatParams::AsPlaceholder);
                             imp_simp.map_or(false, |s| s == simp_rcvr_ty)
@@ -2662,8 +2700,10 @@ pub(crate) fn suggest_else_fn_with_closure(
         found: Ty<'tcx>,
         expected: Ty<'tcx>,
     ) -> bool {
-        let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(expr, found)
-        else { return false; };
+        let Some((_def_id_or_name, output, _inputs)) =
+            self.extract_callable_info(found) else {
+                return false;
+        };
 
         if !self.can_coerce(output, expected) {
             return false;
index 7fbe49ce92233b2d935719cbabe61f7593380328..9c38eb6163f5627043746c3ead3953d998efe121 100644 (file)
@@ -1923,6 +1923,22 @@ fn escape_literal(s: &str) -> String {
                         (ty::Tuple(fields), _) => {
                             self.emit_tuple_wrap_err(&mut err, span, found, fields)
                         }
+                        // If a byte was expected and the found expression is a char literal
+                        // containing a single ASCII character, perhaps the user meant to write `b'c'` to
+                        // specify a byte literal
+                        (ty::Uint(ty::UintTy::U8), ty::Char) => {
+                            if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
+                                && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
+                                && code.chars().next().map_or(false, |c| c.is_ascii())
+                            {
+                                err.span_suggestion(
+                                    span,
+                                    "if you meant to write a byte literal, prefix with `b`",
+                                    format!("b'{}'", escape_literal(code)),
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                        }
                         // If a character was expected and the found expression is a string literal
                         // containing a single character, perhaps the user meant to write `'c'` to
                         // specify a character literal (issue #92479)
index 7504ed094a3d4160715436ac3981b6f1729e45e3..b18cbd404d47f8c03895ef5db759d18f4f722077 100644 (file)
@@ -320,6 +320,7 @@ pub fn suggest_copy_trait_method_bounds(
             .impl_trait_ref(impl_def_id)
             else { return; };
         let trait_substs = trait_ref
+            .subst_identity()
             // Replace the explicit self type with `Self` for better suggestion rendering
             .with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
             .substs;
@@ -329,9 +330,8 @@ pub fn suggest_copy_trait_method_bounds(
 
         let Ok(trait_predicates) = self
             .tcx
-            .bound_explicit_predicates_of(trait_item_def_id)
-            .map_bound(|p| p.predicates)
-            .subst_iter_copied(self.tcx, trait_item_substs)
+            .explicit_predicates_of(trait_item_def_id)
+            .instantiate_own(self.tcx, trait_item_substs)
             .map(|(pred, _)| {
                 if pred.is_suggestable(self.tcx, false) {
                     Ok(pred.to_string())
index 6fedb0ed8ac53c2c841abb1c3b9d338592c96b95..fb448ec0222d8b3f8df6f97288cee776582b7e13 100644 (file)
@@ -1,7 +1,7 @@
 use smallvec::smallvec;
 
 use crate::infer::outlives::components::{push_outlives_components, Component};
-use crate::traits::{Obligation, ObligationCause, PredicateObligation};
+use crate::traits::{self, Obligation, ObligationCause, PredicateObligation};
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_middle::ty::{self, ToPredicate, TyCtxt};
 use rustc_span::symbol::Ident;
@@ -145,16 +145,28 @@ fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
                 // Get predicates declared on the trait.
                 let predicates = tcx.super_predicates_of(data.def_id());
 
-                let obligations = predicates.predicates.iter().map(|&(mut pred, _)| {
+                let obligations = predicates.predicates.iter().map(|&(mut pred, span)| {
                     // when parent predicate is non-const, elaborate it to non-const predicates.
                     if data.constness == ty::BoundConstness::NotConst {
                         pred = pred.without_const(tcx);
                     }
 
+                    let cause = obligation.cause.clone().derived_cause(
+                        bound_predicate.rebind(data),
+                        |derived| {
+                            traits::ImplDerivedObligation(Box::new(
+                                traits::ImplDerivedObligationCause {
+                                    derived,
+                                    impl_def_id: data.def_id(),
+                                    span,
+                                },
+                            ))
+                        },
+                    );
                     predicate_obligation(
                         pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
                         obligation.param_env,
-                        obligation.cause.clone(),
+                        cause,
                     )
                 });
                 debug!(?data, ?obligations, "super_predicates");
index e67dec31dcee377d3387929efe32c87cbcc44bdd..f817c5bc1cd73fd08a6440c0abf4df017a13bb53 100644 (file)
@@ -45,6 +45,7 @@ rustc_plugin_impl = { path = "../rustc_plugin_impl" }
 rustc_privacy = { path = "../rustc_privacy" }
 rustc_query_impl = { path = "../rustc_query_impl" }
 rustc_resolve = { path = "../rustc_resolve" }
+rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_ty_utils = { path = "../rustc_ty_utils" }
 
index f5135c78dc8313c32dfea0a77e564ece5f972c1f..15d7e977bbe881511d6c68a1798b5a70be164608 100644 (file)
@@ -87,3 +87,7 @@ pub struct FailedWritingFile<'a> {
     pub path: &'a Path,
     pub error: io::Error,
 }
+
+#[derive(Diagnostic)]
+#[diag(interface_proc_macro_crate_panic_abort)]
+pub struct ProcMacroCratePanicAbort;
index 2a6852d44eba7fd92f5ae8b2f496ae080d45f9da..50c40206d8026f66626a3ac07b9c1e0c117dbc3d 100644 (file)
@@ -1,7 +1,8 @@
 use crate::errors::{
     CantEmitMIR, EmojiIdentifier, ErrorWritingDependencies, FerrisIdentifier,
     GeneratedFileConflictsWithDirectory, InputFileWouldBeOverWritten, MixedBinCrate,
-    MixedProcMacroCrate, OutDirError, ProcMacroDocWithoutArg, TempsDirError,
+    MixedProcMacroCrate, OutDirError, ProcMacroCratePanicAbort, ProcMacroDocWithoutArg,
+    TempsDirError,
 };
 use crate::interface::{Compiler, Result};
 use crate::proc_macro_decls;
@@ -36,6 +37,7 @@
 use rustc_session::{Limit, Session};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::FileName;
+use rustc_target::spec::PanicStrategy;
 use rustc_trait_selection::traits;
 
 use std::any::Any;
@@ -380,6 +382,10 @@ pub fn configure_and_expand(
         }
     }
 
+    if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort {
+        sess.emit_warning(ProcMacroCratePanicAbort);
+    }
+
     // For backwards compatibility, we don't try to run proc macro injection
     // if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being
     // specified. This should only affect users who manually invoke 'rustdoc', as
index a3b9891ee64e90a5f6c7f323a2d172b6c2b6c403..07b28cc86cee1c95601f320e5ead863001913ab7 100644 (file)
@@ -748,6 +748,7 @@ macro_rules! tracked {
     tracked!(link_only, true);
     tracked!(llvm_plugins, vec![String::from("plugin_name")]);
     tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
+    tracked!(log_backtrace, Some("filter".to_string()));
     tracked!(maximal_hir_to_mir_coverage, true);
     tracked!(merge_functions, Some(MergeFunctions::Disabled));
     tracked!(mir_emit_retag, true);
index 5eb54cc0034279392c1eac3a4cdf8ad6b7d78b80..6cefaea2bc7da8af59508ff2cad32366ccce9d54 100644 (file)
@@ -187,9 +187,9 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
                         },
                         None => cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag),
                     }
-                } else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
+                } else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(ty) = is_ty_or_ty_ctxt(cx, &path) {
                     cx.emit_spanned_lint(USAGE_OF_QUALIFIED_TY, path.span, TyQualified {
-                        ty: t.clone(),
+                        ty,
                         suggestion: path.span,
                     });
                 }
index 57482a9edba880761fd97b38a0b4dc567aba419d..392e13f2fa94165d802ac24c0913934dd5d43d1b 100644 (file)
@@ -32,7 +32,7 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
                     cx.emit_spanned_lint(
                         PASS_BY_VALUE,
                         ty.span,
-                        PassByValueDiag { ty: t.clone(), suggestion: ty.span },
+                        PassByValueDiag { ty: t, suggestion: ty.span },
                     );
                 }
             }
index ac2b32b44e6a1d42e16ab70e7f41872df229b829..36791915964df75565cc6d3a1670fdc01b1e7f95 100644 (file)
@@ -1095,14 +1095,19 @@ fn check_unused_delims_expr(
                 //      ```
                 // - the block has no attribute and was not created inside a macro
                 // - if the block is an `anon_const`, the inner expr must be a literal
-                //      (do not lint `struct A<const N: usize>; let _: A<{ 2 + 3 }>;`)
-                //
+                //   not created by a macro, i.e. do not lint on:
+                //      ```
+                //      struct A<const N: usize>;
+                //      let _: A<{ 2 + 3 }>;
+                //      let _: A<{produces_literal!()}>;
+                //      ```
                 // FIXME(const_generics): handle paths when #67075 is fixed.
                 if let [stmt] = inner.stmts.as_slice() {
                     if let ast::StmtKind::Expr(ref expr) = stmt.kind {
                         if !Self::is_expr_delims_necessary(expr, followed_by_block, false)
                             && (ctx != UnusedDelimsCtx::AnonConst
-                                || matches!(expr.kind, ast::ExprKind::Lit(_)))
+                                || (matches!(expr.kind, ast::ExprKind::Lit(_))
+                                    && !expr.span.from_expansion()))
                             && !cx.sess().source_map().is_multiline(value.span)
                             && value.attrs.is_empty()
                             && !value.span.from_expansion()
index 28317d6cea02a599a0a0cddf1a164911eba33332..6cdf50970836a99ab5a7c73033a5d68ff202c0bd 100644 (file)
     ///
     /// This can be used to implement an unsound API if used incorrectly.
     pub IMPLIED_BOUNDS_ENTAILMENT,
-    Warn,
+    Deny,
     "impl method assumes more implied bounds than its corresponding trait method",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #105572 <https://github.com/rust-lang/rust/issues/105572>",
-        reason: FutureIncompatibilityReason::FutureReleaseError,
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
index 3c50827c1abc33abba077405029d7a91aaa61e2c..7f955b0a75090ee7234784612bdd1a316a80f47b 100644 (file)
@@ -7,6 +7,7 @@ edition = "2021"
 tracing = "0.1.28"
 tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
 tracing-tree = "0.2.0"
+tracing-core = "0.1.28"
 
 [dev-dependencies]
 rustc_span = { path = "../rustc_span" }
index 4cac88aff640e66dff6b89b5ac1feaca2f95bec7..fc1cabd2de95134ab892f7e9f06b8b09d90e2fa2 100644 (file)
 use std::env::{self, VarError};
 use std::fmt::{self, Display};
 use std::io::{self, IsTerminal};
+use tracing_core::{Event, Subscriber};
 use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
+use tracing_subscriber::fmt::{
+    format::{self, FormatEvent, FormatFields},
+    FmtContext,
+};
 use tracing_subscriber::layer::SubscriberExt;
 
 pub fn init_rustc_env_logger() -> Result<(), Error> {
-    init_env_logger("RUSTC_LOG")
+    init_rustc_env_logger_with_backtrace_option(&None)
+}
+
+pub fn init_rustc_env_logger_with_backtrace_option(
+    backtrace_target: &Option<String>,
+) -> Result<(), Error> {
+    init_env_logger_with_backtrace_option("RUSTC_LOG", backtrace_target)
 }
 
 /// In contrast to `init_rustc_env_logger` this allows you to choose an env var
 /// other than `RUSTC_LOG`.
 pub fn init_env_logger(env: &str) -> Result<(), Error> {
+    init_env_logger_with_backtrace_option(env, &None)
+}
+
+pub fn init_env_logger_with_backtrace_option(
+    env: &str,
+    backtrace_target: &Option<String>,
+) -> Result<(), Error> {
     let filter = match env::var(env) {
         Ok(env) => EnvFilter::new(env),
         _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)),
@@ -88,11 +106,47 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> {
     let layer = layer.with_thread_ids(true).with_thread_names(true);
 
     let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
-    tracing::subscriber::set_global_default(subscriber).unwrap();
+    match backtrace_target {
+        Some(str) => {
+            let fmt_layer = tracing_subscriber::fmt::layer()
+                .with_writer(io::stderr)
+                .without_time()
+                .event_format(BacktraceFormatter { backtrace_target: str.to_string() });
+            let subscriber = subscriber.with(fmt_layer);
+            tracing::subscriber::set_global_default(subscriber).unwrap();
+        }
+        None => {
+            tracing::subscriber::set_global_default(subscriber).unwrap();
+        }
+    };
 
     Ok(())
 }
 
+struct BacktraceFormatter {
+    backtrace_target: String,
+}
+
+impl<S, N> FormatEvent<S, N> for BacktraceFormatter
+where
+    S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,
+    N: for<'a> FormatFields<'a> + 'static,
+{
+    fn format_event(
+        &self,
+        _ctx: &FmtContext<'_, S, N>,
+        mut writer: format::Writer<'_>,
+        event: &Event<'_>,
+    ) -> fmt::Result {
+        let target = event.metadata().target();
+        if !target.contains(&self.backtrace_target) {
+            return Ok(());
+        }
+        let backtrace = std::backtrace::Backtrace::capture();
+        writeln!(writer, "stack backtrace: \n{:?}", backtrace)
+    }
+}
+
 pub fn stdout_isatty() -> bool {
     io::stdout().is_terminal()
 }
index 030328d1e26ff1f6b64feb983aba60d89a25eb50..a8000aa3c8a831562cd1543c91d33033b285abb5 100644 (file)
@@ -1555,7 +1555,7 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
                 self.tables.impl_defaultness.set(def_id.index, *defaultness);
                 self.tables.constness.set(def_id.index, *constness);
 
-                let trait_ref = self.tcx.impl_trait_ref(def_id);
+                let trait_ref = self.tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::skip_binder);
                 if let Some(trait_ref) = trait_ref {
                     let trait_def = self.tcx.trait_def(trait_ref.def_id);
                     if let Ok(mut an) = trait_def.ancestors(self.tcx, def_id) {
@@ -1899,6 +1899,8 @@ fn encode_impls(&mut self) -> LazyArray<TraitImpls> {
         for id in tcx.hir().items() {
             if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
                 if let Some(trait_ref) = tcx.impl_trait_ref(id.owner_id) {
+                    let trait_ref = trait_ref.subst_identity();
+
                     let simplified_self_ty = fast_reject::simplify_type(
                         self.tcx,
                         trait_ref.self_ty(),
index bf9be714daf7e940b09c29bdc1819efee06106a6..5b7b096b4edf1a903beb400bb27b6e2de463d515 100644 (file)
@@ -359,8 +359,8 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
     fn_sig: Table<DefIndex, LazyValue<ty::PolyFnSig<'static>>>,
     codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>,
-    impl_trait_ref: Table<DefIndex, LazyValue<ty::TraitRef<'static>>>,
-    const_param_default: Table<DefIndex, LazyValue<rustc_middle::ty::Const<'static>>>,
+    impl_trait_ref: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::TraitRef<'static>>>>,
+    const_param_default: Table<DefIndex, LazyValue<ty::EarlyBinder<rustc_middle::ty::Const<'static>>>>,
     object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
     optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
     mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
index a633201e3d9ae82091808f6684ebee834eb5434a..f567eaf967724909a88df86872a878956d2c2ff3 100644 (file)
@@ -102,6 +102,7 @@ pub fn parent_module(self, id: HirId) -> LocalDefId {
 
     pub fn impl_subject(self, def_id: DefId) -> ImplSubject<'tcx> {
         self.impl_trait_ref(def_id)
+            .map(|t| t.subst_identity())
             .map(ImplSubject::Trait)
             .unwrap_or_else(|| ImplSubject::Inherent(self.type_of(def_id)))
     }
index 8665591573695657dc3941e61f092529869f3327..b3acf815e0c10e931045db237c919ce7191d1acd 100644 (file)
 
     /// Given the def_id of a const-generic parameter, computes the associated default const
     /// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
-    query const_param_default(param: DefId) -> ty::Const<'tcx> {
+    query const_param_default(param: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
         desc { |tcx| "computing const default for a given parameter `{}`", tcx.def_path_str(param)  }
         cache_on_disk_if { param.is_local() }
         separate_provide_extern
 
     /// Given an `impl_id`, return the trait it implements.
     /// Return `None` if this is an inherent impl.
-    query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
+    query impl_trait_ref(impl_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> {
         desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
         cache_on_disk_if { impl_id.is_local() }
         separate_provide_extern
index 152a7e9d43fa4e32e7c6754efb5397cdc782beeb..65cbac3e8f1cd5f341e7a0054a03be00c6c1bc81 100644 (file)
@@ -239,7 +239,7 @@ pub fn is_ct_infer(self) -> bool {
     }
 }
 
-pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> Const<'_> {
+pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Const<'_>> {
     let default_def_id = match tcx.hir().get_by_def_id(def_id.expect_local()) {
         hir::Node::GenericParam(hir::GenericParam {
             kind: hir::GenericParamKind::Const { default: Some(ac), .. },
@@ -250,5 +250,5 @@ pub fn const_param_default(tcx: TyCtxt<'_>, def_id: DefId) -> Const<'_> {
             "`const_param_default` expected a generic parameter with a constant"
         ),
     };
-    Const::from_anon_const(tcx, default_def_id)
+    ty::EarlyBinder(Const::from_anon_const(tcx, default_def_id))
 }
index 8c22df7395f1052669ad14f2e36cc7e187bf4b23..771b63f59c124c5851c9fb6d747d43fd3ee6d35b 100644 (file)
@@ -17,7 +17,7 @@
 
 impl<'tcx> IntoDiagnosticArg for Ty<'tcx> {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
-        format!("{}", self).into_diagnostic_arg()
+        self.to_string().into_diagnostic_arg()
     }
 }
 
index 705adecd3b90f517b9d9c5ed814fdcbaecf4c111..801ca6004456827daba7eaf84db464e153ac1387 100644 (file)
@@ -88,7 +88,7 @@ pub fn default_value<'tcx>(
                 Some(tcx.bound_type_of(self.def_id).map_bound(|t| t.into()))
             }
             GenericParamDefKind::Const { has_default } if has_default => {
-                Some(tcx.bound_const_param_default(self.def_id).map_bound(|c| c.into()))
+                Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
             }
             _ => None,
         }
@@ -341,15 +341,9 @@ pub fn instantiate_own(
         &self,
         tcx: TyCtxt<'tcx>,
         substs: SubstsRef<'tcx>,
-    ) -> InstantiatedPredicates<'tcx> {
-        InstantiatedPredicates {
-            predicates: self
-                .predicates
-                .iter()
-                .map(|(p, _)| EarlyBinder(*p).subst(tcx, substs))
-                .collect(),
-            spans: self.predicates.iter().map(|(_, sp)| *sp).collect(),
-        }
+    ) -> impl Iterator<Item = (Predicate<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator
+    {
+        EarlyBinder(self.predicates).subst_iter_copied(tcx, substs)
     }
 
     #[instrument(level = "debug", skip(self, tcx))]
index 993e95b351484a7d31cb40dfc13a1d7414175633..bf8f45c50a3c951693a1ec418e25b117a85388ec 100644 (file)
@@ -1252,6 +1252,35 @@ pub fn empty() -> InstantiatedPredicates<'tcx> {
     pub fn is_empty(&self) -> bool {
         self.predicates.is_empty()
     }
+
+    pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter {
+        (&self).into_iter()
+    }
+}
+
+impl<'tcx> IntoIterator for InstantiatedPredicates<'tcx> {
+    type Item = (Predicate<'tcx>, Span);
+
+    type IntoIter = std::iter::Zip<std::vec::IntoIter<Predicate<'tcx>>, std::vec::IntoIter<Span>>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        debug_assert_eq!(self.predicates.len(), self.spans.len());
+        std::iter::zip(self.predicates, self.spans)
+    }
+}
+
+impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> {
+    type Item = (Predicate<'tcx>, Span);
+
+    type IntoIter = std::iter::Zip<
+        std::iter::Copied<std::slice::Iter<'a, Predicate<'tcx>>>,
+        std::iter::Copied<std::slice::Iter<'a, Span>>,
+    >;
+
+    fn into_iter(self) -> Self::IntoIter {
+        debug_assert_eq!(self.predicates.len(), self.spans.len());
+        std::iter::zip(self.predicates.iter().copied(), self.spans.iter().copied())
+    }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable, Lift)]
@@ -2187,8 +2216,10 @@ pub fn impls_are_allowed_to_overlap(
     ) -> Option<ImplOverlapKind> {
         // If either trait impl references an error, they're allowed to overlap,
         // as one of them essentially doesn't exist.
-        if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.references_error())
-            || self.impl_trait_ref(def_id2).map_or(false, |tr| tr.references_error())
+        if self.impl_trait_ref(def_id1).map_or(false, |tr| tr.subst_identity().references_error())
+            || self
+                .impl_trait_ref(def_id2)
+                .map_or(false, |tr| tr.subst_identity().references_error())
         {
             return Some(ImplOverlapKind::Permitted { marker: false });
         }
@@ -2218,7 +2249,7 @@ pub fn impls_are_allowed_to_overlap(
         let is_marker_overlap = {
             let is_marker_impl = |def_id: DefId| -> bool {
                 let trait_ref = self.impl_trait_ref(def_id);
-                trait_ref.map_or(false, |tr| self.trait_def(tr.def_id).is_marker)
+                trait_ref.map_or(false, |tr| self.trait_def(tr.skip_binder().def_id).is_marker)
             };
             is_marker_impl(def_id1) && is_marker_impl(def_id2)
         };
@@ -2364,7 +2395,7 @@ pub fn generator_layout(self, def_id: DefId) -> Option<&'tcx GeneratorLayout<'tc
     /// Given the `DefId` of an impl, returns the `DefId` of the trait it implements.
     /// If it implements no trait, returns `None`.
     pub fn trait_id_of_impl(self, def_id: DefId) -> Option<DefId> {
-        self.impl_trait_ref(def_id).map(|tr| tr.def_id)
+        self.impl_trait_ref(def_id).map(|tr| tr.skip_binder().def_id)
     }
 
     /// If the given `DefId` describes an item belonging to a trait,
index 72f451985796b82ac54a5809cf1f7dfd8dec9bd8..e32a7ee1c354569c7df399a82b524d88b1190151 100644 (file)
@@ -32,6 +32,10 @@ impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::Binder<'static, T> {
     type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>;
 }
 
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::EarlyBinder<T> {
+    type Value<'tcx> = ty::EarlyBinder<T::Value<'tcx>>;
+}
+
 #[macro_export]
 macro_rules! trivially_parameterized_over_tcx {
     ($($ty:ty),+ $(,)?) => {
index 29bad33e4bc0f36aa5ef8f955e1ec30da54ef19a..c302c461195aaf833b9b00e843efb17c5dd8272f 100644 (file)
@@ -116,7 +116,7 @@ fn default_print_def_path(
             DefPathData::Impl => {
                 let generics = self.tcx().generics_of(def_id);
                 let self_ty = self.tcx().bound_type_of(def_id);
-                let impl_trait_ref = self.tcx().bound_impl_trait_ref(def_id);
+                let impl_trait_ref = self.tcx().impl_trait_ref(def_id);
                 let (self_ty, impl_trait_ref) = if substs.len() >= generics.count() {
                     (
                         self_ty.subst(self.tcx(), substs),
index bd5b04d5b2baac92b05047c271e24954d8817df8..e49e7e86da08527ec87522011b79e84fd48314f1 100644 (file)
@@ -7,8 +7,8 @@
 use crate::ty::visit::ValidateBoundVars;
 use crate::ty::InferTy::*;
 use crate::ty::{
-    self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable,
-    TypeVisitor,
+    self, AdtDef, DefIdTree, Discr, FallibleTypeFolder, Term, Ty, TyCtxt, TypeFlags, TypeFoldable,
+    TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
 use crate::ty::{List, ParamEnv};
 use hir::def::DefKind;
@@ -1106,6 +1106,17 @@ pub fn no_bound_vars(self) -> Option<T>
         if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
     }
 
+    pub fn no_bound_vars_ignoring_escaping(self, tcx: TyCtxt<'tcx>) -> Option<T>
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        if !self.0.has_escaping_bound_vars() {
+            Some(self.skip_binder())
+        } else {
+            self.0.try_fold_with(&mut SkipBindersAt { index: ty::INNERMOST, tcx }).ok()
+        }
+    }
+
     /// Splits the contents into two things that share the same binder
     /// level as the original, returning two distinct binders.
     ///
@@ -1135,6 +1146,81 @@ pub fn iter(self) -> impl Iterator<Item = ty::Binder<'tcx, T::Item>> {
     }
 }
 
+struct SkipBindersAt<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    index: ty::DebruijnIndex,
+}
+
+impl<'tcx> FallibleTypeFolder<'tcx> for SkipBindersAt<'tcx> {
+    type Error = ();
+
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
+    where
+        T: ty::TypeFoldable<'tcx>,
+    {
+        self.index.shift_in(1);
+        let value = t.try_map_bound(|t| t.try_fold_with(self));
+        self.index.shift_out(1);
+        value
+    }
+
+    fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+        if !ty.has_escaping_bound_vars() {
+            Ok(ty)
+        } else if let ty::Bound(index, bv) = *ty.kind() {
+            if index == self.index {
+                Err(())
+            } else {
+                Ok(self.tcx().mk_ty(ty::Bound(index.shifted_out(1), bv)))
+            }
+        } else {
+            ty.try_super_fold_with(self)
+        }
+    }
+
+    fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+        if !r.has_escaping_bound_vars() {
+            Ok(r)
+        } else if let ty::ReLateBound(index, bv) = r.kind() {
+            if index == self.index {
+                Err(())
+            } else {
+                Ok(self.tcx().mk_region(ty::ReLateBound(index.shifted_out(1), bv)))
+            }
+        } else {
+            r.try_super_fold_with(self)
+        }
+    }
+
+    fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
+        if !ct.has_escaping_bound_vars() {
+            Ok(ct)
+        } else if let ty::ConstKind::Bound(index, bv) = ct.kind() {
+            if index == self.index {
+                Err(())
+            } else {
+                Ok(self.tcx().mk_const(
+                    ty::ConstKind::Bound(index.shifted_out(1), bv),
+                    ct.ty().try_fold_with(self)?,
+                ))
+            }
+        } else {
+            ct.try_super_fold_with(self)
+        }
+    }
+
+    fn try_fold_predicate(
+        &mut self,
+        p: ty::Predicate<'tcx>,
+    ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+        if !p.has_escaping_bound_vars() { Ok(p) } else { p.try_super_fold_with(self) }
+    }
+}
+
 /// Represents the projection of an associated type.
 ///
 /// For a projection, this would be `<Ty as Trait<...>>::N`.
index 2dec58ea82a30cbecb1c214e48a7047dd6a780e6..5f1f1b2c747ba2cf87f7855318c053abd954bb84 100644 (file)
@@ -7,6 +7,7 @@
 use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
 
 use rustc_data_structures::intern::Interned;
+use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
 use rustc_serialize::{self, Decodable, Encodable};
@@ -36,6 +37,12 @@ pub struct GenericArg<'tcx> {
     marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>,
 }
 
+impl<'tcx> IntoDiagnosticArg for GenericArg<'tcx> {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        self.to_string().into_diagnostic_arg()
+    }
+}
+
 const TAG_MASK: usize = 0b11;
 const TYPE_TAG: usize = 0b00;
 const REGION_TAG: usize = 0b01;
@@ -639,6 +646,13 @@ fn next_back(&mut self) -> Option<Self::Item> {
     }
 }
 
+impl<'tcx, I: IntoIterator> ExactSizeIterator for SubstIter<'_, 'tcx, I>
+where
+    I::IntoIter: ExactSizeIterator,
+    I::Item: TypeFoldable<'tcx>,
+{
+}
+
 impl<'tcx, 's, I: IntoIterator> EarlyBinder<I>
 where
     I::Item: Deref,
@@ -686,6 +700,14 @@ fn next_back(&mut self) -> Option<Self::Item> {
     }
 }
 
+impl<'tcx, I: IntoIterator> ExactSizeIterator for SubstIterCopied<'_, 'tcx, I>
+where
+    I::IntoIter: ExactSizeIterator,
+    I::Item: Deref,
+    <I::Item as Deref>::Target: Copy + TypeFoldable<'tcx>,
+{
+}
+
 pub struct EarlyBinderIter<T> {
     t: T,
 }
@@ -713,6 +735,10 @@ pub fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> T {
         let mut folder = SubstFolder { tcx, substs, binders_passed: 0 };
         self.0.fold_with(&mut folder)
     }
+
+    pub fn subst_identity(self) -> T {
+        self.0
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
index 028a03c0b2bdd78d525892e8c5923289af1149e6..b910bd888c0727cf562daaaf34d6c7aebeccf768 100644 (file)
@@ -193,7 +193,7 @@ pub struct TypeckResults<'tcx> {
     pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
 
     /// We sometimes treat byte string literals (which are of type `&[u8; N]`)
-    /// as `&[u8]`, depending on the pattern  in which they are used.
+    /// as `&[u8]`, depending on the pattern in which they are used.
     /// This hashset records all instances where we behave
     /// like this to allow `const_to_pat` to reliably handle this situation.
     pub treat_byte_string_as_slice: ItemLocalSet,
index cc53659f827986d7ff4b7a72163730bcb8a5f5eb..37d3e12a667637e2726e1934c10810d996349e0f 100644 (file)
@@ -652,13 +652,6 @@ pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>>
         ty::EarlyBinder(self.fn_sig(def_id))
     }
 
-    pub fn bound_impl_trait_ref(
-        self,
-        def_id: DefId,
-    ) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> {
-        self.impl_trait_ref(def_id).map(|i| ty::EarlyBinder(i))
-    }
-
     pub fn bound_explicit_item_bounds(
         self,
         def_id: DefId,
@@ -673,24 +666,6 @@ pub fn bound_item_bounds(
         ty::EarlyBinder(self.item_bounds(def_id))
     }
 
-    pub fn bound_const_param_default(self, def_id: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
-        ty::EarlyBinder(self.const_param_default(def_id))
-    }
-
-    pub fn bound_predicates_of(
-        self,
-        def_id: DefId,
-    ) -> ty::EarlyBinder<ty::generics::GenericPredicates<'tcx>> {
-        ty::EarlyBinder(self.predicates_of(def_id))
-    }
-
-    pub fn bound_explicit_predicates_of(
-        self,
-        def_id: DefId,
-    ) -> ty::EarlyBinder<ty::generics::GenericPredicates<'tcx>> {
-        ty::EarlyBinder(self.explicit_predicates_of(def_id))
-    }
-
     pub fn bound_impl_subject(self, def_id: DefId) -> ty::EarlyBinder<ty::ImplSubject<'tcx>> {
         ty::EarlyBinder(self.impl_subject(def_id))
     }
index c242be570312354d780529f5df3449d0e6d64ffe..34e8a559784e6f021d3abd53b12271a0d8b74658 100644 (file)
@@ -94,6 +94,18 @@ fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
     }
 }
 
+impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
+        ty::EarlyBinder(Ty::from_cycle_error(tcx, cycle))
+    }
+}
+
+impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
+        ty::EarlyBinder(ty::Binder::from_cycle_error(tcx, cycle))
+    }
+}
+
 // item_and_field_ids should form a cycle where each field contains the
 // type in the next element in the list
 pub fn recursive_type_error(
index 06523b0a1de84cb658fc3e410bb4d61837eeeec9..7f81aef1c73217d57f5013678b162a4bce27b82f 100644 (file)
@@ -770,6 +770,8 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
     #[subdiagnostic]
     pub let_suggestion: Option<SuggestLet>,
     #[subdiagnostic]
+    pub misc_suggestion: Option<MiscPatternSuggestion>,
+    #[subdiagnostic]
     pub res_defined_here: Option<ResDefinedHere>,
 }
 
@@ -848,3 +850,16 @@ pub enum SuggestLet {
         count: usize,
     },
 }
+
+#[derive(Subdiagnostic)]
+pub enum MiscPatternSuggestion {
+    #[suggestion(
+        mir_build_suggest_attempted_int_lit,
+        code = "_",
+        applicability = "maybe-incorrect"
+    )]
+    AttemptedIntegerLiteral {
+        #[primary_span]
+        start_span: Span,
+    },
+}
index e13c0662ef85f17cb45edb3bd2f7dd26820e7256..34e637f594842687aaec93b1075bacb16eb8df0b 100644 (file)
@@ -6,8 +6,9 @@
 
 use crate::errors::*;
 
+use hir::{ExprKind, PatKind};
 use rustc_arena::TypedArena;
-use rustc_ast::Mutability;
+use rustc_ast::{LitKind, Mutability};
 use rustc_errors::{
     struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
 };
@@ -389,7 +390,7 @@ fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>
             return;
         }
 
-        let (inform, interpreted_as_const, res_defined_here,let_suggestion) =
+        let (inform, interpreted_as_const, res_defined_here,let_suggestion, misc_suggestion) =
             if let hir::PatKind::Path(hir::QPath::Resolved(
                 None,
                 hir::Path {
@@ -413,6 +414,7 @@ fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>
                         }
                     },
                     None,
+                    None,
                 )
             } else if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) {
                 let mut bindings = vec![];
@@ -426,10 +428,19 @@ fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>
                 let end_span = semi_span.shrink_to_lo();
                 let count = witnesses.len();
 
+                // If the pattern to match is an integer literal:
+                let int_suggestion = if
+                    let PatKind::Lit(expr) = &pat.kind
+                    && bindings.is_empty()
+                    && let ExprKind::Lit(Spanned { node: LitKind::Int(_, _), span }) = expr.kind {
+                    // Then give a suggestion, the user might've meant to create a binding instead.
+                    Some(MiscPatternSuggestion::AttemptedIntegerLiteral { start_span: span.shrink_to_lo() })
+                } else { None };
+
                 let let_suggestion = if bindings.is_empty() {SuggestLet::If{start_span, semi_span, count}} else{ SuggestLet::Else{end_span, count }};
-                (sp.map(|_|Inform), None, None, Some(let_suggestion))
+                (sp.map(|_|Inform), None, None, Some(let_suggestion), int_suggestion)
             } else{
-                (sp.map(|_|Inform), None, None,  None)
+                (sp.map(|_|Inform), None, None,  None, None)
             };
 
         let adt_defined_here = try {
@@ -453,6 +464,7 @@ fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>
             _p: (),
             pattern_ty,
             let_suggestion,
+            misc_suggestion,
             res_defined_here,
             adt_defined_here,
         });
index 4219e6280ebbca481424a6b7ee3bbef6ed25d41c..28c9080d38d7d38720b83e5f27e48ac8916fc803 100644 (file)
@@ -542,6 +542,21 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
                     destination
                 };
 
+                // Always create a local to hold the destination, as `RETURN_PLACE` may appear
+                // where a full `Place` is not allowed.
+                let (remap_destination, destination_local) = if let Some(d) = dest.as_local() {
+                    (false, d)
+                } else {
+                    (
+                        true,
+                        self.new_call_temp(
+                            caller_body,
+                            &callsite,
+                            destination.ty(caller_body, self.tcx).ty,
+                        ),
+                    )
+                };
+
                 // Copy the arguments if needed.
                 let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body);
 
@@ -560,7 +575,7 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
                     new_locals: Local::new(caller_body.local_decls.len())..,
                     new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
                     new_blocks: BasicBlock::new(caller_body.basic_blocks.len())..,
-                    destination: dest,
+                    destination: destination_local,
                     callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
                     callsite,
                     cleanup_block: cleanup,
@@ -591,6 +606,16 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
                     // To avoid repeated O(n) insert, push any new statements to the end and rotate
                     // the slice once.
                     let mut n = 0;
+                    if remap_destination {
+                        caller_body[block].statements.push(Statement {
+                            source_info: callsite.source_info,
+                            kind: StatementKind::Assign(Box::new((
+                                dest,
+                                Rvalue::Use(Operand::Move(destination_local.into())),
+                            ))),
+                        });
+                        n += 1;
+                    }
                     for local in callee_body.vars_and_temps_iter().rev() {
                         if !callee_body.local_decls[local].internal
                             && integrator.always_live_locals.contains(local)
@@ -959,7 +984,7 @@ struct Integrator<'a, 'tcx> {
     new_locals: RangeFrom<Local>,
     new_scopes: RangeFrom<SourceScope>,
     new_blocks: RangeFrom<BasicBlock>,
-    destination: Place<'tcx>,
+    destination: Local,
     callsite_scope: SourceScopeData<'tcx>,
     callsite: &'a CallSite<'tcx>,
     cleanup_block: Option<BasicBlock>,
@@ -972,7 +997,7 @@ struct Integrator<'a, 'tcx> {
 impl Integrator<'_, '_> {
     fn map_local(&self, local: Local) -> Local {
         let new = if local == RETURN_PLACE {
-            self.destination.local
+            self.destination
         } else {
             let idx = local.index() - 1;
             if idx < self.args.len() {
@@ -1053,27 +1078,6 @@ fn visit_span(&mut self, span: &mut Span) {
         *span = span.fresh_expansion(self.expn_data);
     }
 
-    fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        for elem in place.projection {
-            // FIXME: Make sure that return place is not used in an indexing projection, since it
-            // won't be rebased as it is supposed to be.
-            assert_ne!(ProjectionElem::Index(RETURN_PLACE), elem);
-        }
-
-        // If this is the `RETURN_PLACE`, we need to rebase any projections onto it.
-        let dest_proj_len = self.destination.projection.len();
-        if place.local == RETURN_PLACE && dest_proj_len > 0 {
-            let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len());
-            projs.extend(self.destination.projection);
-            projs.extend(place.projection);
-
-            place.projection = self.tcx.intern_place_elems(&*projs);
-        }
-        // Handles integrating any locals that occur in the base
-        // or projections
-        self.super_place(place, context, location)
-    }
-
     fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
         self.in_cleanup_block = data.is_cleanup;
         self.super_basic_block_data(block, data);
index b573df4325051306236920cdbdc7f273e3a13395..ec1de3056872b027f8d8da8b3bb880ee49c67076 100644 (file)
@@ -1352,6 +1352,8 @@ fn create_mono_items_for_default_impls<'tcx>(
             );
 
             if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
+                let trait_ref = trait_ref.subst_identity();
+
                 let param_env = ty::ParamEnv::reveal_all();
                 let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
                 let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id);
index f027843e6b43d469ab5483494543ee9d89b42d98..9fe8d9836ba60ca8ecfb16eea7d0383617931c0e 100644 (file)
@@ -52,8 +52,15 @@ pub(crate) fn parse_token_trees<'a>(
     }
 
     let cursor = Cursor::new(src);
-    let string_reader =
-        StringReader { sess, start_pos, pos: start_pos, src, cursor, override_span };
+    let string_reader = StringReader {
+        sess,
+        start_pos,
+        pos: start_pos,
+        src,
+        cursor,
+        override_span,
+        nbsp_is_whitespace: false,
+    };
     tokentrees::TokenTreesReader::parse_all_token_trees(string_reader)
 }
 
@@ -68,6 +75,10 @@ struct StringReader<'a> {
     /// Cursor for getting lexer tokens.
     cursor: Cursor<'a>,
     override_span: Option<Span>,
+    /// When a "unknown start of token: \u{a0}" has already been emitted earlier
+    /// in this file, it's safe to treat further occurrences of the non-breaking
+    /// space character as whitespace.
+    nbsp_is_whitespace: bool,
 }
 
 impl<'a> StringReader<'a> {
@@ -79,7 +90,7 @@ fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span {
     /// preceded by whitespace.
     fn next_token(&mut self) -> (Token, bool) {
         let mut preceded_by_whitespace = false;
-
+        let mut swallow_next_invalid = 0;
         // Skip trivial (whitespace & comments) tokens
         loop {
             let token = self.cursor.advance_token();
@@ -232,19 +243,44 @@ fn next_token(&mut self) -> (Token, bool) {
                 rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
 
                 rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
-                    let c = self.str_from(start).chars().next().unwrap();
+                    // Don't emit diagnostics for sequences of the same invalid token
+                    if swallow_next_invalid > 0 {
+                        swallow_next_invalid -= 1;
+                        continue;
+                    }
+                    let mut it = self.str_from_to_end(start).chars();
+                    let c = it.next().unwrap();
+                    if c == '\u{00a0}' {
+                        // If an error has already been reported on non-breaking
+                        // space characters earlier in the file, treat all
+                        // subsequent occurrences as whitespace.
+                        if self.nbsp_is_whitespace {
+                            preceded_by_whitespace = true;
+                            continue;
+                        }
+                        self.nbsp_is_whitespace = true;
+                    }
+                    let repeats = it.take_while(|c1| *c1 == c).count();
                     let mut err =
-                        self.struct_err_span_char(start, self.pos, "unknown start of token", c);
+                        self.struct_err_span_char(start, self.pos + Pos::from_usize(repeats * c.len_utf8()), "unknown start of token", c);
                     // FIXME: the lexer could be used to turn the ASCII version of unicode
                     // homoglyphs, instead of keeping a table in `check_for_substitution`into the
                     // token. Ideally, this should be inside `rustc_lexer`. However, we should
                     // first remove compound tokens like `<<` from `rustc_lexer`, and then add
                     // fancier error recovery to it, as there will be less overall work to do this
                     // way.
-                    let token = unicode_chars::check_for_substitution(self, start, c, &mut err);
+                    let token = unicode_chars::check_for_substitution(self, start, c, &mut err, repeats+1);
                     if c == '\x00' {
                         err.help("source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used");
                     }
+                    if repeats > 0 {
+                        if repeats == 1 {
+                            err.note(format!("character appears once more"));
+                        } else {
+                            err.note(format!("character appears {repeats} more times"));
+                        }
+                        swallow_next_invalid = repeats;
+                    }
                     err.emit();
                     if let Some(token) = token {
                         token
@@ -471,7 +507,7 @@ fn src_index(&self, pos: BytePos) -> usize {
 
     /// Slice of the source text from `start` up to but excluding `self.pos`,
     /// meaning the slice does not include the character `self.ch`.
-    fn str_from(&self, start: BytePos) -> &str {
+    fn str_from(&self, start: BytePos) -> &'a str {
         self.str_from_to(start, self.pos)
     }
 
@@ -482,10 +518,15 @@ fn symbol_from_to(&self, start: BytePos, end: BytePos) -> Symbol {
     }
 
     /// Slice of the source text spanning from `start` up to but excluding `end`.
-    fn str_from_to(&self, start: BytePos, end: BytePos) -> &str {
+    fn str_from_to(&self, start: BytePos, end: BytePos) -> &'a str {
         &self.src[self.src_index(start)..self.src_index(end)]
     }
 
+    /// Slice of the source text spanning from `start` until the end
+    fn str_from_to_end(&self, start: BytePos) -> &'a str {
+        &self.src[self.src_index(start)..]
+    }
+
     fn report_raw_str_error(&self, start: BytePos, prefix_len: u32) -> ! {
         match rustc_lexer::validate_raw_str(self.str_from(start), prefix_len) {
             Err(RawStrError::InvalidStarter { bad_char }) => {
index f1b50296e2565a858e0442b88e192e1fdf12e7e2..65479b341d7a8f5c2687a97b3e4ecd768962ea34 100644 (file)
@@ -337,10 +337,11 @@ pub(super) fn check_for_substitution<'a>(
     pos: BytePos,
     ch: char,
     err: &mut Diagnostic,
+    count: usize,
 ) -> Option<token::TokenKind> {
     let &(_u_char, u_name, ascii_char) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch)?;
 
-    let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8()));
+    let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8() * count));
 
     let Some((_ascii_char, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(c, _, _)| c == ascii_char) else {
         let msg = format!("substitution character not found for '{}'", ch);
@@ -369,7 +370,12 @@ pub(super) fn check_for_substitution<'a>(
             "Unicode character '{}' ({}) looks like '{}' ({}), but it is not",
             ch, u_name, ascii_char, ascii_name
         );
-        err.span_suggestion(span, &msg, ascii_char, Applicability::MaybeIncorrect);
+        err.span_suggestion(
+            span,
+            &msg,
+            ascii_char.to_string().repeat(count),
+            Applicability::MaybeIncorrect,
+        );
     }
     token.clone()
 }
index dd2b03988c3e8089536b1412b2cbba1e50203a3b..d58afcd4c9fc43b906ee2249b980ea0dd66e092c 100644 (file)
@@ -83,7 +83,7 @@ macro_rules! maybe_whole_expr {
 pub(super) enum LhsExpr {
     NotYetParsed,
     AttributesParsed(AttrWrapper),
-    AlreadyParsed(P<Expr>, bool), // (expr, starts_statement)
+    AlreadyParsed { expr: P<Expr>, starts_statement: bool },
 }
 
 impl From<Option<AttrWrapper>> for LhsExpr {
@@ -97,11 +97,11 @@ fn from(o: Option<AttrWrapper>) -> Self {
 }
 
 impl From<P<Expr>> for LhsExpr {
-    /// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed(expr)`.
+    /// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed { expr, starts_statement: false }`.
     ///
     /// This conversion does not allocate.
     fn from(expr: P<Expr>) -> Self {
-        LhsExpr::AlreadyParsed(expr, false)
+        LhsExpr::AlreadyParsed { expr, starts_statement: false }
     }
 }
 
@@ -174,7 +174,7 @@ pub(super) fn parse_assoc_expr_with(
         lhs: LhsExpr,
     ) -> PResult<'a, P<Expr>> {
         let mut starts_stmt = false;
-        let mut lhs = if let LhsExpr::AlreadyParsed(expr, starts_statement) = lhs {
+        let mut lhs = if let LhsExpr::AlreadyParsed { expr, starts_statement } = lhs {
             starts_stmt = starts_statement;
             expr
         } else {
@@ -562,17 +562,23 @@ macro_rules! make_it {
 
         // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
         match this.token.uninterpolate().kind {
-            token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)), // `!expr`
-            token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)), // `~expr`
+            // `!expr`
+            token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)),
+            // `~expr`
+            token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)),
+            // `-expr`
             token::BinOp(token::Minus) => {
                 make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Neg))
-            } // `-expr`
+            }
+            // `*expr`
             token::BinOp(token::Star) => {
                 make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Deref))
-            } // `*expr`
+            }
+            // `&expr` and `&&expr`
             token::BinOp(token::And) | token::AndAnd => {
                 make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo))
             }
+            // `+lit`
             token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
                 let mut err =
                     LeadingPlusNotSupported { span: lo, remove_plus: None, add_parentheses: None };
@@ -587,7 +593,7 @@ macro_rules! make_it {
 
                 this.bump();
                 this.parse_prefix_expr(None)
-            } // `+expr`
+            }
             // Recover from `++x`:
             token::BinOp(token::Plus)
                 if this.look_ahead(1, |t| *t == token::BinOp(token::Plus)) =>
@@ -624,7 +630,7 @@ fn parse_unary_expr(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKin
         Ok((span, self.mk_unary(op, expr)))
     }
 
-    // Recover on `!` suggesting for bitwise negation instead.
+    /// Recover on `~expr` in favor of `!expr`.
     fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
         self.sess.emit_err(TildeAsUnaryOperator(lo));
 
@@ -651,7 +657,6 @@ fn is_mistaken_not_ident_negation(&self) -> bool {
 
     /// Recover on `not expr` in favor of `!expr`.
     fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
-        // Emit the error...
         let negated_token = self.look_ahead(1, |t| t.clone());
 
         let sub_diag = if negated_token.is_numeric_lit() {
@@ -672,7 +677,6 @@ fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
             ),
         });
 
-        // ...and recover!
         self.parse_unary_expr(lo, UnOp::Not)
     }
 
@@ -1471,9 +1475,8 @@ fn parse_array_or_repeat_expr(&mut self, close_delim: Delimiter) -> PResult<'a,
             } else if self.eat(&token::Comma) {
                 // Vector with two or more elements.
                 let sep = SeqSep::trailing_allowed(token::Comma);
-                let (remaining_exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
-                let mut exprs = vec![first_expr];
-                exprs.extend(remaining_exprs);
+                let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
+                exprs.insert(0, first_expr);
                 ExprKind::Array(exprs)
             } else {
                 // Vector with one element
@@ -1593,7 +1596,7 @@ fn visit_expr_post(&mut self, ex: &'ast Expr) {
                     vis.0
                 };
 
-                // Suggestion involves adding a (as of time of writing this, unstable) labeled block.
+                // Suggestion involves adding a labeled block.
                 //
                 // If there are no breaks that may use this label, suggest removing the label and
                 // recover to the unmodified expression.
index 0b057f2f577fe73e85489bf75063576cdf3c5d72..e73a17ced7deb2598f52a013189ee3392e379547 100644 (file)
@@ -469,7 +469,7 @@ fn recover_dotdotdot_rest_pat(&mut self, lo: Span) -> PatKind {
     /// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`.
     ///
     /// Allowed binding patterns generated by `binding ::= ref? mut? $ident @ $pat_rhs`
-    /// should already have been parsed by now  at this point,
+    /// should already have been parsed by now at this point,
     /// if the next token is `@` then we can try to parse the more general form.
     ///
     /// Consult `parse_pat_ident` for the `binding` grammar.
index 1e5c2834960352c03082ef1e40994755af26dff4..4ff9927aab51af8d3acf925aeff8ccfd6f8ba9fc 100644 (file)
@@ -164,7 +164,10 @@ fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a,
             // Perform this outside of the `collect_tokens_trailing_token` closure,
             // since our outer attributes do not apply to this part of the expression
             let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
-                this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr, true))
+                this.parse_assoc_expr_with(
+                    0,
+                    LhsExpr::AlreadyParsed { expr, starts_statement: true },
+                )
             })?;
             Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
         } else {
@@ -198,7 +201,10 @@ fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResu
             let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
             let e = self.maybe_recover_from_bad_qpath(e)?;
             let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
-            let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e, false))?;
+            let e = self.parse_assoc_expr_with(
+                0,
+                LhsExpr::AlreadyParsed { expr: e, starts_statement: false },
+            )?;
             StmtKind::Expr(e)
         };
         Ok(self.mk_stmt(lo.to(hi), kind))
index a6f702e5428694aa4077eeae5363c905674c030e..1766b0293de52a33c2eceb3254ecfe0b44e7f0af 100644 (file)
@@ -727,11 +727,13 @@ fn parse_generic_bounds_common(
         let mut bounds = Vec::new();
         let mut negative_bounds = Vec::new();
 
+        // In addition to looping while we find generic bounds:
+        // We continue even if we find a keyword. This is necessary for error recovery on,
+        // for example, `impl fn()`. The only keyword that can go after generic bounds is
+        // `where`, so stop if it's it.
+        // We also continue if we find types (not traits), again for error recovery.
         while self.can_begin_bound()
-            // Continue even if we find a keyword.
-            // This is necessary for error recover on, for example, `impl fn()`.
-            //
-            // The only keyword that can go after generic bounds is `where`, so stop if it's it.
+            || self.token.can_begin_type()
             || (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where))
         {
             if self.token.is_keyword(kw::Dyn) {
@@ -938,6 +940,36 @@ fn parse_generic_ty_bound(
             && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
             && let Some(path) = self.recover_path_from_fn()
         {
+            path
+        } else if !self.token.is_path_start() && self.token.can_begin_type() {
+            let ty = self.parse_ty_no_plus()?;
+            // Instead of finding a path (a trait), we found a type.
+            let mut err = self.struct_span_err(ty.span, "expected a trait, found type");
+
+            // If we can recover, try to extract a path from the type. Note
+            // that we do not use the try operator when parsing the type because
+            // if it fails then we get a parser error which we don't want (we're trying
+            // to recover from errors, not make more).
+            let path = if self.may_recover()
+                && matches!(ty.kind, TyKind::Ptr(..) | TyKind::Ref(..))
+                && let TyKind::Path(_, path) = &ty.peel_refs().kind {
+                // Just get the indirection part of the type.
+                let span = ty.span.until(path.span);
+
+                err.span_suggestion_verbose(
+                    span,
+                    "consider removing the indirection",
+                    "",
+                    Applicability::MaybeIncorrect,
+                );
+
+                path.clone()
+            } else {
+                return Err(err);
+            };
+
+            err.emit();
+
             path
         } else {
             self.parse_path(PathStyle::Type)?
index edb0e4367f27354114415fa2dccac4ba576a1af8..94171b4b0c8f1b5ffa6021d2bf3a68c035aceb5c 100644 (file)
@@ -266,7 +266,7 @@ fn should_ignore_item(&mut self, def_id: DefId) -> bool {
             if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
                 && self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
             {
-                let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
+                let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap().subst_identity();
                 if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind()
                     && let Some(adt_def_id) = adt_def.did().as_local()
                 {
index 564cb1baa690914fca320ceb77a56a07e17b5706..fb55bb4afaac3adadbdc8c993038c794df18b324 100644 (file)
@@ -338,7 +338,7 @@ fn of_impl(
         let mut find = FindMin { tcx, effective_visibilities, min: Self::MAX };
         find.visit(tcx.type_of(def_id));
         if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
-            find.visit_trait(trait_ref);
+            find.visit_trait(trait_ref.subst_identity());
         }
         find.min
     }
@@ -838,7 +838,7 @@ fn generics(&mut self) -> &mut Self {
                 GenericParamDefKind::Const { has_default } => {
                     self.visit(self.ev.tcx.type_of(param.def_id));
                     if has_default {
-                        self.visit(self.ev.tcx.const_param_default(param.def_id));
+                        self.visit(self.ev.tcx.const_param_default(param.def_id).subst_identity());
                     }
                 }
             }
@@ -858,7 +858,7 @@ fn ty(&mut self) -> &mut Self {
 
     fn trait_ref(&mut self) -> &mut Self {
         if let Some(trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) {
-            self.visit_trait(trait_ref);
+            self.visit_trait(trait_ref.subst_identity());
         }
         self
     }
index ca43762aa214ec63c846c738a8a8aabe90d86e64..6ca7cd3e71349e133fe079df1533211b89aa8c9b 100644 (file)
@@ -3373,7 +3373,7 @@ fn smart_resolve_path_fragment(
                         sugg.to_string(),
                         Applicability::MaybeIncorrect,
                     ))
-                } else if res.is_none() {
+                } else if res.is_none() && matches!(source, PathSource::Type) {
                     this.report_missing_type_error(path)
                 } else {
                     None
index 84d9794ccf26671471aab168841bca043c1acdff..f950e4a9bee65282e8ae37a9358f1d408191e00d 100644 (file)
@@ -1137,7 +1137,7 @@ fn opt_parent(self, id: DefId) -> Option<DefId> {
     }
 }
 
-impl Resolver<'_> {
+impl<'a> Resolver<'a> {
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
         self.node_id_to_def_id.get(&node).copied()
     }
@@ -1194,6 +1194,10 @@ fn item_generics_num_lifetimes(&self, def_id: DefId) -> usize {
             self.cstore().item_generics_num_lifetimes(def_id, self.session)
         }
     }
+
+    pub fn sess(&self) -> &'a Session {
+        self.session
+    }
 }
 
 impl<'a> Resolver<'a> {
index 1ccfc59f7a9d61e86b5b9f245cf0f8303f465e6b..38aebc81cd6b8cd1a5b95c35fd2a109e67df481f 100644 (file)
@@ -2091,7 +2091,7 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
         .map(|s| {
             // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
             // where KIND is one of "dylib", "framework", "static", "link-arg" and
-            // where MODIFIERS are  a comma separated list of supported modifiers
+            // where MODIFIERS are a comma separated list of supported modifiers
             // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
             // with either + or - to indicate whether it is enabled or disabled.
             // The last value specified for a given modifier wins.
@@ -2459,6 +2459,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     let pretty = parse_pretty(&unstable_opts, error_format);
 
+    // query-dep-graph is required if dump-dep-graph is given #106736
+    if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph {
+        early_error(error_format, "can't dump dependency graph without `-Z query-dep-graph`");
+    }
+
     // Try to find a directory containing the Rust `src`, for more details see
     // the doc comment on the `real_rust_source_base_dir` field.
     let tmp_buf;
index b062b43873b29b28120a142ea689a4c83977932b..7b5fd6cc2a81d9a0c3bc45c660b34f3c7ec7fec3 100644 (file)
@@ -1411,6 +1411,8 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         "what location details should be tracked when using caller_location, either \
         `none`, or a comma separated list of location details, for which \
         valid options are `file`, `line`, and `column` (default: `file,line,column`)"),
+    log_backtrace: Option<String> = (None, parse_opt_string, [TRACKED],
+        "add a backtrace along with logging"),
     ls: bool = (false, parse_bool, [UNTRACKED],
         "list the symbols defined by a library crate (default: no)"),
     macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
index 5ce2577b63c1d81cfd46150dffeb5e039ee00b0c..ae81d95e27967c999d16ac809b23413209919f91 100644 (file)
@@ -15,6 +15,6 @@ scoped-tls = "1.0"
 unicode-width = "0.1.4"
 cfg-if = "1.0"
 tracing = "0.1"
-sha1 = { package = "sha-1", version = "0.10.0" }
+sha1 = "0.10.0"
 sha2 = "0.10.1"
 md5 = { package = "md-5", version = "0.10.0" }
index fa09b4faa441f3b83d50809c92b426e708784b89..58857730e41b6f308fd7fb92b196b7618f2ae83a 100644 (file)
@@ -17,7 +17,7 @@
 use rustc_data_structures::sync::{AtomicU32, Lrc, MappedReadGuard, ReadGuard, RwLock};
 use std::cmp;
 use std::hash::Hash;
-use std::path::{Path, PathBuf};
+use std::path::{self, Path, PathBuf};
 use std::sync::atomic::Ordering;
 
 use std::fs;
@@ -1071,12 +1071,24 @@ pub fn count_lines(&self) -> usize {
 
     pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool {
         source_file.add_external_src(|| {
-            match source_file.name {
-                FileName::Real(ref name) if let Some(local_path) = name.local_path() => {
-                    self.file_loader.read_file(local_path).ok()
+            let FileName::Real(ref name) = source_file.name else {
+                return None;
+            };
+
+            let local_path: Cow<'_, Path> = match name {
+                RealFileName::LocalPath(local_path) => local_path.into(),
+                RealFileName::Remapped { local_path: Some(local_path), .. } => local_path.into(),
+                RealFileName::Remapped { local_path: None, virtual_name } => {
+                    // The compiler produces better error messages if the sources of dependencies
+                    // are available. Attempt to undo any path mapping so we can find remapped
+                    // dependencies.
+                    // We can only use the heuristic because `add_external_src` checks the file
+                    // content hash.
+                    self.path_mapping.reverse_map_prefix_heuristically(virtual_name)?.into()
                 }
-                _ => None,
-            }
+            };
+
+            self.file_loader.read_file(&local_path).ok()
         })
     }
 
@@ -1277,4 +1289,43 @@ pub fn to_embeddable_absolute_path(
             }
         }
     }
+
+    /// Attempts to (heuristically) reverse a prefix mapping.
+    ///
+    /// Returns [`Some`] if there is exactly one mapping where the "to" part is
+    /// a prefix of `path` and has at least one non-empty
+    /// [`Normal`](path::Component::Normal) component. The component
+    /// restriction exists to avoid reverse mapping overly generic paths like
+    /// `/` or `.`).
+    ///
+    /// This is a heuristic and not guaranteed to return the actual original
+    /// path! Do not rely on the result unless you have other means to verify
+    /// that the mapping is correct (e.g. by checking the file content hash).
+    #[instrument(level = "debug", skip(self), ret)]
+    fn reverse_map_prefix_heuristically(&self, path: &Path) -> Option<PathBuf> {
+        let mut found = None;
+
+        for (from, to) in self.mapping.iter() {
+            let has_normal_component = to.components().any(|c| match c {
+                path::Component::Normal(s) => !s.is_empty(),
+                _ => false,
+            });
+
+            if !has_normal_component {
+                continue;
+            }
+
+            let Ok(rest) = path.strip_prefix(to) else {
+                continue;
+            };
+
+            if found.is_some() {
+                return None;
+            }
+
+            found = Some(from.join(rest));
+        }
+
+        found
+    }
 }
index 3cab59e8dbe6cf6166b90d65ad62889e852782a7..b4919af65fd0b2fdd04ba1160a514b2ea043e350 100644 (file)
@@ -344,6 +344,10 @@ fn map_path_prefix(mapping: &FilePathMapping, p: &str) -> String {
     mapping.map_prefix(path(p)).0.to_string_lossy().to_string()
 }
 
+fn reverse_map_prefix(mapping: &FilePathMapping, p: &str) -> Option<String> {
+    mapping.reverse_map_prefix_heuristically(&path(p)).map(|q| q.to_string_lossy().to_string())
+}
+
 #[test]
 fn path_prefix_remapping() {
     // Relative to relative
@@ -480,6 +484,45 @@ fn path_prefix_remapping_expand_to_absolute() {
     );
 }
 
+#[test]
+fn path_prefix_remapping_reverse() {
+    // Ignores options without alphanumeric chars.
+    {
+        let mapping =
+            &FilePathMapping::new(vec![(path("abc"), path("/")), (path("def"), path("."))]);
+
+        assert_eq!(reverse_map_prefix(mapping, "/hello.rs"), None);
+        assert_eq!(reverse_map_prefix(mapping, "./hello.rs"), None);
+    }
+
+    // Returns `None` if multiple options match.
+    {
+        let mapping = &FilePathMapping::new(vec![
+            (path("abc"), path("/redacted")),
+            (path("def"), path("/redacted")),
+        ]);
+
+        assert_eq!(reverse_map_prefix(mapping, "/redacted/hello.rs"), None);
+    }
+
+    // Distinct reverse mappings.
+    {
+        let mapping = &FilePathMapping::new(vec![
+            (path("abc"), path("/redacted")),
+            (path("def/ghi"), path("/fake/dir")),
+        ]);
+
+        assert_eq!(
+            reverse_map_prefix(mapping, "/redacted/path/hello.rs"),
+            Some(path_str("abc/path/hello.rs"))
+        );
+        assert_eq!(
+            reverse_map_prefix(mapping, "/fake/dir/hello.rs"),
+            Some(path_str("def/ghi/hello.rs"))
+        );
+    }
+}
+
 #[test]
 fn test_next_point() {
     let sm = SourceMap::new(FilePathMapping::empty());
index 7f01f33d39c6cace7bfcb13e9fccd35963ae45f1..70cd883be09b3d7d57989931b1a58d8a101ab585 100644 (file)
@@ -462,7 +462,7 @@ pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Sel
     }
 
     /// Returns a suggested template modifier to use for this type and an
-    /// example of a  register named formatted with it.
+    /// example of a register named formatted with it.
     ///
     /// Such suggestions are useful if a type smaller than the full register
     /// size is used and a modifier can be used to point to the subregister of
index e9ddad11ff23e5707ad6297186d93846588e1e03..ba68da0686feaea3aa7c0c5fb845e27f3034eab8 100644 (file)
@@ -2,8 +2,8 @@
 
 use super::infcx_ext::InferCtxtExt;
 use super::{
-    fixme_instantiate_canonical_query_response, CanonicalGoal, CanonicalResponse, Certainty,
-    EvalCtxt, Goal,
+    instantiate_canonical_query_response, CanonicalGoal, CanonicalResponse, Certainty, EvalCtxt,
+    Goal,
 };
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::TyCtxtInferExt;
@@ -121,11 +121,8 @@ fn assemble_candidates_after_normalizing_self_ty(&mut self, goal: Goal<'tcx, G>)
             // canonical wrt the caller.
             for Candidate { source, result } in normalized_candidates {
                 self.infcx.probe(|_| {
-                    let candidate_certainty = fixme_instantiate_canonical_query_response(
-                        &self.infcx,
-                        &orig_values,
-                        result,
-                    );
+                    let candidate_certainty =
+                        instantiate_canonical_query_response(&self.infcx, &orig_values, result);
 
                     // FIXME: This is a bit scary if the `normalizes_to_goal` overflows.
                     //
index 993b79890669c206a8da81d42f7c0b31091a3aab..f1ee73a5b853f463ad9c77b2104a231bcabd3be2 100644 (file)
@@ -9,11 +9,12 @@
 //! FIXME(@lcnr): Write that section, feel free to ping me if you need help here
 //! before then or if I still haven't done that before January 2023.
 use super::overflow::OverflowData;
-use super::CanonicalGoal;
+use super::{CanonicalGoal, Certainty, MaybeCause, Response};
 use super::{EvalCtxt, QueryResult};
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_middle::ty::TyCtxt;
+use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues};
+use rustc_middle::ty::{self, TyCtxt};
 use std::{cmp::Ordering, collections::hash_map::Entry};
 
 #[derive(Debug, Clone)]
@@ -111,11 +112,11 @@ pub(super) fn try_push_stack(
             // No entry, simply push this goal on the stack after dealing with overflow.
             Entry::Vacant(v) => {
                 if self.overflow_data.has_overflow(cache.stack.len()) {
-                    return Err(self.deal_with_overflow());
+                    return Err(self.deal_with_overflow(goal));
                 }
 
                 v.insert(ProvisionalEntry {
-                    response: fixme_response_yes_no_constraints(),
+                    response: response_no_constraints(self.tcx, goal, Certainty::Yes),
                     depth: cache.stack.len(),
                 });
                 cache.stack.push(StackElem { goal, has_been_used: false });
@@ -150,7 +151,11 @@ pub(super) fn try_push_stack(
                 {
                     Err(entry.response)
                 } else {
-                    Err(fixme_response_maybe_no_constraints())
+                    Err(response_no_constraints(
+                        self.tcx,
+                        goal,
+                        Certainty::Maybe(MaybeCause::Ambiguity),
+                    ))
                 }
             }
         }
@@ -248,10 +253,39 @@ fn try_move_finished_goal_to_global_cache(
     }
 }
 
-fn fixme_response_yes_no_constraints<'tcx>() -> QueryResult<'tcx> {
-    unimplemented!()
-}
+pub(super) fn response_no_constraints<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    goal: Canonical<'tcx, impl Sized>,
+    certainty: Certainty,
+) -> QueryResult<'tcx> {
+    let var_values = goal
+        .variables
+        .iter()
+        .enumerate()
+        .map(|(i, info)| match info.kind {
+            CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
+                tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into())).into()
+            }
+            CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
+                let br = ty::BoundRegion {
+                    var: ty::BoundVar::from_usize(i),
+                    kind: ty::BrAnon(i as u32, None),
+                };
+                tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
+            }
+            CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => tcx
+                .mk_const(ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)), ty)
+                .into(),
+        })
+        .collect();
 
-fn fixme_response_maybe_no_constraints<'tcx>() -> QueryResult<'tcx> {
-    unimplemented!()
+    Ok(Canonical {
+        max_universe: goal.max_universe,
+        variables: goal.variables,
+        value: Response {
+            var_values: CanonicalVarValues { var_values },
+            external_constraints: Default::default(),
+            certainty,
+        },
+    })
 }
index c014d682a9aaabcdb269168dd6e050f4dae2784c..dfc2b5ed32947d11a847fd64019b391bf9fc32af 100644 (file)
@@ -62,7 +62,7 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
         let mut errors = Vec::new();
         for i in 0.. {
             if !infcx.tcx.recursion_limit().value_within_limit(i) {
-                unimplemented!("overflow")
+                unimplemented!("overflowed on pending obligations: {:?}", self.obligations);
             }
 
             let mut has_changed = false;
index 7f5e3208f4e7c0fd03dba54521b106c640ac214b..042ba96b379e08ac271a80040fac474e621b233b 100644 (file)
 
 use std::mem;
 
-use rustc_infer::infer::canonical::OriginalQueryValues;
-use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse};
+use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::Obligation;
+use rustc_middle::infer::canonical::Certainty as OldCertainty;
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{RegionOutlivesPredicate, ToPredicate, TypeOutlivesPredicate};
 use rustc_span::DUMMY_SP;
 
+use crate::traits::ObligationCause;
+
+use self::cache::response_no_constraints;
 use self::infcx_ext::InferCtxtExt;
 
 mod assembly;
@@ -119,7 +123,7 @@ pub enum MaybeCause {
 }
 
 /// Additional constraints returned on success.
-#[derive(Debug, PartialEq, Eq, Clone, Hash, TypeFoldable, TypeVisitable)]
+#[derive(Debug, PartialEq, Eq, Clone, Hash, TypeFoldable, TypeVisitable, Default)]
 pub struct ExternalConstraints<'tcx> {
     // FIXME: implement this.
     regions: (),
@@ -175,7 +179,7 @@ fn evaluate_goal(
         let canonical_response = self.evaluate_canonical_goal(canonical_goal)?;
         Ok((
             true, // FIXME: check whether `var_values` are an identity substitution.
-            fixme_instantiate_canonical_query_response(infcx, &orig_values, canonical_response),
+            instantiate_canonical_query_response(infcx, &orig_values, canonical_response),
         ))
     }
 
@@ -208,7 +212,8 @@ fn compute_goal(&mut self, canonical_goal: CanonicalGoal<'tcx>) -> QueryResult<'
         // of `PredicateKind` this is the case and it is and faster than instantiating and
         // recanonicalizing.
         let Goal { param_env, predicate } = canonical_goal.value;
-        if let Some(kind) = predicate.kind().no_bound_vars() {
+
+        if let Some(kind) = predicate.kind().no_bound_vars_ignoring_escaping(self.tcx) {
             match kind {
                 ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => self.compute_trait_goal(
                     canonical_goal.unchecked_rebind(Goal { param_env, predicate }),
@@ -234,7 +239,10 @@ fn compute_goal(&mut self, canonical_goal: CanonicalGoal<'tcx>) -> QueryResult<'
                 | ty::PredicateKind::ConstEvaluatable(_)
                 | ty::PredicateKind::ConstEquate(_, _)
                 | ty::PredicateKind::TypeWellFormedFromEnv(_)
-                | ty::PredicateKind::Ambiguous => unimplemented!(),
+                | ty::PredicateKind::Ambiguous => {
+                    // FIXME
+                    response_no_constraints(self.tcx, canonical_goal, Certainty::Yes)
+                }
             }
         } else {
             let (infcx, goal, var_values) =
@@ -248,16 +256,18 @@ fn compute_goal(&mut self, canonical_goal: CanonicalGoal<'tcx>) -> QueryResult<'
 
     fn compute_type_outlives_goal(
         &mut self,
-        _goal: CanonicalGoal<'tcx, TypeOutlivesPredicate<'tcx>>,
+        goal: CanonicalGoal<'tcx, TypeOutlivesPredicate<'tcx>>,
     ) -> QueryResult<'tcx> {
-        todo!()
+        // FIXME
+        response_no_constraints(self.tcx, goal, Certainty::Yes)
     }
 
     fn compute_region_outlives_goal(
         &mut self,
-        _goal: CanonicalGoal<'tcx, RegionOutlivesPredicate<'tcx>>,
+        goal: CanonicalGoal<'tcx, RegionOutlivesPredicate<'tcx>>,
     ) -> QueryResult<'tcx> {
-        todo!()
+        // FIXME
+        response_no_constraints(self.tcx, goal, Certainty::Yes)
     }
 }
 
@@ -300,10 +310,27 @@ fn evaluate_all(
     }
 }
 
-fn fixme_instantiate_canonical_query_response<'tcx>(
-    _: &InferCtxt<'tcx>,
-    _: &OriginalQueryValues<'tcx>,
-    _: CanonicalResponse<'tcx>,
+fn instantiate_canonical_query_response<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    original_values: &OriginalQueryValues<'tcx>,
+    response: CanonicalResponse<'tcx>,
 ) -> Certainty {
-    unimplemented!()
+    let Ok(InferOk { value, obligations }) = infcx
+        .instantiate_query_response_and_region_obligations(
+            &ObligationCause::dummy(),
+            ty::ParamEnv::empty(),
+            original_values,
+            &response.unchecked_map(|resp| QueryResponse {
+                var_values: resp.var_values,
+                region_constraints: QueryRegionConstraints::default(),
+                certainty: match resp.certainty {
+                    Certainty::Yes => OldCertainty::Proven,
+                    Certainty::Maybe(_) => OldCertainty::Ambiguous,
+                },
+                opaque_types: resp.external_constraints.opaque_types,
+                value: resp.certainty,
+            }),
+        ) else { bug!(); };
+    assert!(obligations.is_empty());
+    value
 }
index fdd6adb681be4cba1aa43187d323db65e864b3b4..8bbb9f63e78682702ed9fdba111658e8e9ad3539 100644 (file)
@@ -1,7 +1,9 @@
+use rustc_infer::infer::canonical::Canonical;
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Limit;
 
+use super::cache::response_no_constraints;
 use super::{Certainty, EvalCtxt, MaybeCause, QueryResult};
 
 /// When detecting a solver overflow, we return ambiguity. Overflow can be
@@ -49,9 +51,12 @@ fn deal_with_overflow(&mut self) {
 }
 
 impl<'tcx> EvalCtxt<'tcx> {
-    pub(super) fn deal_with_overflow(&mut self) -> QueryResult<'tcx> {
+    pub(super) fn deal_with_overflow(
+        &mut self,
+        goal: Canonical<'tcx, impl Sized>,
+    ) -> QueryResult<'tcx> {
         self.overflow_data.deal_with_overflow();
-        fixme_response_overflow_no_constraints()
+        response_no_constraints(self.tcx, goal, Certainty::Maybe(MaybeCause::Overflow))
     }
 
     /// A `while`-loop which tracks overflow.
@@ -74,7 +79,3 @@ pub(super) fn repeat_while_none(
         Ok(Certainty::Maybe(MaybeCause::Overflow))
     }
 }
-
-fn fixme_response_overflow_no_constraints<'tcx>() -> QueryResult<'tcx> {
-    unimplemented!()
-}
index 3d649bea19ddfc966ed0f9ceb3e659e12f4a0950..d2f2e78f555ae603f1eaaff6d0bbe2b2f088fafd 100644 (file)
@@ -110,7 +110,7 @@ fn consider_impl_candidate(
     ) {
         let tcx = acx.cx.tcx;
         let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
-        let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap();
+        let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
         let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
         if iter::zip(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs)
             .any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
@@ -171,7 +171,7 @@ fn consider_impl_candidate(
             let impl_substs_with_gat = goal.predicate.projection_ty.substs.rebase_onto(
                 tcx,
                 goal_trait_ref.def_id,
-                impl_trait_ref.substs,
+                impl_substs,
             );
             let substs = translate_substs(
                 acx.infcx,
index c69cc39acb53cea516568532d109556cfaee5a86..a43fef5cdb0c875f26e0976766cf9faedc0febf1 100644 (file)
@@ -73,7 +73,7 @@ fn consider_impl_candidate(
     ) {
         let tcx = acx.cx.tcx;
 
-        let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap();
+        let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
         let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
         if iter::zip(goal.predicate.trait_ref.substs, impl_trait_ref.skip_binder().substs)
             .any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
index 258d2e2d28c9db5db8efc8e8dfcfb9b734d20be0..0edae34190c300f2a42a616db12251dab87a175e 100644 (file)
@@ -80,7 +80,7 @@ pub fn overlapping_impls(
     let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
     let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
     let may_overlap = match (impl1_ref, impl2_ref) {
-        (Some(a), Some(b)) => iter::zip(a.substs, b.substs)
+        (Some(a), Some(b)) => iter::zip(a.skip_binder().substs, b.skip_binder().substs)
             .all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)),
         (None, None) => {
             let self_ty1 = tcx.type_of(impl1_def_id);
@@ -126,7 +126,7 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
     let header = ty::ImplHeader {
         impl_def_id,
         self_ty: tcx.bound_type_of(impl_def_id).subst(tcx, impl_substs),
-        trait_ref: tcx.bound_impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)),
+        trait_ref: tcx.impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)),
         predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates,
     };
 
@@ -461,7 +461,7 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
 
     // We only except this routine to be invoked on implementations
     // of a trait, not inherent implementations.
-    let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+    let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
     debug!("orphan_check: trait_ref={:?}", trait_ref);
 
     // If the *trait* is local to the crate, ok.
index 0c1717cff332c40e79bede7a633994be3c054155..0419bb3f724f9ed86454dc73c60dc5db20502ada 100644 (file)
@@ -27,7 +27,7 @@ pub fn recompute_applicable_impls<'tcx>(
             ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
 
         let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
-        let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs);
+        let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs);
         let impl_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
 
         if let Err(_) =
@@ -82,9 +82,7 @@ pub fn recompute_applicable_impls<'tcx>(
 
     let predicates =
         tcx.predicates_of(obligation.cause.body_id.owner.to_def_id()).instantiate_identity(tcx);
-    for obligation in
-        elaborate_predicates_with_span(tcx, std::iter::zip(predicates.predicates, predicates.spans))
-    {
+    for obligation in elaborate_predicates_with_span(tcx, predicates.into_iter()) {
         let kind = obligation.predicate.kind();
         if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder()
             && param_env_candidate_may_apply(kind.rebind(trait_pred))
index 0c7ffb056cc0256e4177ba9a4a1aba7943eba29e..edd187b8dec3b1469a14125c01ad4845f6e0bade 100644 (file)
@@ -374,6 +374,7 @@ fn type_implements_fn_trait(
         })
     }
 }
+
 impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     fn report_fulfillment_errors(
         &self,
@@ -453,9 +454,11 @@ struct ErrorDescriptor<'tcx> {
             }
         }
 
-        for (error, suppressed) in iter::zip(errors, is_suppressed) {
-            if !suppressed {
-                self.report_fulfillment_error(error, body_id);
+        for from_expansion in [false, true] {
+            for (error, suppressed) in iter::zip(errors, &is_suppressed) {
+                if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
+                    self.report_fulfillment_error(error, body_id);
+                }
             }
         }
 
@@ -852,6 +855,29 @@ fn report_selection_error(
                         let mut suggested =
                             self.suggest_dereferences(&obligation, &mut err, trait_predicate);
                         suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate);
+                        let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
+                        suggested = if let &[cand] = &impl_candidates[..] {
+                            let cand = cand.trait_ref;
+                            if let (ty::FnPtr(_), ty::FnDef(..)) =
+                                (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind())
+                            {
+                                err.span_suggestion(
+                                    span.shrink_to_hi(),
+                                    format!(
+                                        "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`",
+                                        cand.print_only_trait_path(),
+                                        cand.self_ty(),
+                                    ),
+                                    format!(" as {}", cand.self_ty()),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                true
+                            } else {
+                                false
+                            }
+                        } else {
+                            false
+                        } || suggested;
                         suggested |=
                             self.suggest_remove_reference(&obligation, &mut err, trait_predicate);
                         suggested |= self.suggest_semicolon_removal(
@@ -1940,7 +1966,7 @@ fn find_similar_impl_candidates(
                     return None;
                 }
 
-                let imp = self.tcx.impl_trait_ref(def_id).unwrap();
+                let imp = self.tcx.impl_trait_ref(def_id).unwrap().skip_binder();
 
                 self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false)
                     .map(|similarity| ImplCandidate { trait_ref: imp, similarity })
@@ -1968,27 +1994,25 @@ fn report_similar_impl_candidates(
             candidates.sort();
             candidates.dedup();
             let len = candidates.len();
-            if candidates.len() == 0 {
+            if candidates.is_empty() {
                 return false;
             }
-            if candidates.len() == 1 {
-                let ty_desc = match candidates[0].self_ty().kind() {
-                    ty::FnPtr(_) => Some("fn pointer"),
-                    _ => None,
-                };
-                let the_desc = match ty_desc {
-                    Some(desc) => format!(" implemented for {} `", desc),
-                    None => " implemented for `".to_string(),
-                };
+            if let &[cand] = &candidates[..] {
+                let (desc, mention_castable) =
+                    match (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) {
+                        (ty::FnPtr(_), ty::FnDef(..)) => {
+                            (" implemented for fn pointer `", ", cast using `as`")
+                        }
+                        (ty::FnPtr(_), _) => (" implemented for fn pointer `", ""),
+                        _ => (" implemented for `", ""),
+                    };
                 err.highlighted_help(vec![
-                    (
-                        format!("the trait `{}` ", candidates[0].print_only_trait_path()),
-                        Style::NoStyle,
-                    ),
+                    (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle),
                     ("is".to_string(), Style::Highlight),
-                    (the_desc, Style::NoStyle),
-                    (candidates[0].self_ty().to_string(), Style::Highlight),
+                    (desc.to_string(), Style::NoStyle),
+                    (cand.self_ty().to_string(), Style::Highlight),
                     ("`".to_string(), Style::NoStyle),
+                    (mention_castable.to_string(), Style::NoStyle),
                 ]);
                 return true;
             }
@@ -2040,6 +2064,7 @@ fn report_similar_impl_candidates(
                         || self.tcx.is_builtin_derive(def_id)
                 })
                 .filter_map(|def_id| self.tcx.impl_trait_ref(def_id))
+                .map(ty::EarlyBinder::subst_identity)
                 .filter(|trait_ref| {
                     let self_ty = trait_ref.self_ty();
                     // Avoid mentioning type parameters.
@@ -2912,6 +2937,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
     }
 }
 
+#[derive(Copy, Clone)]
 pub enum DefIdOrName {
     DefId(DefId),
     Name(&'static str),
index e599996230f51691b87c4a97c34d2195d2307739..18d308f7123aec90bf1d9192e1cc5b24b76dc8a8 100644 (file)
@@ -68,7 +68,7 @@ fn impl_similar_to(
 
         self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
             let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
-            let impl_trait_ref = tcx.bound_impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);
+            let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);
 
             let impl_self_ty = impl_trait_ref.self_ty();
 
index 1b98ead29f851d96e076703361ea7053be52d9d0..6e2341a823b9b82d46edbf403f773eaf003297ba 100644 (file)
@@ -212,6 +212,13 @@ fn suggest_add_clone_to_arg(
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool;
 
+    fn extract_callable_info(
+        &self,
+        hir_id: HirId,
+        param_env: ty::ParamEnv<'tcx>,
+        found: Ty<'tcx>,
+    ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)>;
+
     fn suggest_add_reference_to_arg(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -878,6 +885,12 @@ fn suggest_fn_call(
         err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
+        // It doesn't make sense to make this suggestion outside of typeck...
+        // (also autoderef will ICE...)
+        if self.typeck_results.is_none() {
+            return false;
+        }
+
         if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = obligation.predicate.kind().skip_binder()
             && Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait()
         {
@@ -885,92 +898,17 @@ fn suggest_fn_call(
             return false;
         }
 
-        // This is duplicated from `extract_callable_info` in typeck, which
-        // relies on autoderef, so we can't use it here.
-        let found = trait_pred.self_ty().skip_binder().peel_refs();
-        let Some((def_id_or_name, output, inputs)) = (match *found.kind()
-        {
-            ty::FnPtr(fn_sig) => {
-                Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs()))
-            }
-            ty::FnDef(def_id, _) => {
-                let fn_sig = found.fn_sig(self.tcx);
-                Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
-            }
-            ty::Closure(def_id, substs) => {
-                let fn_sig = substs.as_closure().sig();
-                Some((
-                    DefIdOrName::DefId(def_id),
-                    fn_sig.output(),
-                    fn_sig.inputs().map_bound(|inputs| &inputs[1..]),
-                ))
-            }
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
-                self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
-                    if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
-                    && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
-                    // args tuple will always be substs[1]
-                    && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
-                    {
-                        Some((
-                            DefIdOrName::DefId(def_id),
-                            pred.kind().rebind(proj.term.ty().unwrap()),
-                            pred.kind().rebind(args.as_slice()),
-                        ))
-                    } else {
-                        None
-                    }
-                })
-            }
-            ty::Dynamic(data, _, ty::Dyn) => {
-                data.iter().find_map(|pred| {
-                    if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
-                    && Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
-                    // for existential projection, substs are shifted over by 1
-                    && let ty::Tuple(args) = proj.substs.type_at(0).kind()
-                    {
-                        Some((
-                            DefIdOrName::Name("trait object"),
-                            pred.rebind(proj.term.ty().unwrap()),
-                            pred.rebind(args.as_slice()),
-                        ))
-                    } else {
-                        None
-                    }
-                })
-            }
-            ty::Param(_) => {
-                obligation.param_env.caller_bounds().iter().find_map(|pred| {
-                    if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
-                    && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
-                    && proj.projection_ty.self_ty() == found
-                    // args tuple will always be substs[1]
-                    && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
-                    {
-                        Some((
-                            DefIdOrName::Name("type parameter"),
-                            pred.kind().rebind(proj.term.ty().unwrap()),
-                            pred.kind().rebind(args.as_slice()),
-                        ))
-                    } else {
-                        None
-                    }
-                })
-            }
-            _ => None,
-        }) else { return false; };
-        let output = self.replace_bound_vars_with_fresh_vars(
-            obligation.cause.span,
+        let self_ty = self.replace_bound_vars_with_fresh_vars(
+            DUMMY_SP,
             LateBoundRegionConversionTime::FnCall,
-            output,
+            trait_pred.self_ty(),
         );
-        let inputs = inputs.skip_binder().iter().map(|ty| {
-            self.replace_bound_vars_with_fresh_vars(
-                obligation.cause.span,
-                LateBoundRegionConversionTime::FnCall,
-                inputs.rebind(*ty),
-            )
-        });
+
+        let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(
+            obligation.cause.body_id,
+            obligation.param_env,
+            self_ty,
+        ) else { return false; };
 
         // Remapping bound vars here
         let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output));
@@ -998,6 +936,7 @@ fn suggest_fn_call(
         };
 
         let args = inputs
+            .into_iter()
             .map(|ty| {
                 if ty.is_suggestable(self.tcx, false) {
                     format!("/* {ty} */")
@@ -1161,6 +1100,120 @@ fn suggest_add_clone_to_arg(
         false
     }
 
+    /// Extracts information about a callable type for diagnostics. This is a
+    /// heuristic -- it doesn't necessarily mean that a type is always callable,
+    /// because the callable type must also be well-formed to be called.
+    fn extract_callable_info(
+        &self,
+        hir_id: HirId,
+        param_env: ty::ParamEnv<'tcx>,
+        found: Ty<'tcx>,
+    ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
+        // Autoderef is useful here because sometimes we box callables, etc.
+        let Some((def_id_or_name, output, inputs)) = (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| {
+            match *found.kind() {
+                ty::FnPtr(fn_sig) =>
+                    Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())),
+                ty::FnDef(def_id, _) => {
+                    let fn_sig = found.fn_sig(self.tcx);
+                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
+                }
+                ty::Closure(def_id, substs) => {
+                    let fn_sig = substs.as_closure().sig();
+                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..])))
+                }
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
+                    self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
+                        if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
+                        && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
+                        // args tuple will always be substs[1]
+                        && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+                        {
+                            Some((
+                                DefIdOrName::DefId(def_id),
+                                pred.kind().rebind(proj.term.ty().unwrap()),
+                                pred.kind().rebind(args.as_slice()),
+                            ))
+                        } else {
+                            None
+                        }
+                    })
+                }
+                ty::Dynamic(data, _, ty::Dyn) => {
+                    data.iter().find_map(|pred| {
+                        if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
+                        && Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
+                        // for existential projection, substs are shifted over by 1
+                        && let ty::Tuple(args) = proj.substs.type_at(0).kind()
+                        {
+                            Some((
+                                DefIdOrName::Name("trait object"),
+                                pred.rebind(proj.term.ty().unwrap()),
+                                pred.rebind(args.as_slice()),
+                            ))
+                        } else {
+                            None
+                        }
+                    })
+                }
+                ty::Param(param) => {
+                    let generics = self.tcx.generics_of(hir_id.owner.to_def_id());
+                    let name = if generics.count() > param.index as usize
+                        && let def = generics.param_at(param.index as usize, self.tcx)
+                        && matches!(def.kind, ty::GenericParamDefKind::Type { .. })
+                        && def.name == param.name
+                    {
+                        DefIdOrName::DefId(def.def_id)
+                    } else {
+                        DefIdOrName::Name("type parameter")
+                    };
+                    param_env.caller_bounds().iter().find_map(|pred| {
+                        if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
+                        && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
+                        && proj.projection_ty.self_ty() == found
+                        // args tuple will always be substs[1]
+                        && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+                        {
+                            Some((
+                                name,
+                                pred.kind().rebind(proj.term.ty().unwrap()),
+                                pred.kind().rebind(args.as_slice()),
+                            ))
+                        } else {
+                            None
+                        }
+                    })
+                }
+                _ => None,
+            }
+        }) else { return None; };
+
+        let output = self.replace_bound_vars_with_fresh_vars(
+            DUMMY_SP,
+            LateBoundRegionConversionTime::FnCall,
+            output,
+        );
+        let inputs = inputs
+            .skip_binder()
+            .iter()
+            .map(|ty| {
+                self.replace_bound_vars_with_fresh_vars(
+                    DUMMY_SP,
+                    LateBoundRegionConversionTime::FnCall,
+                    inputs.rebind(*ty),
+                )
+            })
+            .collect();
+
+        // We don't want to register any extra obligations, which should be
+        // implied by wf, but also because that would possibly result in
+        // erroneous errors later on.
+        let InferOk { value: output, obligations: _ } =
+            self.at(&ObligationCause::dummy(), param_env).normalize(output);
+
+        if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
+    }
+
     fn suggest_add_reference_to_arg(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -2017,7 +2070,7 @@ fn note_conflicting_closure_bounds(
 
             // Find another predicate whose self-type is equal to the expected self type,
             // but whose substs don't match.
-            let other_pred = std::iter::zip(&predicates.predicates, &predicates.spans)
+            let other_pred = predicates.into_iter()
                 .enumerate()
                 .find(|(other_idx, (pred, _))| match pred.kind().skip_binder() {
                     ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))
@@ -2042,7 +2095,7 @@ fn note_conflicting_closure_bounds(
             // If we found one, then it's very likely the cause of the error.
             if let Some((_, (_, other_pred_span))) = other_pred {
                 err.span_note(
-                    *other_pred_span,
+                    other_pred_span,
                     "closure inferred to have a different signature due to this bound",
                 );
             }
index 37b40a2f75adc108a77765070c011073a69da460..531aa23d6eac59a1fc7a41176a73631aa9c9e841 100644 (file)
@@ -115,14 +115,12 @@ pub fn predicates_for_generics<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     generic_bounds: ty::InstantiatedPredicates<'tcx>,
 ) -> impl Iterator<Item = PredicateObligation<'tcx>> {
-    std::iter::zip(generic_bounds.predicates, generic_bounds.spans).enumerate().map(
-        move |(idx, (predicate, span))| Obligation {
-            cause: cause(idx, span),
-            recursion_depth: 0,
-            param_env,
-            predicate,
-        },
-    )
+    generic_bounds.into_iter().enumerate().map(move |(idx, (predicate, span))| Obligation {
+        cause: cause(idx, span),
+        recursion_depth: 0,
+        param_env,
+        predicate,
+    })
 }
 
 /// Determines whether the type `ty` is known to meet `bound` and
@@ -308,7 +306,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     // the `TypeOutlives` predicates first inside the unnormalized parameter environment, and
     // then we normalize the `TypeOutlives` bounds inside the normalized parameter environment.
     //
-    // This works fairly well because trait matching  does not actually care about param-env
+    // This works fairly well because trait matching does not actually care about param-env
     // TypeOutlives predicates - these are normally used by regionck.
     let outlives_predicates: Vec<_> = predicates
         .drain_filter(|predicate| {
@@ -521,8 +519,10 @@ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
 
     let generics = tcx.generics_of(trait_item_def_id);
     let predicates = tcx.predicates_of(trait_item_def_id);
-    let impl_trait_ref =
-        tcx.impl_trait_ref(impl_def_id).expect("expected impl to correspond to trait");
+    let impl_trait_ref = tcx
+        .impl_trait_ref(impl_def_id)
+        .expect("expected impl to correspond to trait")
+        .subst_identity();
     let param_env = tcx.param_env(impl_def_id);
 
     let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id };
index 81966f3fcb231791b5cc098dab611e9b81fde698..9c655aff0bac462df7efaf44335cd465d224cc22 100644 (file)
@@ -2259,25 +2259,23 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
         tcx.predicates_of(impl_fn_def_id).instantiate(tcx, impl_fn_substs),
         &mut obligations,
     );
-    obligations.extend(std::iter::zip(predicates.predicates, predicates.spans).map(
-        |(pred, span)| {
-            Obligation::with_depth(
-                tcx,
-                ObligationCause::new(
-                    obligation.cause.span,
-                    obligation.cause.body_id,
-                    if span.is_dummy() {
-                        super::ItemObligation(impl_fn_def_id)
-                    } else {
-                        super::BindingObligation(impl_fn_def_id, span)
-                    },
-                ),
-                obligation.recursion_depth + 1,
-                obligation.param_env,
-                pred,
-            )
-        },
-    ));
+    obligations.extend(predicates.into_iter().map(|(pred, span)| {
+        Obligation::with_depth(
+            tcx,
+            ObligationCause::new(
+                obligation.cause.span,
+                obligation.cause.body_id,
+                if span.is_dummy() {
+                    super::ItemObligation(impl_fn_def_id)
+                } else {
+                    super::BindingObligation(impl_fn_def_id, span)
+                },
+            ),
+            obligation.recursion_depth + 1,
+            obligation.param_env,
+            pred,
+        )
+    }));
 
     let ty = normalize_with_depth_to(
         selcx,
@@ -2303,10 +2301,10 @@ fn assoc_ty_own_obligations<'cx, 'tcx>(
     nested: &mut Vec<PredicateObligation<'tcx>>,
 ) {
     let tcx = selcx.tcx();
-    let own = tcx
+    let predicates = tcx
         .predicates_of(obligation.predicate.def_id)
         .instantiate_own(tcx, obligation.predicate.substs);
-    for (predicate, span) in std::iter::zip(own.predicates, own.spans) {
+    for (predicate, span) in predicates {
         let normalized = normalize_with_depth_to(
             selcx,
             obligation.param_env,
index 8c291d1595d960a1c5bcc473127ac6044c022e41..e29ad30d5f2ec7cb5a9e7aa4c0382912e45c6e85 100644 (file)
@@ -357,7 +357,7 @@ fn assemble_candidates_from_impls(
                 // Before we create the substitutions and everything, first
                 // consider a "quick reject". This avoids creating more types
                 // and so forth that we need to.
-                let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap();
+                let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
                 if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) {
                     return;
                 }
index a41d10f104358ea57f8f6e4cb641e38455b63ad7..d4ac461690c9034460e6a5696d1d6ef38db64b97 100644 (file)
@@ -185,9 +185,8 @@ fn confirm_projection_candidate(
         })?);
 
         if let ty::Alias(ty::Projection, ..) = placeholder_self_ty.kind() {
-            let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates;
-            debug!(?predicates, "projection predicates");
-            for predicate in predicates {
+            let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
+            for (predicate, _) in predicates {
                 let normalized = normalize_with_depth_to(
                     self,
                     obligation.param_env,
index 305902af7c8290469f4660d519398536c64e5cfe..95c269d1b78538eace45ef2bdb44d9ae699983c4 100644 (file)
@@ -2335,7 +2335,7 @@ fn rematch_impl(
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
     ) -> Normalized<'tcx, SubstsRef<'tcx>> {
-        let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap();
+        let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
         match self.match_impl(impl_def_id, impl_trait_ref, obligation) {
             Ok(substs) => substs,
             Err(()) => {
@@ -2558,12 +2558,11 @@ fn impl_or_trait_obligations(
         // obligation will normalize to `<$0 as Iterator>::Item = $1` and
         // `$1: Copy`, so we must ensure the obligations are emitted in
         // that order.
-        let predicates = tcx.bound_predicates_of(def_id);
-        debug!(?predicates);
-        assert_eq!(predicates.0.parent, None);
-        let mut obligations = Vec::with_capacity(predicates.0.predicates.len());
-        for (predicate, span) in predicates.0.predicates {
-            let span = *span;
+        let predicates = tcx.predicates_of(def_id);
+        assert_eq!(predicates.parent, None);
+        let predicates = predicates.instantiate_own(tcx, substs);
+        let mut obligations = Vec::with_capacity(predicates.len());
+        for (predicate, span) in predicates {
             let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
                 ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
                     derived,
@@ -2576,7 +2575,7 @@ fn impl_or_trait_obligations(
                 param_env,
                 cause.clone(),
                 recursion_depth,
-                predicates.rebind(*predicate).subst(tcx, substs),
+                predicate,
                 &mut obligations,
             );
             obligations.push(Obligation { cause, recursion_depth, param_env, predicate });
index a251a508b48cf1777f4d86e62583066eb8caa0b7..3b796c623c0ab11a771bf7eb990b1433dc607ef5 100644 (file)
@@ -87,7 +87,7 @@ pub fn translate_substs<'tcx>(
         param_env, source_impl, source_substs, target_node
     );
     let source_trait_ref =
-        infcx.tcx.bound_impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs);
+        infcx.tcx.impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs);
 
     // translate the Self and Param parts of the substitution, since those
     // vary across impls
@@ -148,7 +148,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
 
     // create a parameter environment corresponding to a (placeholder) instantiation of impl1
     let penv = tcx.param_env(impl1_def_id);
-    let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
+    let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity();
 
     // Create an infcx, taking the predicates of impl1 as assumptions:
     let infcx = tcx.infer_ctxt().build();
@@ -431,7 +431,7 @@ fn decorate<'tcx>(
 pub(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)?;
+    let trait_ref = tcx.impl_trait_ref(impl_def_id)?.subst_identity();
     let mut w = "impl".to_owned();
 
     let substs = InternalSubsts::identity_for_item(tcx, impl_def_id);
index 02b0667774028a37224a926b1d74bb9a92f52b6f..6411206a5a40c276b188a337270ade6dbc2cae6f 100644 (file)
@@ -48,7 +48,7 @@ fn insert(
 impl<'tcx> ChildrenExt<'tcx> for Children {
     /// Insert an impl into this set of children without comparing to any existing impls.
     fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
-        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
         if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
         {
             debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
@@ -63,7 +63,7 @@ fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
     /// an impl with a parent. The impl must be present in the list of
     /// children already.
     fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
-        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
         let vec: &mut Vec<DefId>;
         if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
         {
@@ -181,7 +181,7 @@ fn insert(
             if le && !ge {
                 debug!(
                     "descending as child of TraitRef {:?}",
-                    tcx.impl_trait_ref(possible_sibling).unwrap()
+                    tcx.impl_trait_ref(possible_sibling).unwrap().subst_identity()
                 );
 
                 // The impl specializes `possible_sibling`.
@@ -189,7 +189,7 @@ fn insert(
             } else if ge && !le {
                 debug!(
                     "placing as parent of TraitRef {:?}",
-                    tcx.impl_trait_ref(possible_sibling).unwrap()
+                    tcx.impl_trait_ref(possible_sibling).unwrap().subst_identity()
                 );
 
                 replace_children.push(possible_sibling);
@@ -275,7 +275,8 @@ fn insert(
     ) -> Result<Option<FutureCompatOverlapError<'tcx>>, OverlapError<'tcx>> {
         assert!(impl_def_id.is_local());
 
-        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+        // FIXME: use `EarlyBinder` in `self.children`
+        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
         let trait_def_id = trait_ref.def_id;
 
         debug!(
@@ -388,7 +389,7 @@ pub(crate) fn assoc_def(
     impl_def_id: DefId,
     assoc_def_id: DefId,
 ) -> Result<LeafDef, ErrorGuaranteed> {
-    let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id;
+    let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
     let trait_def = tcx.trait_def(trait_def_id);
 
     // This function may be called while we are still building the
index 5ec9c2a24cd448db3534fa5f3a8798cba24a1c64..64daca714c32d1e8b20d6ed3ed8a300727a0bc69 100644 (file)
@@ -261,7 +261,10 @@ fn vtable_entries<'tcx>(
                     // Note that this method could then never be called, so we
                     // do not want to try and codegen it, in that case (see #23435).
                     let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
-                    if impossible_predicates(tcx, predicates.predicates) {
+                    if impossible_predicates(
+                        tcx,
+                        predicates.map(|(predicate, _)| predicate).collect(),
+                    ) {
                         debug!("vtable_entries: predicates do not hold");
                         return VtblEntry::Vacant;
                     }
index fec4047ff49ba4d4a675b7cd97c4bd8d31c1085a..2cebad64c43732f58741dd5e9fe5074eed52eacc 100644 (file)
@@ -736,7 +736,7 @@ fn nominal_obligations_inner(
         trace!("{:#?}", predicates);
         debug_assert_eq!(predicates.predicates.len(), origins.len());
 
-        iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev())
+        iter::zip(predicates, origins.into_iter().rev())
             .map(|((mut pred, span), origin_def_id)| {
                 let code = if span.is_dummy() {
                     traits::ItemObligation(origin_def_id)
index f288eb112582dfeed77719c0ea805d3c2376c17f..f146de3966ba107865068631c9328f88fe2bd885 100644 (file)
@@ -7,7 +7,7 @@
 //! `crate::chalk::lowering` (to lower rustc types into Chalk types).
 
 use rustc_middle::traits::ChalkRustInterner as RustInterner;
-use rustc_middle::ty::{self, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
+use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
 use rustc_target::abi::{Integer, IntegerType};
 
@@ -38,13 +38,12 @@ fn where_clauses_for(
         def_id: DefId,
         bound_vars: SubstsRef<'tcx>,
     ) -> Vec<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
-        let predicates = self.interner.tcx.predicates_defined_on(def_id).predicates;
-        predicates
-            .iter()
-            .map(|(wc, _)| EarlyBinder(*wc).subst(self.interner.tcx, bound_vars))
-            .filter_map(|wc| LowerInto::<
-                    Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>
-                    >::lower_into(wc, self.interner)).collect()
+        self.interner
+            .tcx
+            .predicates_defined_on(def_id)
+            .instantiate_own(self.interner.tcx, bound_vars)
+            .filter_map(|(wc, _)| LowerInto::lower_into(wc, self.interner))
+            .collect()
     }
 
     fn bounds_for<T>(&self, def_id: DefId, bound_vars: SubstsRef<'tcx>) -> Vec<T>
@@ -309,7 +308,7 @@ fn impl_datum(
         let bound_vars = bound_vars_for_item(self.interner.tcx, def_id);
         let binders = binders_for(self.interner, bound_vars);
 
-        let trait_ref = self.interner.tcx.bound_impl_trait_ref(def_id).expect("not an impl");
+        let trait_ref = self.interner.tcx.impl_trait_ref(def_id).expect("not an impl");
         let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars);
 
         let where_clauses = self.where_clauses_for(def_id, bound_vars);
@@ -351,7 +350,7 @@ fn impls_for_trait(
         let all_impls = self.interner.tcx.all_impls(def_id);
         let matched_impls = all_impls.filter(|impl_def_id| {
             use chalk_ir::could_match::CouldMatch;
-            let trait_ref = self.interner.tcx.bound_impl_trait_ref(*impl_def_id).unwrap();
+            let trait_ref = self.interner.tcx.impl_trait_ref(*impl_def_id).unwrap();
             let bound_vars = bound_vars_for_item(self.interner.tcx, *impl_def_id);
 
             let self_ty = trait_ref.map_bound(|t| t.self_ty());
@@ -380,7 +379,7 @@ fn impl_provided_for(
         let trait_def_id = auto_trait_id.0;
         let all_impls = self.interner.tcx.all_impls(trait_def_id);
         for impl_def_id in all_impls {
-            let trait_ref = self.interner.tcx.impl_trait_ref(impl_def_id).unwrap();
+            let trait_ref = self.interner.tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity();
             let self_ty = trait_ref.self_ty();
             let provides = match (self_ty.kind(), chalk_ty) {
                 (&ty::Adt(impl_adt_def, ..), Adt(id, ..)) => impl_adt_def.did() == id.0.did(),
index aa5c83ac2e6557cd98e40f7d29cbc18db5a99853..f35c5e44882df38db20a578bc83cdfcd9c2f50ae 100644 (file)
@@ -17,7 +17,6 @@
 use rustc_trait_selection::traits::query::{Fallible, NoSolution};
 use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt};
 use std::fmt;
-use std::iter::zip;
 
 pub(crate) fn provide(p: &mut Providers) {
     *p = Providers {
@@ -108,9 +107,7 @@ fn relate_mir_and_user_substs<'tcx>(
     let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
 
     debug!(?instantiated_predicates);
-    for (instantiated_predicate, predicate_span) in
-        zip(instantiated_predicates.predicates, instantiated_predicates.spans)
-    {
+    for (instantiated_predicate, predicate_span) in instantiated_predicates {
         let span = if span == DUMMY_SP { predicate_span } else { span };
         let cause = ObligationCause::new(
             span,
index b7a24a22c53e3d8d3916257116e62f7f3c741ab2..7a24645803c9660441eef85bba5f794d5d51aced 100644 (file)
@@ -21,14 +21,16 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
             assumed_wf_types.extend(liberated_sig.inputs_and_output);
             tcx.intern_type_list(&assumed_wf_types)
         }
-        DefKind::Impl => match tcx.impl_trait_ref(def_id) {
-            Some(trait_ref) => {
-                let types: Vec<_> = trait_ref.substs.types().collect();
-                tcx.intern_type_list(&types)
+        DefKind::Impl => {
+            match tcx.impl_trait_ref(def_id) {
+                Some(trait_ref) => {
+                    let types: Vec<_> = trait_ref.skip_binder().substs.types().collect();
+                    tcx.intern_type_list(&types)
+                }
+                // Only the impl self type
+                None => tcx.intern_type_list(&[tcx.type_of(def_id)]),
             }
-            // Only the impl self type
-            None => tcx.intern_type_list(&[tcx.type_of(def_id)]),
-        },
+        }
         DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
         DefKind::Mod
         | DefKind::Struct
index 87923ebbe4bc948502d1fefca6a13935867bf864..eb5454bf2634b6b61f948a265efea3b59a0ed8c5 100644 (file)
@@ -289,7 +289,7 @@ enum NodeKind {
         // In a trait impl, we assume that the header trait ref and all its
         // constituents are well-formed.
         NodeKind::TraitImpl => {
-            let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
+            let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl").subst_identity();
 
             // FIXME(chalk): this has problems because of late-bound regions
             //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk()));
@@ -360,7 +360,8 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ty<'_>> {
 
     let trait_ref = tcx
         .impl_trait_ref(def_id)
-        .unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id));
+        .unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id))
+        .skip_binder();
 
     debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref);
 
index fe6de1cf879b2e2395173f1d4e5d3c80ea2a1fe9..3a797bd5ecaa8ea84e8d90f8a47dab4f5b6c94b9 100644 (file)
@@ -20,7 +20,7 @@
 mod tests;
 
 extern "Rust" {
-    // These are the magic symbols to call the global allocator.  rustc generates
+    // These are the magic symbols to call the global allocator. rustc generates
     // them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
     // (the code expanding that attribute macro generates those functions), or to call
     // the default implementations in std (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
@@ -353,7 +353,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
 
 #[cfg(not(no_global_oom_handling))]
 extern "Rust" {
-    // This is the magic symbol to call the global alloc error handler.  rustc generates
+    // This is the magic symbol to call the global alloc error handler. rustc generates
     // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
     // default implementations below (`__rdl_oom`) otherwise.
     fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs
deleted file mode 100644 (file)
index 4583bc9..0000000
+++ /dev/null
@@ -1,1721 +0,0 @@
-//! A priority queue implemented with a binary heap.
-//!
-//! Insertion and popping the largest element have *O*(log(*n*)) time complexity.
-//! Checking the largest element is *O*(1). Converting a vector to a binary heap
-//! can be done in-place, and has *O*(*n*) complexity. A binary heap can also be
-//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* * log(*n*))
-//! in-place heapsort.
-//!
-//! # Examples
-//!
-//! This is a larger example that implements [Dijkstra's algorithm][dijkstra]
-//! to solve the [shortest path problem][sssp] on a [directed graph][dir_graph].
-//! It shows how to use [`BinaryHeap`] with custom types.
-//!
-//! [dijkstra]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
-//! [sssp]: https://en.wikipedia.org/wiki/Shortest_path_problem
-//! [dir_graph]: https://en.wikipedia.org/wiki/Directed_graph
-//!
-//! ```
-//! use std::cmp::Ordering;
-//! use std::collections::BinaryHeap;
-//!
-//! #[derive(Copy, Clone, Eq, PartialEq)]
-//! struct State {
-//!     cost: usize,
-//!     position: usize,
-//! }
-//!
-//! // The priority queue depends on `Ord`.
-//! // Explicitly implement the trait so the queue becomes a min-heap
-//! // instead of a max-heap.
-//! impl Ord for State {
-//!     fn cmp(&self, other: &Self) -> Ordering {
-//!         // Notice that the we flip the ordering on costs.
-//!         // In case of a tie we compare positions - this step is necessary
-//!         // to make implementations of `PartialEq` and `Ord` consistent.
-//!         other.cost.cmp(&self.cost)
-//!             .then_with(|| self.position.cmp(&other.position))
-//!     }
-//! }
-//!
-//! // `PartialOrd` needs to be implemented as well.
-//! impl PartialOrd for State {
-//!     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-//!         Some(self.cmp(other))
-//!     }
-//! }
-//!
-//! // Each node is represented as a `usize`, for a shorter implementation.
-//! struct Edge {
-//!     node: usize,
-//!     cost: usize,
-//! }
-//!
-//! // Dijkstra's shortest path algorithm.
-//!
-//! // Start at `start` and use `dist` to track the current shortest distance
-//! // to each node. This implementation isn't memory-efficient as it may leave duplicate
-//! // nodes in the queue. It also uses `usize::MAX` as a sentinel value,
-//! // for a simpler implementation.
-//! fn shortest_path(adj_list: &Vec<Vec<Edge>>, start: usize, goal: usize) -> Option<usize> {
-//!     // dist[node] = current shortest distance from `start` to `node`
-//!     let mut dist: Vec<_> = (0..adj_list.len()).map(|_| usize::MAX).collect();
-//!
-//!     let mut heap = BinaryHeap::new();
-//!
-//!     // We're at `start`, with a zero cost
-//!     dist[start] = 0;
-//!     heap.push(State { cost: 0, position: start });
-//!
-//!     // Examine the frontier with lower cost nodes first (min-heap)
-//!     while let Some(State { cost, position }) = heap.pop() {
-//!         // Alternatively we could have continued to find all shortest paths
-//!         if position == goal { return Some(cost); }
-//!
-//!         // Important as we may have already found a better way
-//!         if cost > dist[position] { continue; }
-//!
-//!         // For each node we can reach, see if we can find a way with
-//!         // a lower cost going through this node
-//!         for edge in &adj_list[position] {
-//!             let next = State { cost: cost + edge.cost, position: edge.node };
-//!
-//!             // If so, add it to the frontier and continue
-//!             if next.cost < dist[next.position] {
-//!                 heap.push(next);
-//!                 // Relaxation, we have now found a better way
-//!                 dist[next.position] = next.cost;
-//!             }
-//!         }
-//!     }
-//!
-//!     // Goal not reachable
-//!     None
-//! }
-//!
-//! fn main() {
-//!     // This is the directed graph we're going to use.
-//!     // The node numbers correspond to the different states,
-//!     // and the edge weights symbolize the cost of moving
-//!     // from one node to another.
-//!     // Note that the edges are one-way.
-//!     //
-//!     //                  7
-//!     //          +-----------------+
-//!     //          |                 |
-//!     //          v   1        2    |  2
-//!     //          0 -----> 1 -----> 3 ---> 4
-//!     //          |        ^        ^      ^
-//!     //          |        | 1      |      |
-//!     //          |        |        | 3    | 1
-//!     //          +------> 2 -------+      |
-//!     //           10      |               |
-//!     //                   +---------------+
-//!     //
-//!     // The graph is represented as an adjacency list where each index,
-//!     // corresponding to a node value, has a list of outgoing edges.
-//!     // Chosen for its efficiency.
-//!     let graph = vec![
-//!         // Node 0
-//!         vec![Edge { node: 2, cost: 10 },
-//!              Edge { node: 1, cost: 1 }],
-//!         // Node 1
-//!         vec![Edge { node: 3, cost: 2 }],
-//!         // Node 2
-//!         vec![Edge { node: 1, cost: 1 },
-//!              Edge { node: 3, cost: 3 },
-//!              Edge { node: 4, cost: 1 }],
-//!         // Node 3
-//!         vec![Edge { node: 0, cost: 7 },
-//!              Edge { node: 4, cost: 2 }],
-//!         // Node 4
-//!         vec![]];
-//!
-//!     assert_eq!(shortest_path(&graph, 0, 1), Some(1));
-//!     assert_eq!(shortest_path(&graph, 0, 3), Some(3));
-//!     assert_eq!(shortest_path(&graph, 3, 0), Some(7));
-//!     assert_eq!(shortest_path(&graph, 0, 4), Some(5));
-//!     assert_eq!(shortest_path(&graph, 4, 0), None);
-//! }
-//! ```
-
-#![allow(missing_docs)]
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use core::fmt;
-use core::iter::{FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen};
-use core::mem::{self, swap, ManuallyDrop};
-use core::ops::{Deref, DerefMut};
-use core::ptr;
-
-use crate::collections::TryReserveError;
-use crate::slice;
-use crate::vec::{self, AsVecIntoIter, Vec};
-
-use super::SpecExtend;
-
-#[cfg(test)]
-mod tests;
-
-/// A priority queue implemented with a binary heap.
-///
-/// This will be a max-heap.
-///
-/// 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 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
-/// be encapsulated to the `BinaryHeap` that observed the logic error and not
-/// result in undefined behavior. This could include panics, incorrect results,
-/// aborts, memory leaks, and non-termination.
-///
-/// # Examples
-///
-/// ```
-/// use std::collections::BinaryHeap;
-///
-/// // Type inference lets us omit an explicit type signature (which
-/// // would be `BinaryHeap<i32>` in this example).
-/// let mut heap = BinaryHeap::new();
-///
-/// // We can use peek to look at the next item in the heap. In this case,
-/// // there's no items in there yet so we get None.
-/// assert_eq!(heap.peek(), None);
-///
-/// // Let's add some scores...
-/// heap.push(1);
-/// heap.push(5);
-/// heap.push(2);
-///
-/// // Now peek shows the most important item in the heap.
-/// assert_eq!(heap.peek(), Some(&5));
-///
-/// // We can check the length of a heap.
-/// assert_eq!(heap.len(), 3);
-///
-/// // We can iterate over the items in the heap, although they are returned in
-/// // a random order.
-/// for x in &heap {
-///     println!("{x}");
-/// }
-///
-/// // If we instead pop these scores, they should come back in order.
-/// assert_eq!(heap.pop(), Some(5));
-/// assert_eq!(heap.pop(), Some(2));
-/// assert_eq!(heap.pop(), Some(1));
-/// assert_eq!(heap.pop(), None);
-///
-/// // We can clear the heap of any remaining items.
-/// heap.clear();
-///
-/// // The heap should now be empty.
-/// assert!(heap.is_empty())
-/// ```
-///
-/// A `BinaryHeap` with a known list of items can be initialized from an array:
-///
-/// ```
-/// use std::collections::BinaryHeap;
-///
-/// let heap = BinaryHeap::from([1, 5, 2]);
-/// ```
-///
-/// ## Min-heap
-///
-/// Either [`core::cmp::Reverse`] or a custom [`Ord`] implementation can be used to
-/// make `BinaryHeap` a min-heap. This makes `heap.pop()` return the smallest
-/// value instead of the greatest one.
-///
-/// ```
-/// use std::collections::BinaryHeap;
-/// use std::cmp::Reverse;
-///
-/// let mut heap = BinaryHeap::new();
-///
-/// // Wrap values in `Reverse`
-/// heap.push(Reverse(1));
-/// heap.push(Reverse(5));
-/// heap.push(Reverse(2));
-///
-/// // If we pop these scores now, they should come back in the reverse order.
-/// assert_eq!(heap.pop(), Some(Reverse(1)));
-/// assert_eq!(heap.pop(), Some(Reverse(2)));
-/// assert_eq!(heap.pop(), Some(Reverse(5)));
-/// assert_eq!(heap.pop(), None);
-/// ```
-///
-/// # Time complexity
-///
-/// | [push]  | [pop]         | [peek]/[peek\_mut] |
-/// |---------|---------------|--------------------|
-/// | *O*(1)~ | *O*(log(*n*)) | *O*(1)             |
-///
-/// The value for `push` is an expected cost; the method documentation gives a
-/// more detailed analysis.
-///
-/// [`core::cmp::Reverse`]: core::cmp::Reverse
-/// [`Ord`]: core::cmp::Ord
-/// [`Cell`]: core::cell::Cell
-/// [`RefCell`]: core::cell::RefCell
-/// [push]: BinaryHeap::push
-/// [pop]: BinaryHeap::pop
-/// [peek]: BinaryHeap::peek
-/// [peek\_mut]: BinaryHeap::peek_mut
-#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "BinaryHeap")]
-pub struct BinaryHeap<T> {
-    data: Vec<T>,
-}
-
-/// Structure wrapping a mutable reference to the greatest item on a
-/// `BinaryHeap`.
-///
-/// This `struct` is created by the [`peek_mut`] method on [`BinaryHeap`]. See
-/// its documentation for more.
-///
-/// [`peek_mut`]: BinaryHeap::peek_mut
-#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
-pub struct PeekMut<'a, T: 'a + Ord> {
-    heap: &'a mut BinaryHeap<T>,
-    sift: bool,
-}
-
-#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<T: Ord + fmt::Debug> fmt::Debug for PeekMut<'_, T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("PeekMut").field(&self.heap.data[0]).finish()
-    }
-}
-
-#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
-impl<T: Ord> Drop for PeekMut<'_, T> {
-    fn drop(&mut self) {
-        if self.sift {
-            // SAFETY: PeekMut is only instantiated for non-empty heaps.
-            unsafe { self.heap.sift_down(0) };
-        }
-    }
-}
-
-#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
-impl<T: Ord> Deref for PeekMut<'_, T> {
-    type Target = T;
-    fn deref(&self) -> &T {
-        debug_assert!(!self.heap.is_empty());
-        // SAFE: PeekMut is only instantiated for non-empty heaps
-        unsafe { self.heap.data.get_unchecked(0) }
-    }
-}
-
-#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
-impl<T: Ord> DerefMut for PeekMut<'_, T> {
-    fn deref_mut(&mut self) -> &mut T {
-        debug_assert!(!self.heap.is_empty());
-        self.sift = true;
-        // SAFE: PeekMut is only instantiated for non-empty heaps
-        unsafe { self.heap.data.get_unchecked_mut(0) }
-    }
-}
-
-impl<'a, T: Ord> PeekMut<'a, T> {
-    /// Removes the peeked value from the heap and returns it.
-    #[stable(feature = "binary_heap_peek_mut_pop", since = "1.18.0")]
-    pub fn pop(mut this: PeekMut<'a, T>) -> T {
-        let value = this.heap.pop().unwrap();
-        this.sift = false;
-        value
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Clone> Clone for BinaryHeap<T> {
-    fn clone(&self) -> Self {
-        BinaryHeap { data: self.data.clone() }
-    }
-
-    fn clone_from(&mut self, source: &Self) {
-        self.data.clone_from(&source.data);
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord> Default for BinaryHeap<T> {
-    /// Creates an empty `BinaryHeap<T>`.
-    #[inline]
-    fn default() -> BinaryHeap<T> {
-        BinaryHeap::new()
-    }
-}
-
-#[stable(feature = "binaryheap_debug", since = "1.4.0")]
-impl<T: fmt::Debug> fmt::Debug for BinaryHeap<T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_list().entries(self.iter()).finish()
-    }
-}
-
-impl<T: Ord> BinaryHeap<T> {
-    /// Creates an empty `BinaryHeap` as a max-heap.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::new();
-    /// heap.push(4);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    pub fn new() -> BinaryHeap<T> {
-        BinaryHeap { data: vec![] }
-    }
-
-    /// Creates an empty `BinaryHeap` with at least the specified capacity.
-    ///
-    /// The binary heap will be able to hold at least `capacity` elements without
-    /// reallocating. This method is allowed to allocate for more elements than
-    /// `capacity`. If `capacity` is 0, the binary heap will not allocate.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::with_capacity(10);
-    /// heap.push(4);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    pub fn with_capacity(capacity: usize) -> BinaryHeap<T> {
-        BinaryHeap { data: Vec::with_capacity(capacity) }
-    }
-
-    /// Returns a mutable reference to the greatest item in the binary heap, or
-    /// `None` if it is empty.
-    ///
-    /// Note: If the `PeekMut` value is leaked, the heap may be in an
-    /// inconsistent state.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::new();
-    /// assert!(heap.peek_mut().is_none());
-    ///
-    /// heap.push(1);
-    /// heap.push(5);
-    /// heap.push(2);
-    /// {
-    ///     let mut val = heap.peek_mut().unwrap();
-    ///     *val = 0;
-    /// }
-    /// assert_eq!(heap.peek(), Some(&2));
-    /// ```
-    ///
-    /// # Time complexity
-    ///
-    /// If the item is modified then the worst case time complexity is *O*(log(*n*)),
-    /// otherwise it's *O*(1).
-    #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
-    pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
-        if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: false }) }
-    }
-
-    /// Removes the greatest item from the binary heap and returns it, or `None` if it
-    /// is empty.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::from([1, 3]);
-    ///
-    /// assert_eq!(heap.pop(), Some(3));
-    /// assert_eq!(heap.pop(), Some(1));
-    /// assert_eq!(heap.pop(), None);
-    /// ```
-    ///
-    /// # Time complexity
-    ///
-    /// The worst case cost of `pop` on a heap containing *n* elements is *O*(log(*n*)).
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn pop(&mut self) -> Option<T> {
-        self.data.pop().map(|mut item| {
-            if !self.is_empty() {
-                swap(&mut item, &mut self.data[0]);
-                // SAFETY: !self.is_empty() means that self.len() > 0
-                unsafe { self.sift_down_to_bottom(0) };
-            }
-            item
-        })
-    }
-
-    /// Pushes an item onto the binary heap.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::new();
-    /// heap.push(3);
-    /// heap.push(5);
-    /// heap.push(1);
-    ///
-    /// assert_eq!(heap.len(), 3);
-    /// assert_eq!(heap.peek(), Some(&5));
-    /// ```
-    ///
-    /// # Time complexity
-    ///
-    /// The expected cost of `push`, averaged over every possible ordering of
-    /// the elements being pushed, and over a sufficiently large number of
-    /// pushes, is *O*(1). This is the most meaningful cost metric when pushing
-    /// elements that are *not* already in any sorted pattern.
-    ///
-    /// The time complexity degrades if elements are pushed in predominantly
-    /// ascending order. In the worst case, elements are pushed in ascending
-    /// sorted order and the amortized cost per push is *O*(log(*n*)) against a heap
-    /// containing *n* elements.
-    ///
-    /// The worst case cost of a *single* call to `push` is *O*(*n*). The worst case
-    /// occurs when capacity is exhausted and needs a resize. The resize cost
-    /// has been amortized in the previous figures.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn push(&mut self, item: T) {
-        let old_len = self.len();
-        self.data.push(item);
-        // SAFETY: Since we pushed a new item it means that
-        //  old_len = self.len() - 1 < self.len()
-        unsafe { self.sift_up(0, old_len) };
-    }
-
-    /// Consumes the `BinaryHeap` and returns a vector in sorted
-    /// (ascending) order.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    ///
-    /// let mut heap = BinaryHeap::from([1, 2, 4, 5, 7]);
-    /// heap.push(6);
-    /// heap.push(3);
-    ///
-    /// let vec = heap.into_sorted_vec();
-    /// assert_eq!(vec, [1, 2, 3, 4, 5, 6, 7]);
-    /// ```
-    #[must_use = "`self` will be dropped if the result is not used"]
-    #[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
-    pub fn into_sorted_vec(mut self) -> Vec<T> {
-        let mut end = self.len();
-        while end > 1 {
-            end -= 1;
-            // SAFETY: `end` goes from `self.len() - 1` to 1 (both included),
-            //  so it's always a valid index to access.
-            //  It is safe to access index 0 (i.e. `ptr`), because
-            //  1 <= end < self.len(), which means self.len() >= 2.
-            unsafe {
-                let ptr = self.data.as_mut_ptr();
-                ptr::swap(ptr, ptr.add(end));
-            }
-            // SAFETY: `end` goes from `self.len() - 1` to 1 (both included) so:
-            //  0 < 1 <= end <= self.len() - 1 < self.len()
-            //  Which means 0 < end and end < self.len().
-            unsafe { self.sift_down_range(0, end) };
-        }
-        self.into_vec()
-    }
-
-    // The implementations of sift_up and sift_down use unsafe blocks in
-    // order to move an element out of the vector (leaving behind a
-    // hole), shift along the others and move the removed element back into the
-    // vector at the final location of the hole.
-    // The `Hole` type is used to represent this, and make sure
-    // the hole is filled back at the end of its scope, even on panic.
-    // Using a hole reduces the constant factor compared to using swaps,
-    // which involves twice as many moves.
-
-    /// # Safety
-    ///
-    /// The caller must guarantee that `pos < self.len()`.
-    unsafe fn sift_up(&mut self, start: usize, pos: usize) -> usize {
-        // Take out the value at `pos` and create a hole.
-        // SAFETY: The caller guarantees that pos < self.len()
-        let mut hole = unsafe { Hole::new(&mut self.data, pos) };
-
-        while hole.pos() > start {
-            let parent = (hole.pos() - 1) / 2;
-
-            // SAFETY: hole.pos() > start >= 0, which means hole.pos() > 0
-            //  and so hole.pos() - 1 can't underflow.
-            //  This guarantees that parent < hole.pos() so
-            //  it's a valid index and also != hole.pos().
-            if hole.element() <= unsafe { hole.get(parent) } {
-                break;
-            }
-
-            // SAFETY: Same as above
-            unsafe { hole.move_to(parent) };
-        }
-
-        hole.pos()
-    }
-
-    /// Take an element at `pos` and move it down the heap,
-    /// while its children are larger.
-    ///
-    /// # Safety
-    ///
-    /// The caller must guarantee that `pos < end <= self.len()`.
-    unsafe fn sift_down_range(&mut self, pos: usize, end: usize) {
-        // SAFETY: The caller guarantees that pos < end <= self.len().
-        let mut hole = unsafe { Hole::new(&mut self.data, pos) };
-        let mut child = 2 * hole.pos() + 1;
-
-        // Loop invariant: child == 2 * hole.pos() + 1.
-        while child <= end.saturating_sub(2) {
-            // compare with the greater of the two children
-            // SAFETY: child < end - 1 < self.len() and
-            //  child + 1 < end <= self.len(), so they're valid indexes.
-            //  child == 2 * hole.pos() + 1 != hole.pos() and
-            //  child + 1 == 2 * hole.pos() + 2 != hole.pos().
-            // FIXME: 2 * hole.pos() + 1 or 2 * hole.pos() + 2 could overflow
-            //  if T is a ZST
-            child += unsafe { hole.get(child) <= hole.get(child + 1) } as usize;
-
-            // if we are already in order, stop.
-            // SAFETY: child is now either the old child or the old child+1
-            //  We already proven that both are < self.len() and != hole.pos()
-            if hole.element() >= unsafe { hole.get(child) } {
-                return;
-            }
-
-            // SAFETY: same as above.
-            unsafe { hole.move_to(child) };
-            child = 2 * hole.pos() + 1;
-        }
-
-        // SAFETY: && short circuit, which means that in the
-        //  second condition it's already true that child == end - 1 < self.len().
-        if child == end - 1 && hole.element() < unsafe { hole.get(child) } {
-            // SAFETY: child is already proven to be a valid index and
-            //  child == 2 * hole.pos() + 1 != hole.pos().
-            unsafe { hole.move_to(child) };
-        }
-    }
-
-    /// # Safety
-    ///
-    /// The caller must guarantee that `pos < self.len()`.
-    unsafe fn sift_down(&mut self, pos: usize) {
-        let len = self.len();
-        // SAFETY: pos < len is guaranteed by the caller and
-        //  obviously len = self.len() <= self.len().
-        unsafe { self.sift_down_range(pos, len) };
-    }
-
-    /// Take an element at `pos` and move it all the way down the heap,
-    /// then sift it up to its position.
-    ///
-    /// Note: This is faster when the element is known to be large / should
-    /// be closer to the bottom.
-    ///
-    /// # Safety
-    ///
-    /// The caller must guarantee that `pos < self.len()`.
-    unsafe fn sift_down_to_bottom(&mut self, mut pos: usize) {
-        let end = self.len();
-        let start = pos;
-
-        // SAFETY: The caller guarantees that pos < self.len().
-        let mut hole = unsafe { Hole::new(&mut self.data, pos) };
-        let mut child = 2 * hole.pos() + 1;
-
-        // Loop invariant: child == 2 * hole.pos() + 1.
-        while child <= end.saturating_sub(2) {
-            // SAFETY: child < end - 1 < self.len() and
-            //  child + 1 < end <= self.len(), so they're valid indexes.
-            //  child == 2 * hole.pos() + 1 != hole.pos() and
-            //  child + 1 == 2 * hole.pos() + 2 != hole.pos().
-            // FIXME: 2 * hole.pos() + 1 or 2 * hole.pos() + 2 could overflow
-            //  if T is a ZST
-            child += unsafe { hole.get(child) <= hole.get(child + 1) } as usize;
-
-            // SAFETY: Same as above
-            unsafe { hole.move_to(child) };
-            child = 2 * hole.pos() + 1;
-        }
-
-        if child == end - 1 {
-            // SAFETY: child == end - 1 < self.len(), so it's a valid index
-            //  and child == 2 * hole.pos() + 1 != hole.pos().
-            unsafe { hole.move_to(child) };
-        }
-        pos = hole.pos();
-        drop(hole);
-
-        // SAFETY: pos is the position in the hole and was already proven
-        //  to be a valid index.
-        unsafe { self.sift_up(start, pos) };
-    }
-
-    /// Rebuild assuming data[0..start] is still a proper heap.
-    fn rebuild_tail(&mut self, start: usize) {
-        if start == self.len() {
-            return;
-        }
-
-        let tail_len = self.len() - start;
-
-        #[inline(always)]
-        fn log2_fast(x: usize) -> usize {
-            (usize::BITS - x.leading_zeros() - 1) as usize
-        }
-
-        // `rebuild` takes O(self.len()) operations
-        // and about 2 * self.len() comparisons in the worst case
-        // while repeating `sift_up` takes O(tail_len * log(start)) operations
-        // and about 1 * tail_len * log_2(start) comparisons in the worst case,
-        // assuming start >= tail_len. For larger heaps, the crossover point
-        // no longer follows this reasoning and was determined empirically.
-        let better_to_rebuild = if start < tail_len {
-            true
-        } else if self.len() <= 2048 {
-            2 * self.len() < tail_len * log2_fast(start)
-        } else {
-            2 * self.len() < tail_len * 11
-        };
-
-        if better_to_rebuild {
-            self.rebuild();
-        } else {
-            for i in start..self.len() {
-                // SAFETY: The index `i` is always less than self.len().
-                unsafe { self.sift_up(0, i) };
-            }
-        }
-    }
-
-    fn rebuild(&mut self) {
-        let mut n = self.len() / 2;
-        while n > 0 {
-            n -= 1;
-            // SAFETY: n starts from self.len() / 2 and goes down to 0.
-            //  The only case when !(n < self.len()) is if
-            //  self.len() == 0, but it's ruled out by the loop condition.
-            unsafe { self.sift_down(n) };
-        }
-    }
-
-    /// Moves all the elements of `other` into `self`, leaving `other` empty.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    ///
-    /// let mut a = BinaryHeap::from([-10, 1, 2, 3, 3]);
-    /// let mut b = BinaryHeap::from([-20, 5, 43]);
-    ///
-    /// a.append(&mut b);
-    ///
-    /// assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
-    /// assert!(b.is_empty());
-    /// ```
-    #[stable(feature = "binary_heap_append", since = "1.11.0")]
-    pub fn append(&mut self, other: &mut Self) {
-        if self.len() < other.len() {
-            swap(self, other);
-        }
-
-        let start = self.data.len();
-
-        self.data.append(&mut other.data);
-
-        self.rebuild_tail(start);
-    }
-
-    /// Clears the binary heap, returning an iterator over the removed elements
-    /// in heap order. If the iterator is dropped before being fully consumed,
-    /// it drops the remaining elements in heap order.
-    ///
-    /// The returned iterator keeps a mutable borrow on the heap to optimize
-    /// its implementation.
-    ///
-    /// Note:
-    /// * `.drain_sorted()` is *O*(*n* \* log(*n*)); much slower than `.drain()`.
-    ///   You should use the latter for most cases.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// #![feature(binary_heap_drain_sorted)]
-    /// use std::collections::BinaryHeap;
-    ///
-    /// let mut heap = BinaryHeap::from([1, 2, 3, 4, 5]);
-    /// assert_eq!(heap.len(), 5);
-    ///
-    /// drop(heap.drain_sorted()); // removes all elements in heap order
-    /// assert_eq!(heap.len(), 0);
-    /// ```
-    #[inline]
-    #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
-    pub fn drain_sorted(&mut self) -> DrainSorted<'_, T> {
-        DrainSorted { inner: self }
-    }
-
-    /// Retains only the elements specified by the predicate.
-    ///
-    /// In other words, remove all elements `e` for which `f(&e)` returns
-    /// `false`. The elements are visited in unsorted (and unspecified) order.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// #![feature(binary_heap_retain)]
-    /// use std::collections::BinaryHeap;
-    ///
-    /// let mut heap = BinaryHeap::from([-10, -5, 1, 2, 4, 13]);
-    ///
-    /// heap.retain(|x| x % 2 == 0); // only keep even numbers
-    ///
-    /// assert_eq!(heap.into_sorted_vec(), [-10, 2, 4])
-    /// ```
-    #[unstable(feature = "binary_heap_retain", issue = "71503")]
-    pub fn retain<F>(&mut self, mut f: F)
-    where
-        F: FnMut(&T) -> bool,
-    {
-        let mut first_removed = self.len();
-        let mut i = 0;
-        self.data.retain(|e| {
-            let keep = f(e);
-            if !keep && i < first_removed {
-                first_removed = i;
-            }
-            i += 1;
-            keep
-        });
-        // data[0..first_removed] is untouched, so we only need to rebuild the tail:
-        self.rebuild_tail(first_removed);
-    }
-}
-
-impl<T> BinaryHeap<T> {
-    /// Returns an iterator visiting all values in the underlying vector, in
-    /// arbitrary order.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let heap = BinaryHeap::from([1, 2, 3, 4]);
-    ///
-    /// // Print 1, 2, 3, 4 in arbitrary order
-    /// for x in heap.iter() {
-    ///     println!("{x}");
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn iter(&self) -> Iter<'_, T> {
-        Iter { iter: self.data.iter() }
-    }
-
-    /// Returns an iterator which retrieves elements in heap order.
-    /// This method consumes the original heap.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// #![feature(binary_heap_into_iter_sorted)]
-    /// use std::collections::BinaryHeap;
-    /// let heap = BinaryHeap::from([1, 2, 3, 4, 5]);
-    ///
-    /// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), [5, 4]);
-    /// ```
-    #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
-    pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
-        IntoIterSorted { inner: self }
-    }
-
-    /// Returns the greatest item in the binary heap, or `None` if it is empty.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::new();
-    /// assert_eq!(heap.peek(), None);
-    ///
-    /// heap.push(1);
-    /// heap.push(5);
-    /// heap.push(2);
-    /// assert_eq!(heap.peek(), Some(&5));
-    ///
-    /// ```
-    ///
-    /// # Time complexity
-    ///
-    /// Cost is *O*(1) in the worst case.
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn peek(&self) -> Option<&T> {
-        self.data.get(0)
-    }
-
-    /// Returns the number of elements the binary heap can hold without reallocating.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::with_capacity(100);
-    /// assert!(heap.capacity() >= 100);
-    /// heap.push(4);
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn capacity(&self) -> usize {
-        self.data.capacity()
-    }
-
-    /// Reserves the minimum capacity for at least `additional` elements more than
-    /// the current length. Unlike [`reserve`], this will not
-    /// deliberately over-allocate to speculatively avoid frequent allocations.
-    /// After calling `reserve_exact`, capacity will be greater than or equal to
-    /// `self.len() + additional`. Does nothing if the capacity is already
-    /// sufficient.
-    ///
-    /// [`reserve`]: BinaryHeap::reserve
-    ///
-    /// # Panics
-    ///
-    /// Panics if the new capacity overflows [`usize`].
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::new();
-    /// heap.reserve_exact(100);
-    /// assert!(heap.capacity() >= 100);
-    /// heap.push(4);
-    /// ```
-    ///
-    /// [`reserve`]: BinaryHeap::reserve
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn reserve_exact(&mut self, additional: usize) {
-        self.data.reserve_exact(additional);
-    }
-
-    /// Reserves capacity for at least `additional` elements more than the
-    /// current length. The allocator may reserve more space to speculatively
-    /// avoid frequent allocations. After calling `reserve`,
-    /// capacity will be greater than or equal to `self.len() + additional`.
-    /// Does nothing if capacity is already sufficient.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the new capacity overflows [`usize`].
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::new();
-    /// heap.reserve(100);
-    /// assert!(heap.capacity() >= 100);
-    /// heap.push(4);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn reserve(&mut self, additional: usize) {
-        self.data.reserve(additional);
-    }
-
-    /// Tries to reserve the minimum capacity for at least `additional` elements
-    /// more than the current length. Unlike [`try_reserve`], this will not
-    /// deliberately over-allocate to speculatively avoid frequent allocations.
-    /// After calling `try_reserve_exact`, capacity will be greater than or
-    /// equal to `self.len() + additional` if it returns `Ok(())`.
-    /// Does nothing if the capacity is already sufficient.
-    ///
-    /// Note that the allocator may give the collection more space than it
-    /// requests. Therefore, capacity can not be relied upon to be precisely
-    /// minimal. Prefer [`try_reserve`] if future insertions are expected.
-    ///
-    /// [`try_reserve`]: BinaryHeap::try_reserve
-    ///
-    /// # Errors
-    ///
-    /// If the capacity overflows, or the allocator reports a failure, then an error
-    /// is returned.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// use std::collections::TryReserveError;
-    ///
-    /// fn find_max_slow(data: &[u32]) -> Result<Option<u32>, TryReserveError> {
-    ///     let mut heap = BinaryHeap::new();
-    ///
-    ///     // Pre-reserve the memory, exiting if we can't
-    ///     heap.try_reserve_exact(data.len())?;
-    ///
-    ///     // Now we know this can't OOM in the middle of our complex work
-    ///     heap.extend(data.iter());
-    ///
-    ///     Ok(heap.pop())
-    /// }
-    /// # find_max_slow(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
-    /// ```
-    #[stable(feature = "try_reserve_2", since = "1.63.0")]
-    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
-        self.data.try_reserve_exact(additional)
-    }
-
-    /// Tries to reserve capacity for at least `additional` elements more than the
-    /// current length. The allocator may reserve more space to speculatively
-    /// avoid frequent allocations. After calling `try_reserve`, capacity will be
-    /// greater than or equal to `self.len() + additional` if it returns
-    /// `Ok(())`. Does nothing if capacity is already sufficient. This method
-    /// preserves the contents even if an error occurs.
-    ///
-    /// # Errors
-    ///
-    /// If the capacity overflows, or the allocator reports a failure, then an error
-    /// is returned.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// use std::collections::TryReserveError;
-    ///
-    /// fn find_max_slow(data: &[u32]) -> Result<Option<u32>, TryReserveError> {
-    ///     let mut heap = BinaryHeap::new();
-    ///
-    ///     // Pre-reserve the memory, exiting if we can't
-    ///     heap.try_reserve(data.len())?;
-    ///
-    ///     // Now we know this can't OOM in the middle of our complex work
-    ///     heap.extend(data.iter());
-    ///
-    ///     Ok(heap.pop())
-    /// }
-    /// # find_max_slow(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
-    /// ```
-    #[stable(feature = "try_reserve_2", since = "1.63.0")]
-    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
-        self.data.try_reserve(additional)
-    }
-
-    /// Discards as much additional capacity as possible.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let mut heap: BinaryHeap<i32> = BinaryHeap::with_capacity(100);
-    ///
-    /// assert!(heap.capacity() >= 100);
-    /// heap.shrink_to_fit();
-    /// assert!(heap.capacity() == 0);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn shrink_to_fit(&mut self) {
-        self.data.shrink_to_fit();
-    }
-
-    /// Discards capacity with a lower bound.
-    ///
-    /// The capacity will remain at least as large as both the length
-    /// and the supplied value.
-    ///
-    /// If the current capacity is less than the lower limit, this is a no-op.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let mut heap: BinaryHeap<i32> = BinaryHeap::with_capacity(100);
-    ///
-    /// assert!(heap.capacity() >= 100);
-    /// heap.shrink_to(10);
-    /// assert!(heap.capacity() >= 10);
-    /// ```
-    #[inline]
-    #[stable(feature = "shrink_to", since = "1.56.0")]
-    pub fn shrink_to(&mut self, min_capacity: usize) {
-        self.data.shrink_to(min_capacity)
-    }
-
-    /// Returns a slice of all values in the underlying vector, in arbitrary
-    /// order.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// #![feature(binary_heap_as_slice)]
-    /// use std::collections::BinaryHeap;
-    /// use std::io::{self, Write};
-    ///
-    /// let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]);
-    ///
-    /// io::sink().write(heap.as_slice()).unwrap();
-    /// ```
-    #[must_use]
-    #[unstable(feature = "binary_heap_as_slice", issue = "83659")]
-    pub fn as_slice(&self) -> &[T] {
-        self.data.as_slice()
-    }
-
-    /// Consumes the `BinaryHeap` and returns the underlying vector
-    /// in arbitrary order.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]);
-    /// let vec = heap.into_vec();
-    ///
-    /// // Will print in some order
-    /// for x in vec {
-    ///     println!("{x}");
-    /// }
-    /// ```
-    #[must_use = "`self` will be dropped if the result is not used"]
-    #[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
-    pub fn into_vec(self) -> Vec<T> {
-        self.into()
-    }
-
-    /// Returns the length of the binary heap.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let heap = BinaryHeap::from([1, 3]);
-    ///
-    /// assert_eq!(heap.len(), 2);
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn len(&self) -> usize {
-        self.data.len()
-    }
-
-    /// Checks if the binary heap is empty.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::new();
-    ///
-    /// assert!(heap.is_empty());
-    ///
-    /// heap.push(3);
-    /// heap.push(5);
-    /// heap.push(1);
-    ///
-    /// assert!(!heap.is_empty());
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn is_empty(&self) -> bool {
-        self.len() == 0
-    }
-
-    /// Clears the binary heap, returning an iterator over the removed elements
-    /// in arbitrary order. If the iterator is dropped before being fully
-    /// consumed, it drops the remaining elements in arbitrary order.
-    ///
-    /// The returned iterator keeps a mutable borrow on the heap to optimize
-    /// its implementation.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::from([1, 3]);
-    ///
-    /// assert!(!heap.is_empty());
-    ///
-    /// for x in heap.drain() {
-    ///     println!("{x}");
-    /// }
-    ///
-    /// assert!(heap.is_empty());
-    /// ```
-    #[inline]
-    #[stable(feature = "drain", since = "1.6.0")]
-    pub fn drain(&mut self) -> Drain<'_, T> {
-        Drain { iter: self.data.drain(..) }
-    }
-
-    /// Drops all items from the binary heap.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::from([1, 3]);
-    ///
-    /// assert!(!heap.is_empty());
-    ///
-    /// heap.clear();
-    ///
-    /// assert!(heap.is_empty());
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn clear(&mut self) {
-        self.drain();
-    }
-}
-
-/// Hole represents a hole in a slice i.e., an index without valid value
-/// (because it was moved from or duplicated).
-/// In drop, `Hole` will restore the slice by filling the hole
-/// position with the value that was originally removed.
-struct Hole<'a, T: 'a> {
-    data: &'a mut [T],
-    elt: ManuallyDrop<T>,
-    pos: usize,
-}
-
-impl<'a, T> Hole<'a, T> {
-    /// Create a new `Hole` at index `pos`.
-    ///
-    /// Unsafe because pos must be within the data slice.
-    #[inline]
-    unsafe fn new(data: &'a mut [T], pos: usize) -> Self {
-        debug_assert!(pos < data.len());
-        // SAFE: pos should be inside the slice
-        let elt = unsafe { ptr::read(data.get_unchecked(pos)) };
-        Hole { data, elt: ManuallyDrop::new(elt), pos }
-    }
-
-    #[inline]
-    fn pos(&self) -> usize {
-        self.pos
-    }
-
-    /// Returns a reference to the element removed.
-    #[inline]
-    fn element(&self) -> &T {
-        &self.elt
-    }
-
-    /// Returns a reference to the element at `index`.
-    ///
-    /// Unsafe because index must be within the data slice and not equal to pos.
-    #[inline]
-    unsafe fn get(&self, index: usize) -> &T {
-        debug_assert!(index != self.pos);
-        debug_assert!(index < self.data.len());
-        unsafe { self.data.get_unchecked(index) }
-    }
-
-    /// Move hole to new location
-    ///
-    /// Unsafe because index must be within the data slice and not equal to pos.
-    #[inline]
-    unsafe fn move_to(&mut self, index: usize) {
-        debug_assert!(index != self.pos);
-        debug_assert!(index < self.data.len());
-        unsafe {
-            let ptr = self.data.as_mut_ptr();
-            let index_ptr: *const _ = ptr.add(index);
-            let hole_ptr = ptr.add(self.pos);
-            ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
-        }
-        self.pos = index;
-    }
-}
-
-impl<T> Drop for Hole<'_, T> {
-    #[inline]
-    fn drop(&mut self) {
-        // fill the hole again
-        unsafe {
-            let pos = self.pos;
-            ptr::copy_nonoverlapping(&*self.elt, self.data.get_unchecked_mut(pos), 1);
-        }
-    }
-}
-
-/// An iterator over the elements of a `BinaryHeap`.
-///
-/// This `struct` is created by [`BinaryHeap::iter()`]. See its
-/// documentation for more.
-///
-/// [`iter`]: BinaryHeap::iter
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Iter<'a, T: 'a> {
-    iter: slice::Iter<'a, T>,
-}
-
-#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("Iter").field(&self.iter.as_slice()).finish()
-    }
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Clone for Iter<'_, T> {
-    fn clone(&self) -> Self {
-        Iter { iter: self.iter.clone() }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> Iterator for Iter<'a, T> {
-    type Item = &'a T;
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a T> {
-        self.iter.next()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-
-    #[inline]
-    fn last(self) -> Option<&'a T> {
-        self.iter.last()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a T> {
-        self.iter.next_back()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ExactSizeIterator for Iter<'_, T> {
-    fn is_empty(&self) -> bool {
-        self.iter.is_empty()
-    }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for Iter<'_, T> {}
-
-/// An owning iterator over the elements of a `BinaryHeap`.
-///
-/// This `struct` is created by [`BinaryHeap::into_iter()`]
-/// (provided by the [`IntoIterator`] trait). See its documentation for more.
-///
-/// [`into_iter`]: BinaryHeap::into_iter
-/// [`IntoIterator`]: core::iter::IntoIterator
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone)]
-pub struct IntoIter<T> {
-    iter: vec::IntoIter<T>,
-}
-
-#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("IntoIter").field(&self.iter.as_slice()).finish()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Iterator for IntoIter<T> {
-    type Item = T;
-
-    #[inline]
-    fn next(&mut self) -> Option<T> {
-        self.iter.next()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> DoubleEndedIterator for IntoIter<T> {
-    #[inline]
-    fn next_back(&mut self) -> Option<T> {
-        self.iter.next_back()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ExactSizeIterator for IntoIter<T> {
-    fn is_empty(&self) -> bool {
-        self.iter.is_empty()
-    }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for IntoIter<T> {}
-
-// In addition to the SAFETY invariants of the following three unsafe traits
-// also refer to the vec::in_place_collect module documentation to get an overview
-#[unstable(issue = "none", feature = "inplace_iteration")]
-#[doc(hidden)]
-unsafe impl<T> SourceIter for IntoIter<T> {
-    type Source = IntoIter<T>;
-
-    #[inline]
-    unsafe fn as_inner(&mut self) -> &mut Self::Source {
-        self
-    }
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-#[doc(hidden)]
-unsafe impl<I> InPlaceIterable for IntoIter<I> {}
-
-unsafe impl<I> AsVecIntoIter for IntoIter<I> {
-    type Item = I;
-
-    fn as_into_iter(&mut self) -> &mut vec::IntoIter<Self::Item> {
-        &mut self.iter
-    }
-}
-
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
-#[derive(Clone, Debug)]
-pub struct IntoIterSorted<T> {
-    inner: BinaryHeap<T>,
-}
-
-#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
-impl<T: Ord> Iterator for IntoIterSorted<T> {
-    type Item = T;
-
-    #[inline]
-    fn next(&mut self) -> Option<T> {
-        self.inner.pop()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let exact = self.inner.len();
-        (exact, Some(exact))
-    }
-}
-
-#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
-impl<T: Ord> ExactSizeIterator for IntoIterSorted<T> {}
-
-#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
-impl<T: Ord> FusedIterator for IntoIterSorted<T> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T: Ord> TrustedLen for IntoIterSorted<T> {}
-
-/// A draining iterator over the elements of a `BinaryHeap`.
-///
-/// This `struct` is created by [`BinaryHeap::drain()`]. See its
-/// documentation for more.
-///
-/// [`drain`]: BinaryHeap::drain
-#[stable(feature = "drain", since = "1.6.0")]
-#[derive(Debug)]
-pub struct Drain<'a, T: 'a> {
-    iter: vec::Drain<'a, T>,
-}
-
-#[stable(feature = "drain", since = "1.6.0")]
-impl<T> Iterator for Drain<'_, T> {
-    type Item = T;
-
-    #[inline]
-    fn next(&mut self) -> Option<T> {
-        self.iter.next()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-#[stable(feature = "drain", since = "1.6.0")]
-impl<T> DoubleEndedIterator for Drain<'_, T> {
-    #[inline]
-    fn next_back(&mut self) -> Option<T> {
-        self.iter.next_back()
-    }
-}
-
-#[stable(feature = "drain", since = "1.6.0")]
-impl<T> ExactSizeIterator for Drain<'_, T> {
-    fn is_empty(&self) -> bool {
-        self.iter.is_empty()
-    }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for Drain<'_, T> {}
-
-/// A draining iterator over the elements of a `BinaryHeap`.
-///
-/// This `struct` is created by [`BinaryHeap::drain_sorted()`]. See its
-/// documentation for more.
-///
-/// [`drain_sorted`]: BinaryHeap::drain_sorted
-#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
-#[derive(Debug)]
-pub struct DrainSorted<'a, T: Ord> {
-    inner: &'a mut BinaryHeap<T>,
-}
-
-#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
-impl<'a, T: Ord> Drop for DrainSorted<'a, T> {
-    /// Removes heap elements in heap order.
-    fn drop(&mut self) {
-        struct DropGuard<'r, 'a, T: Ord>(&'r mut DrainSorted<'a, T>);
-
-        impl<'r, 'a, T: Ord> Drop for DropGuard<'r, 'a, T> {
-            fn drop(&mut self) {
-                while self.0.inner.pop().is_some() {}
-            }
-        }
-
-        while let Some(item) = self.inner.pop() {
-            let guard = DropGuard(self);
-            drop(item);
-            mem::forget(guard);
-        }
-    }
-}
-
-#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
-impl<T: Ord> Iterator for DrainSorted<'_, T> {
-    type Item = T;
-
-    #[inline]
-    fn next(&mut self) -> Option<T> {
-        self.inner.pop()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let exact = self.inner.len();
-        (exact, Some(exact))
-    }
-}
-
-#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
-impl<T: Ord> ExactSizeIterator for DrainSorted<'_, T> {}
-
-#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
-impl<T: Ord> FusedIterator for DrainSorted<'_, T> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T: Ord> TrustedLen for DrainSorted<'_, T> {}
-
-#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
-impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
-    /// Converts a `Vec<T>` into a `BinaryHeap<T>`.
-    ///
-    /// This conversion happens in-place, and has *O*(*n*) time complexity.
-    fn from(vec: Vec<T>) -> BinaryHeap<T> {
-        let mut heap = BinaryHeap { data: vec };
-        heap.rebuild();
-        heap
-    }
-}
-
-#[stable(feature = "std_collections_from_array", since = "1.56.0")]
-impl<T: Ord, const N: usize> From<[T; N]> for BinaryHeap<T> {
-    /// ```
-    /// use std::collections::BinaryHeap;
-    ///
-    /// let mut h1 = BinaryHeap::from([1, 4, 2, 3]);
-    /// let mut h2: BinaryHeap<_> = [1, 4, 2, 3].into();
-    /// while let Some((a, b)) = h1.pop().zip(h2.pop()) {
-    ///     assert_eq!(a, b);
-    /// }
-    /// ```
-    fn from(arr: [T; N]) -> Self {
-        Self::from_iter(arr)
-    }
-}
-
-#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
-impl<T> From<BinaryHeap<T>> for Vec<T> {
-    /// Converts a `BinaryHeap<T>` into a `Vec<T>`.
-    ///
-    /// This conversion requires no data movement or allocation, and has
-    /// constant time complexity.
-    fn from(heap: BinaryHeap<T>) -> Vec<T> {
-        heap.data
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord> FromIterator<T> for BinaryHeap<T> {
-    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> BinaryHeap<T> {
-        BinaryHeap::from(iter.into_iter().collect::<Vec<_>>())
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> IntoIterator for BinaryHeap<T> {
-    type Item = T;
-    type IntoIter = IntoIter<T>;
-
-    /// Creates a consuming iterator, that is, one that moves each value out of
-    /// the binary heap in arbitrary order. The binary heap cannot be used
-    /// after calling this.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::collections::BinaryHeap;
-    /// let heap = BinaryHeap::from([1, 2, 3, 4]);
-    ///
-    /// // Print 1, 2, 3, 4 in arbitrary order
-    /// for x in heap.into_iter() {
-    ///     // x has type i32, not &i32
-    ///     println!("{x}");
-    /// }
-    /// ```
-    fn into_iter(self) -> IntoIter<T> {
-        IntoIter { iter: self.data.into_iter() }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> IntoIterator for &'a BinaryHeap<T> {
-    type Item = &'a T;
-    type IntoIter = Iter<'a, T>;
-
-    fn into_iter(self) -> Iter<'a, T> {
-        self.iter()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord> Extend<T> for BinaryHeap<T> {
-    #[inline]
-    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
-        <Self as SpecExtend<I>>::spec_extend(self, iter);
-    }
-
-    #[inline]
-    fn extend_one(&mut self, item: T) {
-        self.push(item);
-    }
-
-    #[inline]
-    fn extend_reserve(&mut self, additional: usize) {
-        self.reserve(additional);
-    }
-}
-
-impl<T: Ord, I: IntoIterator<Item = T>> SpecExtend<I> for BinaryHeap<T> {
-    default fn spec_extend(&mut self, iter: I) {
-        self.extend_desugared(iter.into_iter());
-    }
-}
-
-impl<T: Ord> SpecExtend<Vec<T>> for BinaryHeap<T> {
-    fn spec_extend(&mut self, ref mut other: Vec<T>) {
-        let start = self.data.len();
-        self.data.append(other);
-        self.rebuild_tail(start);
-    }
-}
-
-impl<T: Ord> SpecExtend<BinaryHeap<T>> for BinaryHeap<T> {
-    fn spec_extend(&mut self, ref mut other: BinaryHeap<T>) {
-        self.append(other);
-    }
-}
-
-impl<T: Ord> BinaryHeap<T> {
-    fn extend_desugared<I: IntoIterator<Item = T>>(&mut self, iter: I) {
-        let iterator = iter.into_iter();
-        let (lower, _) = iterator.size_hint();
-
-        self.reserve(lower);
-
-        iterator.for_each(move |elem| self.push(elem));
-    }
-}
-
-#[stable(feature = "extend_ref", since = "1.2.0")]
-impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap<T> {
-    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
-        self.extend(iter.into_iter().cloned());
-    }
-
-    #[inline]
-    fn extend_one(&mut self, &item: &'a T) {
-        self.push(item);
-    }
-
-    #[inline]
-    fn extend_reserve(&mut self, additional: usize) {
-        self.reserve(additional);
-    }
-}
diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs
new file mode 100644 (file)
index 0000000..0b73b1a
--- /dev/null
@@ -0,0 +1,1766 @@
+//! A priority queue implemented with a binary heap.
+//!
+//! Insertion and popping the largest element have *O*(log(*n*)) time complexity.
+//! Checking the largest element is *O*(1). Converting a vector to a binary heap
+//! can be done in-place, and has *O*(*n*) complexity. A binary heap can also be
+//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* * log(*n*))
+//! in-place heapsort.
+//!
+//! # Examples
+//!
+//! This is a larger example that implements [Dijkstra's algorithm][dijkstra]
+//! to solve the [shortest path problem][sssp] on a [directed graph][dir_graph].
+//! It shows how to use [`BinaryHeap`] with custom types.
+//!
+//! [dijkstra]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
+//! [sssp]: https://en.wikipedia.org/wiki/Shortest_path_problem
+//! [dir_graph]: https://en.wikipedia.org/wiki/Directed_graph
+//!
+//! ```
+//! use std::cmp::Ordering;
+//! use std::collections::BinaryHeap;
+//!
+//! #[derive(Copy, Clone, Eq, PartialEq)]
+//! struct State {
+//!     cost: usize,
+//!     position: usize,
+//! }
+//!
+//! // The priority queue depends on `Ord`.
+//! // Explicitly implement the trait so the queue becomes a min-heap
+//! // instead of a max-heap.
+//! impl Ord for State {
+//!     fn cmp(&self, other: &Self) -> Ordering {
+//!         // Notice that the we flip the ordering on costs.
+//!         // In case of a tie we compare positions - this step is necessary
+//!         // to make implementations of `PartialEq` and `Ord` consistent.
+//!         other.cost.cmp(&self.cost)
+//!             .then_with(|| self.position.cmp(&other.position))
+//!     }
+//! }
+//!
+//! // `PartialOrd` needs to be implemented as well.
+//! impl PartialOrd for State {
+//!     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+//!         Some(self.cmp(other))
+//!     }
+//! }
+//!
+//! // Each node is represented as a `usize`, for a shorter implementation.
+//! struct Edge {
+//!     node: usize,
+//!     cost: usize,
+//! }
+//!
+//! // Dijkstra's shortest path algorithm.
+//!
+//! // Start at `start` and use `dist` to track the current shortest distance
+//! // to each node. This implementation isn't memory-efficient as it may leave duplicate
+//! // nodes in the queue. It also uses `usize::MAX` as a sentinel value,
+//! // for a simpler implementation.
+//! fn shortest_path(adj_list: &Vec<Vec<Edge>>, start: usize, goal: usize) -> Option<usize> {
+//!     // dist[node] = current shortest distance from `start` to `node`
+//!     let mut dist: Vec<_> = (0..adj_list.len()).map(|_| usize::MAX).collect();
+//!
+//!     let mut heap = BinaryHeap::new();
+//!
+//!     // We're at `start`, with a zero cost
+//!     dist[start] = 0;
+//!     heap.push(State { cost: 0, position: start });
+//!
+//!     // Examine the frontier with lower cost nodes first (min-heap)
+//!     while let Some(State { cost, position }) = heap.pop() {
+//!         // Alternatively we could have continued to find all shortest paths
+//!         if position == goal { return Some(cost); }
+//!
+//!         // Important as we may have already found a better way
+//!         if cost > dist[position] { continue; }
+//!
+//!         // For each node we can reach, see if we can find a way with
+//!         // a lower cost going through this node
+//!         for edge in &adj_list[position] {
+//!             let next = State { cost: cost + edge.cost, position: edge.node };
+//!
+//!             // If so, add it to the frontier and continue
+//!             if next.cost < dist[next.position] {
+//!                 heap.push(next);
+//!                 // Relaxation, we have now found a better way
+//!                 dist[next.position] = next.cost;
+//!             }
+//!         }
+//!     }
+//!
+//!     // Goal not reachable
+//!     None
+//! }
+//!
+//! fn main() {
+//!     // This is the directed graph we're going to use.
+//!     // The node numbers correspond to the different states,
+//!     // and the edge weights symbolize the cost of moving
+//!     // from one node to another.
+//!     // Note that the edges are one-way.
+//!     //
+//!     //                  7
+//!     //          +-----------------+
+//!     //          |                 |
+//!     //          v   1        2    |  2
+//!     //          0 -----> 1 -----> 3 ---> 4
+//!     //          |        ^        ^      ^
+//!     //          |        | 1      |      |
+//!     //          |        |        | 3    | 1
+//!     //          +------> 2 -------+      |
+//!     //           10      |               |
+//!     //                   +---------------+
+//!     //
+//!     // The graph is represented as an adjacency list where each index,
+//!     // corresponding to a node value, has a list of outgoing edges.
+//!     // Chosen for its efficiency.
+//!     let graph = vec![
+//!         // Node 0
+//!         vec![Edge { node: 2, cost: 10 },
+//!              Edge { node: 1, cost: 1 }],
+//!         // Node 1
+//!         vec![Edge { node: 3, cost: 2 }],
+//!         // Node 2
+//!         vec![Edge { node: 1, cost: 1 },
+//!              Edge { node: 3, cost: 3 },
+//!              Edge { node: 4, cost: 1 }],
+//!         // Node 3
+//!         vec![Edge { node: 0, cost: 7 },
+//!              Edge { node: 4, cost: 2 }],
+//!         // Node 4
+//!         vec![]];
+//!
+//!     assert_eq!(shortest_path(&graph, 0, 1), Some(1));
+//!     assert_eq!(shortest_path(&graph, 0, 3), Some(3));
+//!     assert_eq!(shortest_path(&graph, 3, 0), Some(7));
+//!     assert_eq!(shortest_path(&graph, 0, 4), Some(5));
+//!     assert_eq!(shortest_path(&graph, 4, 0), None);
+//! }
+//! ```
+
+#![allow(missing_docs)]
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use core::fmt;
+use core::iter::{FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen};
+use core::mem::{self, swap, ManuallyDrop};
+use core::num::NonZeroUsize;
+use core::ops::{Deref, DerefMut};
+use core::ptr;
+
+use crate::collections::TryReserveError;
+use crate::slice;
+use crate::vec::{self, AsVecIntoIter, Vec};
+
+use super::SpecExtend;
+
+#[cfg(test)]
+mod tests;
+
+/// A priority queue implemented with a binary heap.
+///
+/// This will be a max-heap.
+///
+/// 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 heap. This is normally only possible
+/// through interior mutability, global state, I/O, or unsafe code. The
+/// behavior resulting from such a logic error is not specified, but will
+/// be encapsulated to the `BinaryHeap` that observed the logic error and not
+/// result in undefined behavior. This could include panics, incorrect results,
+/// aborts, memory leaks, and non-termination.
+///
+/// As long as no elements change their relative order while being in the heap
+/// as described above, the API of `BinaryHeap` guarantees that the heap
+/// invariant remains intact i.e. its methods all behave as documented. For
+/// example if a method is documented as iterating in sorted order, that's
+/// guaranteed to work as long as elements in the heap have not changed order,
+/// even in the presence of closures getting unwinded out of, iterators getting
+/// leaked, and similar foolishness.
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::BinaryHeap;
+///
+/// // Type inference lets us omit an explicit type signature (which
+/// // would be `BinaryHeap<i32>` in this example).
+/// let mut heap = BinaryHeap::new();
+///
+/// // We can use peek to look at the next item in the heap. In this case,
+/// // there's no items in there yet so we get None.
+/// assert_eq!(heap.peek(), None);
+///
+/// // Let's add some scores...
+/// heap.push(1);
+/// heap.push(5);
+/// heap.push(2);
+///
+/// // Now peek shows the most important item in the heap.
+/// assert_eq!(heap.peek(), Some(&5));
+///
+/// // We can check the length of a heap.
+/// assert_eq!(heap.len(), 3);
+///
+/// // We can iterate over the items in the heap, although they are returned in
+/// // a random order.
+/// for x in &heap {
+///     println!("{x}");
+/// }
+///
+/// // If we instead pop these scores, they should come back in order.
+/// assert_eq!(heap.pop(), Some(5));
+/// assert_eq!(heap.pop(), Some(2));
+/// assert_eq!(heap.pop(), Some(1));
+/// assert_eq!(heap.pop(), None);
+///
+/// // We can clear the heap of any remaining items.
+/// heap.clear();
+///
+/// // The heap should now be empty.
+/// assert!(heap.is_empty())
+/// ```
+///
+/// A `BinaryHeap` with a known list of items can be initialized from an array:
+///
+/// ```
+/// use std::collections::BinaryHeap;
+///
+/// let heap = BinaryHeap::from([1, 5, 2]);
+/// ```
+///
+/// ## Min-heap
+///
+/// Either [`core::cmp::Reverse`] or a custom [`Ord`] implementation can be used to
+/// make `BinaryHeap` a min-heap. This makes `heap.pop()` return the smallest
+/// value instead of the greatest one.
+///
+/// ```
+/// use std::collections::BinaryHeap;
+/// use std::cmp::Reverse;
+///
+/// let mut heap = BinaryHeap::new();
+///
+/// // Wrap values in `Reverse`
+/// heap.push(Reverse(1));
+/// heap.push(Reverse(5));
+/// heap.push(Reverse(2));
+///
+/// // If we pop these scores now, they should come back in the reverse order.
+/// assert_eq!(heap.pop(), Some(Reverse(1)));
+/// assert_eq!(heap.pop(), Some(Reverse(2)));
+/// assert_eq!(heap.pop(), Some(Reverse(5)));
+/// assert_eq!(heap.pop(), None);
+/// ```
+///
+/// # Time complexity
+///
+/// | [push]  | [pop]         | [peek]/[peek\_mut] |
+/// |---------|---------------|--------------------|
+/// | *O*(1)~ | *O*(log(*n*)) | *O*(1)             |
+///
+/// The value for `push` is an expected cost; the method documentation gives a
+/// more detailed analysis.
+///
+/// [`core::cmp::Reverse`]: core::cmp::Reverse
+/// [`Ord`]: core::cmp::Ord
+/// [`Cell`]: core::cell::Cell
+/// [`RefCell`]: core::cell::RefCell
+/// [push]: BinaryHeap::push
+/// [pop]: BinaryHeap::pop
+/// [peek]: BinaryHeap::peek
+/// [peek\_mut]: BinaryHeap::peek_mut
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "BinaryHeap")]
+pub struct BinaryHeap<T> {
+    data: Vec<T>,
+}
+
+/// Structure wrapping a mutable reference to the greatest item on a
+/// `BinaryHeap`.
+///
+/// This `struct` is created by the [`peek_mut`] method on [`BinaryHeap`]. See
+/// its documentation for more.
+///
+/// [`peek_mut`]: BinaryHeap::peek_mut
+#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
+pub struct PeekMut<'a, T: 'a + Ord> {
+    heap: &'a mut BinaryHeap<T>,
+    // If a set_len + sift_down are required, this is Some. If a &mut T has not
+    // yet been exposed to peek_mut()'s caller, it's None.
+    original_len: Option<NonZeroUsize>,
+}
+
+#[stable(feature = "collection_debug", since = "1.17.0")]
+impl<T: Ord + fmt::Debug> fmt::Debug for PeekMut<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("PeekMut").field(&self.heap.data[0]).finish()
+    }
+}
+
+#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
+impl<T: Ord> Drop for PeekMut<'_, T> {
+    fn drop(&mut self) {
+        if let Some(original_len) = self.original_len {
+            // SAFETY: That's how many elements were in the Vec at the time of
+            // the PeekMut::deref_mut call, and therefore also at the time of
+            // the BinaryHeap::peek_mut call. Since the PeekMut did not end up
+            // getting leaked, we are now undoing the leak amplification that
+            // the DerefMut prepared for.
+            unsafe { self.heap.data.set_len(original_len.get()) };
+
+            // SAFETY: PeekMut is only instantiated for non-empty heaps.
+            unsafe { self.heap.sift_down(0) };
+        }
+    }
+}
+
+#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
+impl<T: Ord> Deref for PeekMut<'_, T> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        debug_assert!(!self.heap.is_empty());
+        // SAFE: PeekMut is only instantiated for non-empty heaps
+        unsafe { self.heap.data.get_unchecked(0) }
+    }
+}
+
+#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
+impl<T: Ord> DerefMut for PeekMut<'_, T> {
+    fn deref_mut(&mut self) -> &mut T {
+        debug_assert!(!self.heap.is_empty());
+
+        let len = self.heap.len();
+        if len > 1 {
+            // Here we preemptively leak all the rest of the underlying vector
+            // after the currently max element. If the caller mutates the &mut T
+            // we're about to give them, and then leaks the PeekMut, all these
+            // elements will remain leaked. If they don't leak the PeekMut, then
+            // either Drop or PeekMut::pop will un-leak the vector elements.
+            //
+            // This is technique is described throughout several other places in
+            // the standard library as "leak amplification".
+            unsafe {
+                // SAFETY: len > 1 so len != 0.
+                self.original_len = Some(NonZeroUsize::new_unchecked(len));
+                // SAFETY: len > 1 so all this does for now is leak elements,
+                // which is safe.
+                self.heap.data.set_len(1);
+            }
+        }
+
+        // SAFE: PeekMut is only instantiated for non-empty heaps
+        unsafe { self.heap.data.get_unchecked_mut(0) }
+    }
+}
+
+impl<'a, T: Ord> PeekMut<'a, T> {
+    /// Removes the peeked value from the heap and returns it.
+    #[stable(feature = "binary_heap_peek_mut_pop", since = "1.18.0")]
+    pub fn pop(mut this: PeekMut<'a, T>) -> T {
+        if let Some(original_len) = this.original_len.take() {
+            // SAFETY: This is how many elements were in the Vec at the time of
+            // the BinaryHeap::peek_mut call.
+            unsafe { this.heap.data.set_len(original_len.get()) };
+
+            // Unlike in Drop, here we don't also need to do a sift_down even if
+            // the caller could've mutated the element. It is removed from the
+            // heap on the next line and pop() is not sensitive to its value.
+        }
+        this.heap.pop().unwrap()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Clone> Clone for BinaryHeap<T> {
+    fn clone(&self) -> Self {
+        BinaryHeap { data: self.data.clone() }
+    }
+
+    fn clone_from(&mut self, source: &Self) {
+        self.data.clone_from(&source.data);
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Ord> Default for BinaryHeap<T> {
+    /// Creates an empty `BinaryHeap<T>`.
+    #[inline]
+    fn default() -> BinaryHeap<T> {
+        BinaryHeap::new()
+    }
+}
+
+#[stable(feature = "binaryheap_debug", since = "1.4.0")]
+impl<T: fmt::Debug> fmt::Debug for BinaryHeap<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.iter()).finish()
+    }
+}
+
+impl<T: Ord> BinaryHeap<T> {
+    /// Creates an empty `BinaryHeap` as a max-heap.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let mut heap = BinaryHeap::new();
+    /// heap.push(4);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    pub fn new() -> BinaryHeap<T> {
+        BinaryHeap { data: vec![] }
+    }
+
+    /// Creates an empty `BinaryHeap` with at least the specified capacity.
+    ///
+    /// The binary heap will be able to hold at least `capacity` elements without
+    /// reallocating. This method is allowed to allocate for more elements than
+    /// `capacity`. If `capacity` is 0, the binary heap will not allocate.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let mut heap = BinaryHeap::with_capacity(10);
+    /// heap.push(4);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    pub fn with_capacity(capacity: usize) -> BinaryHeap<T> {
+        BinaryHeap { data: Vec::with_capacity(capacity) }
+    }
+
+    /// Returns a mutable reference to the greatest item in the binary heap, or
+    /// `None` if it is empty.
+    ///
+    /// Note: If the `PeekMut` value is leaked, some heap elements might get
+    /// leaked along with it, but the remaining elements will remain a valid
+    /// heap.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let mut heap = BinaryHeap::new();
+    /// assert!(heap.peek_mut().is_none());
+    ///
+    /// heap.push(1);
+    /// heap.push(5);
+    /// heap.push(2);
+    /// {
+    ///     let mut val = heap.peek_mut().unwrap();
+    ///     *val = 0;
+    /// }
+    /// assert_eq!(heap.peek(), Some(&2));
+    /// ```
+    ///
+    /// # Time complexity
+    ///
+    /// If the item is modified then the worst case time complexity is *O*(log(*n*)),
+    /// otherwise it's *O*(1).
+    #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
+    pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
+        if self.is_empty() { None } else { Some(PeekMut { heap: self, original_len: None }) }
+    }
+
+    /// Removes the greatest item from the binary heap and returns it, or `None` if it
+    /// is empty.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let mut heap = BinaryHeap::from([1, 3]);
+    ///
+    /// assert_eq!(heap.pop(), Some(3));
+    /// assert_eq!(heap.pop(), Some(1));
+    /// assert_eq!(heap.pop(), None);
+    /// ```
+    ///
+    /// # Time complexity
+    ///
+    /// The worst case cost of `pop` on a heap containing *n* elements is *O*(log(*n*)).
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn pop(&mut self) -> Option<T> {
+        self.data.pop().map(|mut item| {
+            if !self.is_empty() {
+                swap(&mut item, &mut self.data[0]);
+                // SAFETY: !self.is_empty() means that self.len() > 0
+                unsafe { self.sift_down_to_bottom(0) };
+            }
+            item
+        })
+    }
+
+    /// Pushes an item onto the binary heap.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let mut heap = BinaryHeap::new();
+    /// heap.push(3);
+    /// heap.push(5);
+    /// heap.push(1);
+    ///
+    /// assert_eq!(heap.len(), 3);
+    /// assert_eq!(heap.peek(), Some(&5));
+    /// ```
+    ///
+    /// # Time complexity
+    ///
+    /// The expected cost of `push`, averaged over every possible ordering of
+    /// the elements being pushed, and over a sufficiently large number of
+    /// pushes, is *O*(1). This is the most meaningful cost metric when pushing
+    /// elements that are *not* already in any sorted pattern.
+    ///
+    /// The time complexity degrades if elements are pushed in predominantly
+    /// ascending order. In the worst case, elements are pushed in ascending
+    /// sorted order and the amortized cost per push is *O*(log(*n*)) against a heap
+    /// containing *n* elements.
+    ///
+    /// The worst case cost of a *single* call to `push` is *O*(*n*). The worst case
+    /// occurs when capacity is exhausted and needs a resize. The resize cost
+    /// has been amortized in the previous figures.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn push(&mut self, item: T) {
+        let old_len = self.len();
+        self.data.push(item);
+        // SAFETY: Since we pushed a new item it means that
+        //  old_len = self.len() - 1 < self.len()
+        unsafe { self.sift_up(0, old_len) };
+    }
+
+    /// Consumes the `BinaryHeap` and returns a vector in sorted
+    /// (ascending) order.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    ///
+    /// let mut heap = BinaryHeap::from([1, 2, 4, 5, 7]);
+    /// heap.push(6);
+    /// heap.push(3);
+    ///
+    /// let vec = heap.into_sorted_vec();
+    /// assert_eq!(vec, [1, 2, 3, 4, 5, 6, 7]);
+    /// ```
+    #[must_use = "`self` will be dropped if the result is not used"]
+    #[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
+    pub fn into_sorted_vec(mut self) -> Vec<T> {
+        let mut end = self.len();
+        while end > 1 {
+            end -= 1;
+            // SAFETY: `end` goes from `self.len() - 1` to 1 (both included),
+            //  so it's always a valid index to access.
+            //  It is safe to access index 0 (i.e. `ptr`), because
+            //  1 <= end < self.len(), which means self.len() >= 2.
+            unsafe {
+                let ptr = self.data.as_mut_ptr();
+                ptr::swap(ptr, ptr.add(end));
+            }
+            // SAFETY: `end` goes from `self.len() - 1` to 1 (both included) so:
+            //  0 < 1 <= end <= self.len() - 1 < self.len()
+            //  Which means 0 < end and end < self.len().
+            unsafe { self.sift_down_range(0, end) };
+        }
+        self.into_vec()
+    }
+
+    // The implementations of sift_up and sift_down use unsafe blocks in
+    // order to move an element out of the vector (leaving behind a
+    // hole), shift along the others and move the removed element back into the
+    // vector at the final location of the hole.
+    // The `Hole` type is used to represent this, and make sure
+    // the hole is filled back at the end of its scope, even on panic.
+    // Using a hole reduces the constant factor compared to using swaps,
+    // which involves twice as many moves.
+
+    /// # Safety
+    ///
+    /// The caller must guarantee that `pos < self.len()`.
+    unsafe fn sift_up(&mut self, start: usize, pos: usize) -> usize {
+        // Take out the value at `pos` and create a hole.
+        // SAFETY: The caller guarantees that pos < self.len()
+        let mut hole = unsafe { Hole::new(&mut self.data, pos) };
+
+        while hole.pos() > start {
+            let parent = (hole.pos() - 1) / 2;
+
+            // SAFETY: hole.pos() > start >= 0, which means hole.pos() > 0
+            //  and so hole.pos() - 1 can't underflow.
+            //  This guarantees that parent < hole.pos() so
+            //  it's a valid index and also != hole.pos().
+            if hole.element() <= unsafe { hole.get(parent) } {
+                break;
+            }
+
+            // SAFETY: Same as above
+            unsafe { hole.move_to(parent) };
+        }
+
+        hole.pos()
+    }
+
+    /// Take an element at `pos` and move it down the heap,
+    /// while its children are larger.
+    ///
+    /// # Safety
+    ///
+    /// The caller must guarantee that `pos < end <= self.len()`.
+    unsafe fn sift_down_range(&mut self, pos: usize, end: usize) {
+        // SAFETY: The caller guarantees that pos < end <= self.len().
+        let mut hole = unsafe { Hole::new(&mut self.data, pos) };
+        let mut child = 2 * hole.pos() + 1;
+
+        // Loop invariant: child == 2 * hole.pos() + 1.
+        while child <= end.saturating_sub(2) {
+            // compare with the greater of the two children
+            // SAFETY: child < end - 1 < self.len() and
+            //  child + 1 < end <= self.len(), so they're valid indexes.
+            //  child == 2 * hole.pos() + 1 != hole.pos() and
+            //  child + 1 == 2 * hole.pos() + 2 != hole.pos().
+            // FIXME: 2 * hole.pos() + 1 or 2 * hole.pos() + 2 could overflow
+            //  if T is a ZST
+            child += unsafe { hole.get(child) <= hole.get(child + 1) } as usize;
+
+            // if we are already in order, stop.
+            // SAFETY: child is now either the old child or the old child+1
+            //  We already proven that both are < self.len() and != hole.pos()
+            if hole.element() >= unsafe { hole.get(child) } {
+                return;
+            }
+
+            // SAFETY: same as above.
+            unsafe { hole.move_to(child) };
+            child = 2 * hole.pos() + 1;
+        }
+
+        // SAFETY: && short circuit, which means that in the
+        //  second condition it's already true that child == end - 1 < self.len().
+        if child == end - 1 && hole.element() < unsafe { hole.get(child) } {
+            // SAFETY: child is already proven to be a valid index and
+            //  child == 2 * hole.pos() + 1 != hole.pos().
+            unsafe { hole.move_to(child) };
+        }
+    }
+
+    /// # Safety
+    ///
+    /// The caller must guarantee that `pos < self.len()`.
+    unsafe fn sift_down(&mut self, pos: usize) {
+        let len = self.len();
+        // SAFETY: pos < len is guaranteed by the caller and
+        //  obviously len = self.len() <= self.len().
+        unsafe { self.sift_down_range(pos, len) };
+    }
+
+    /// Take an element at `pos` and move it all the way down the heap,
+    /// then sift it up to its position.
+    ///
+    /// Note: This is faster when the element is known to be large / should
+    /// be closer to the bottom.
+    ///
+    /// # Safety
+    ///
+    /// The caller must guarantee that `pos < self.len()`.
+    unsafe fn sift_down_to_bottom(&mut self, mut pos: usize) {
+        let end = self.len();
+        let start = pos;
+
+        // SAFETY: The caller guarantees that pos < self.len().
+        let mut hole = unsafe { Hole::new(&mut self.data, pos) };
+        let mut child = 2 * hole.pos() + 1;
+
+        // Loop invariant: child == 2 * hole.pos() + 1.
+        while child <= end.saturating_sub(2) {
+            // SAFETY: child < end - 1 < self.len() and
+            //  child + 1 < end <= self.len(), so they're valid indexes.
+            //  child == 2 * hole.pos() + 1 != hole.pos() and
+            //  child + 1 == 2 * hole.pos() + 2 != hole.pos().
+            // FIXME: 2 * hole.pos() + 1 or 2 * hole.pos() + 2 could overflow
+            //  if T is a ZST
+            child += unsafe { hole.get(child) <= hole.get(child + 1) } as usize;
+
+            // SAFETY: Same as above
+            unsafe { hole.move_to(child) };
+            child = 2 * hole.pos() + 1;
+        }
+
+        if child == end - 1 {
+            // SAFETY: child == end - 1 < self.len(), so it's a valid index
+            //  and child == 2 * hole.pos() + 1 != hole.pos().
+            unsafe { hole.move_to(child) };
+        }
+        pos = hole.pos();
+        drop(hole);
+
+        // SAFETY: pos is the position in the hole and was already proven
+        //  to be a valid index.
+        unsafe { self.sift_up(start, pos) };
+    }
+
+    /// Rebuild assuming data[0..start] is still a proper heap.
+    fn rebuild_tail(&mut self, start: usize) {
+        if start == self.len() {
+            return;
+        }
+
+        let tail_len = self.len() - start;
+
+        #[inline(always)]
+        fn log2_fast(x: usize) -> usize {
+            (usize::BITS - x.leading_zeros() - 1) as usize
+        }
+
+        // `rebuild` takes O(self.len()) operations
+        // and about 2 * self.len() comparisons in the worst case
+        // while repeating `sift_up` takes O(tail_len * log(start)) operations
+        // and about 1 * tail_len * log_2(start) comparisons in the worst case,
+        // assuming start >= tail_len. For larger heaps, the crossover point
+        // no longer follows this reasoning and was determined empirically.
+        let better_to_rebuild = if start < tail_len {
+            true
+        } else if self.len() <= 2048 {
+            2 * self.len() < tail_len * log2_fast(start)
+        } else {
+            2 * self.len() < tail_len * 11
+        };
+
+        if better_to_rebuild {
+            self.rebuild();
+        } else {
+            for i in start..self.len() {
+                // SAFETY: The index `i` is always less than self.len().
+                unsafe { self.sift_up(0, i) };
+            }
+        }
+    }
+
+    fn rebuild(&mut self) {
+        let mut n = self.len() / 2;
+        while n > 0 {
+            n -= 1;
+            // SAFETY: n starts from self.len() / 2 and goes down to 0.
+            //  The only case when !(n < self.len()) is if
+            //  self.len() == 0, but it's ruled out by the loop condition.
+            unsafe { self.sift_down(n) };
+        }
+    }
+
+    /// Moves all the elements of `other` into `self`, leaving `other` empty.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    ///
+    /// let mut a = BinaryHeap::from([-10, 1, 2, 3, 3]);
+    /// let mut b = BinaryHeap::from([-20, 5, 43]);
+    ///
+    /// a.append(&mut b);
+    ///
+    /// assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
+    /// assert!(b.is_empty());
+    /// ```
+    #[stable(feature = "binary_heap_append", since = "1.11.0")]
+    pub fn append(&mut self, other: &mut Self) {
+        if self.len() < other.len() {
+            swap(self, other);
+        }
+
+        let start = self.data.len();
+
+        self.data.append(&mut other.data);
+
+        self.rebuild_tail(start);
+    }
+
+    /// Clears the binary heap, returning an iterator over the removed elements
+    /// in heap order. If the iterator is dropped before being fully consumed,
+    /// it drops the remaining elements in heap order.
+    ///
+    /// The returned iterator keeps a mutable borrow on the heap to optimize
+    /// its implementation.
+    ///
+    /// Note:
+    /// * `.drain_sorted()` is *O*(*n* \* log(*n*)); much slower than `.drain()`.
+    ///   You should use the latter for most cases.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(binary_heap_drain_sorted)]
+    /// use std::collections::BinaryHeap;
+    ///
+    /// let mut heap = BinaryHeap::from([1, 2, 3, 4, 5]);
+    /// assert_eq!(heap.len(), 5);
+    ///
+    /// drop(heap.drain_sorted()); // removes all elements in heap order
+    /// assert_eq!(heap.len(), 0);
+    /// ```
+    #[inline]
+    #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+    pub fn drain_sorted(&mut self) -> DrainSorted<'_, T> {
+        DrainSorted { inner: self }
+    }
+
+    /// Retains only the elements specified by the predicate.
+    ///
+    /// In other words, remove all elements `e` for which `f(&e)` returns
+    /// `false`. The elements are visited in unsorted (and unspecified) order.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(binary_heap_retain)]
+    /// use std::collections::BinaryHeap;
+    ///
+    /// let mut heap = BinaryHeap::from([-10, -5, 1, 2, 4, 13]);
+    ///
+    /// heap.retain(|x| x % 2 == 0); // only keep even numbers
+    ///
+    /// assert_eq!(heap.into_sorted_vec(), [-10, 2, 4])
+    /// ```
+    #[unstable(feature = "binary_heap_retain", issue = "71503")]
+    pub fn retain<F>(&mut self, mut f: F)
+    where
+        F: FnMut(&T) -> bool,
+    {
+        let mut first_removed = self.len();
+        let mut i = 0;
+        self.data.retain(|e| {
+            let keep = f(e);
+            if !keep && i < first_removed {
+                first_removed = i;
+            }
+            i += 1;
+            keep
+        });
+        // data[0..first_removed] is untouched, so we only need to rebuild the tail:
+        self.rebuild_tail(first_removed);
+    }
+}
+
+impl<T> BinaryHeap<T> {
+    /// Returns an iterator visiting all values in the underlying vector, in
+    /// arbitrary order.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let heap = BinaryHeap::from([1, 2, 3, 4]);
+    ///
+    /// // Print 1, 2, 3, 4 in arbitrary order
+    /// for x in heap.iter() {
+    ///     println!("{x}");
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn iter(&self) -> Iter<'_, T> {
+        Iter { iter: self.data.iter() }
+    }
+
+    /// Returns an iterator which retrieves elements in heap order.
+    /// This method consumes the original heap.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(binary_heap_into_iter_sorted)]
+    /// use std::collections::BinaryHeap;
+    /// let heap = BinaryHeap::from([1, 2, 3, 4, 5]);
+    ///
+    /// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), [5, 4]);
+    /// ```
+    #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+    pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
+        IntoIterSorted { inner: self }
+    }
+
+    /// Returns the greatest item in the binary heap, or `None` if it is empty.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let mut heap = BinaryHeap::new();
+    /// assert_eq!(heap.peek(), None);
+    ///
+    /// heap.push(1);
+    /// heap.push(5);
+    /// heap.push(2);
+    /// assert_eq!(heap.peek(), Some(&5));
+    ///
+    /// ```
+    ///
+    /// # Time complexity
+    ///
+    /// Cost is *O*(1) in the worst case.
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn peek(&self) -> Option<&T> {
+        self.data.get(0)
+    }
+
+    /// Returns the number of elements the binary heap can hold without reallocating.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let mut heap = BinaryHeap::with_capacity(100);
+    /// assert!(heap.capacity() >= 100);
+    /// heap.push(4);
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn capacity(&self) -> usize {
+        self.data.capacity()
+    }
+
+    /// Reserves the minimum capacity for at least `additional` elements more than
+    /// the current length. Unlike [`reserve`], this will not
+    /// deliberately over-allocate to speculatively avoid frequent allocations.
+    /// After calling `reserve_exact`, capacity will be greater than or equal to
+    /// `self.len() + additional`. Does nothing if the capacity is already
+    /// sufficient.
+    ///
+    /// [`reserve`]: BinaryHeap::reserve
+    ///
+    /// # Panics
+    ///
+    /// Panics if the new capacity overflows [`usize`].
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let mut heap = BinaryHeap::new();
+    /// heap.reserve_exact(100);
+    /// assert!(heap.capacity() >= 100);
+    /// heap.push(4);
+    /// ```
+    ///
+    /// [`reserve`]: BinaryHeap::reserve
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn reserve_exact(&mut self, additional: usize) {
+        self.data.reserve_exact(additional);
+    }
+
+    /// Reserves capacity for at least `additional` elements more than the
+    /// current length. The allocator may reserve more space to speculatively
+    /// avoid frequent allocations. After calling `reserve`,
+    /// capacity will be greater than or equal to `self.len() + additional`.
+    /// Does nothing if capacity is already sufficient.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the new capacity overflows [`usize`].
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let mut heap = BinaryHeap::new();
+    /// heap.reserve(100);
+    /// assert!(heap.capacity() >= 100);
+    /// heap.push(4);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn reserve(&mut self, additional: usize) {
+        self.data.reserve(additional);
+    }
+
+    /// Tries to reserve the minimum capacity for at least `additional` elements
+    /// more than the current length. Unlike [`try_reserve`], this will not
+    /// deliberately over-allocate to speculatively avoid frequent allocations.
+    /// After calling `try_reserve_exact`, capacity will be greater than or
+    /// equal to `self.len() + additional` if it returns `Ok(())`.
+    /// Does nothing if the capacity is already sufficient.
+    ///
+    /// Note that the allocator may give the collection more space than it
+    /// requests. Therefore, capacity can not be relied upon to be precisely
+    /// minimal. Prefer [`try_reserve`] if future insertions are expected.
+    ///
+    /// [`try_reserve`]: BinaryHeap::try_reserve
+    ///
+    /// # Errors
+    ///
+    /// If the capacity overflows, or the allocator reports a failure, then an error
+    /// is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// use std::collections::TryReserveError;
+    ///
+    /// fn find_max_slow(data: &[u32]) -> Result<Option<u32>, TryReserveError> {
+    ///     let mut heap = BinaryHeap::new();
+    ///
+    ///     // Pre-reserve the memory, exiting if we can't
+    ///     heap.try_reserve_exact(data.len())?;
+    ///
+    ///     // Now we know this can't OOM in the middle of our complex work
+    ///     heap.extend(data.iter());
+    ///
+    ///     Ok(heap.pop())
+    /// }
+    /// # find_max_slow(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
+    /// ```
+    #[stable(feature = "try_reserve_2", since = "1.63.0")]
+    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
+        self.data.try_reserve_exact(additional)
+    }
+
+    /// Tries to reserve capacity for at least `additional` elements more than the
+    /// current length. The allocator may reserve more space to speculatively
+    /// avoid frequent allocations. After calling `try_reserve`, capacity will be
+    /// greater than or equal to `self.len() + additional` if it returns
+    /// `Ok(())`. Does nothing if capacity is already sufficient. This method
+    /// preserves the contents even if an error occurs.
+    ///
+    /// # Errors
+    ///
+    /// If the capacity overflows, or the allocator reports a failure, then an error
+    /// is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// use std::collections::TryReserveError;
+    ///
+    /// fn find_max_slow(data: &[u32]) -> Result<Option<u32>, TryReserveError> {
+    ///     let mut heap = BinaryHeap::new();
+    ///
+    ///     // Pre-reserve the memory, exiting if we can't
+    ///     heap.try_reserve(data.len())?;
+    ///
+    ///     // Now we know this can't OOM in the middle of our complex work
+    ///     heap.extend(data.iter());
+    ///
+    ///     Ok(heap.pop())
+    /// }
+    /// # find_max_slow(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
+    /// ```
+    #[stable(feature = "try_reserve_2", since = "1.63.0")]
+    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
+        self.data.try_reserve(additional)
+    }
+
+    /// Discards as much additional capacity as possible.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let mut heap: BinaryHeap<i32> = BinaryHeap::with_capacity(100);
+    ///
+    /// assert!(heap.capacity() >= 100);
+    /// heap.shrink_to_fit();
+    /// assert!(heap.capacity() == 0);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn shrink_to_fit(&mut self) {
+        self.data.shrink_to_fit();
+    }
+
+    /// Discards capacity with a lower bound.
+    ///
+    /// The capacity will remain at least as large as both the length
+    /// and the supplied value.
+    ///
+    /// If the current capacity is less than the lower limit, this is a no-op.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let mut heap: BinaryHeap<i32> = BinaryHeap::with_capacity(100);
+    ///
+    /// assert!(heap.capacity() >= 100);
+    /// heap.shrink_to(10);
+    /// assert!(heap.capacity() >= 10);
+    /// ```
+    #[inline]
+    #[stable(feature = "shrink_to", since = "1.56.0")]
+    pub fn shrink_to(&mut self, min_capacity: usize) {
+        self.data.shrink_to(min_capacity)
+    }
+
+    /// Returns a slice of all values in the underlying vector, in arbitrary
+    /// order.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(binary_heap_as_slice)]
+    /// use std::collections::BinaryHeap;
+    /// use std::io::{self, Write};
+    ///
+    /// let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]);
+    ///
+    /// io::sink().write(heap.as_slice()).unwrap();
+    /// ```
+    #[must_use]
+    #[unstable(feature = "binary_heap_as_slice", issue = "83659")]
+    pub fn as_slice(&self) -> &[T] {
+        self.data.as_slice()
+    }
+
+    /// Consumes the `BinaryHeap` and returns the underlying vector
+    /// in arbitrary order.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]);
+    /// let vec = heap.into_vec();
+    ///
+    /// // Will print in some order
+    /// for x in vec {
+    ///     println!("{x}");
+    /// }
+    /// ```
+    #[must_use = "`self` will be dropped if the result is not used"]
+    #[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
+    pub fn into_vec(self) -> Vec<T> {
+        self.into()
+    }
+
+    /// Returns the length of the binary heap.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let heap = BinaryHeap::from([1, 3]);
+    ///
+    /// assert_eq!(heap.len(), 2);
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn len(&self) -> usize {
+        self.data.len()
+    }
+
+    /// Checks if the binary heap is empty.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let mut heap = BinaryHeap::new();
+    ///
+    /// assert!(heap.is_empty());
+    ///
+    /// heap.push(3);
+    /// heap.push(5);
+    /// heap.push(1);
+    ///
+    /// assert!(!heap.is_empty());
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Clears the binary heap, returning an iterator over the removed elements
+    /// in arbitrary order. If the iterator is dropped before being fully
+    /// consumed, it drops the remaining elements in arbitrary order.
+    ///
+    /// The returned iterator keeps a mutable borrow on the heap to optimize
+    /// its implementation.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let mut heap = BinaryHeap::from([1, 3]);
+    ///
+    /// assert!(!heap.is_empty());
+    ///
+    /// for x in heap.drain() {
+    ///     println!("{x}");
+    /// }
+    ///
+    /// assert!(heap.is_empty());
+    /// ```
+    #[inline]
+    #[stable(feature = "drain", since = "1.6.0")]
+    pub fn drain(&mut self) -> Drain<'_, T> {
+        Drain { iter: self.data.drain(..) }
+    }
+
+    /// Drops all items from the binary heap.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let mut heap = BinaryHeap::from([1, 3]);
+    ///
+    /// assert!(!heap.is_empty());
+    ///
+    /// heap.clear();
+    ///
+    /// assert!(heap.is_empty());
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn clear(&mut self) {
+        self.drain();
+    }
+}
+
+/// Hole represents a hole in a slice i.e., an index without valid value
+/// (because it was moved from or duplicated).
+/// In drop, `Hole` will restore the slice by filling the hole
+/// position with the value that was originally removed.
+struct Hole<'a, T: 'a> {
+    data: &'a mut [T],
+    elt: ManuallyDrop<T>,
+    pos: usize,
+}
+
+impl<'a, T> Hole<'a, T> {
+    /// Create a new `Hole` at index `pos`.
+    ///
+    /// Unsafe because pos must be within the data slice.
+    #[inline]
+    unsafe fn new(data: &'a mut [T], pos: usize) -> Self {
+        debug_assert!(pos < data.len());
+        // SAFE: pos should be inside the slice
+        let elt = unsafe { ptr::read(data.get_unchecked(pos)) };
+        Hole { data, elt: ManuallyDrop::new(elt), pos }
+    }
+
+    #[inline]
+    fn pos(&self) -> usize {
+        self.pos
+    }
+
+    /// Returns a reference to the element removed.
+    #[inline]
+    fn element(&self) -> &T {
+        &self.elt
+    }
+
+    /// Returns a reference to the element at `index`.
+    ///
+    /// Unsafe because index must be within the data slice and not equal to pos.
+    #[inline]
+    unsafe fn get(&self, index: usize) -> &T {
+        debug_assert!(index != self.pos);
+        debug_assert!(index < self.data.len());
+        unsafe { self.data.get_unchecked(index) }
+    }
+
+    /// Move hole to new location
+    ///
+    /// Unsafe because index must be within the data slice and not equal to pos.
+    #[inline]
+    unsafe fn move_to(&mut self, index: usize) {
+        debug_assert!(index != self.pos);
+        debug_assert!(index < self.data.len());
+        unsafe {
+            let ptr = self.data.as_mut_ptr();
+            let index_ptr: *const _ = ptr.add(index);
+            let hole_ptr = ptr.add(self.pos);
+            ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
+        }
+        self.pos = index;
+    }
+}
+
+impl<T> Drop for Hole<'_, T> {
+    #[inline]
+    fn drop(&mut self) {
+        // fill the hole again
+        unsafe {
+            let pos = self.pos;
+            ptr::copy_nonoverlapping(&*self.elt, self.data.get_unchecked_mut(pos), 1);
+        }
+    }
+}
+
+/// An iterator over the elements of a `BinaryHeap`.
+///
+/// This `struct` is created by [`BinaryHeap::iter()`]. See its
+/// documentation for more.
+///
+/// [`iter`]: BinaryHeap::iter
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Iter<'a, T: 'a> {
+    iter: slice::Iter<'a, T>,
+}
+
+#[stable(feature = "collection_debug", since = "1.17.0")]
+impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("Iter").field(&self.iter.as_slice()).finish()
+    }
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Clone for Iter<'_, T> {
+    fn clone(&self) -> Self {
+        Iter { iter: self.iter.clone() }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> Iterator for Iter<'a, T> {
+    type Item = &'a T;
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a T> {
+        self.iter.next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+
+    #[inline]
+    fn last(self) -> Option<&'a T> {
+        self.iter.last()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a T> {
+        self.iter.next_back()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> ExactSizeIterator for Iter<'_, T> {
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T> FusedIterator for Iter<'_, T> {}
+
+/// An owning iterator over the elements of a `BinaryHeap`.
+///
+/// This `struct` is created by [`BinaryHeap::into_iter()`]
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
+///
+/// [`into_iter`]: BinaryHeap::into_iter
+/// [`IntoIterator`]: core::iter::IntoIterator
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone)]
+pub struct IntoIter<T> {
+    iter: vec::IntoIter<T>,
+}
+
+#[stable(feature = "collection_debug", since = "1.17.0")]
+impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("IntoIter").field(&self.iter.as_slice()).finish()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Iterator for IntoIter<T> {
+    type Item = T;
+
+    #[inline]
+    fn next(&mut self) -> Option<T> {
+        self.iter.next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> DoubleEndedIterator for IntoIter<T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<T> {
+        self.iter.next_back()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> ExactSizeIterator for IntoIter<T> {
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T> FusedIterator for IntoIter<T> {}
+
+// In addition to the SAFETY invariants of the following three unsafe traits
+// also refer to the vec::in_place_collect module documentation to get an overview
+#[unstable(issue = "none", feature = "inplace_iteration")]
+#[doc(hidden)]
+unsafe impl<T> SourceIter for IntoIter<T> {
+    type Source = IntoIter<T>;
+
+    #[inline]
+    unsafe fn as_inner(&mut self) -> &mut Self::Source {
+        self
+    }
+}
+
+#[unstable(issue = "none", feature = "inplace_iteration")]
+#[doc(hidden)]
+unsafe impl<I> InPlaceIterable for IntoIter<I> {}
+
+unsafe impl<I> AsVecIntoIter for IntoIter<I> {
+    type Item = I;
+
+    fn as_into_iter(&mut self) -> &mut vec::IntoIter<Self::Item> {
+        &mut self.iter
+    }
+}
+
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+#[derive(Clone, Debug)]
+pub struct IntoIterSorted<T> {
+    inner: BinaryHeap<T>,
+}
+
+#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+impl<T: Ord> Iterator for IntoIterSorted<T> {
+    type Item = T;
+
+    #[inline]
+    fn next(&mut self) -> Option<T> {
+        self.inner.pop()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let exact = self.inner.len();
+        (exact, Some(exact))
+    }
+}
+
+#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+impl<T: Ord> ExactSizeIterator for IntoIterSorted<T> {}
+
+#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+impl<T: Ord> FusedIterator for IntoIterSorted<T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T: Ord> TrustedLen for IntoIterSorted<T> {}
+
+/// A draining iterator over the elements of a `BinaryHeap`.
+///
+/// This `struct` is created by [`BinaryHeap::drain()`]. See its
+/// documentation for more.
+///
+/// [`drain`]: BinaryHeap::drain
+#[stable(feature = "drain", since = "1.6.0")]
+#[derive(Debug)]
+pub struct Drain<'a, T: 'a> {
+    iter: vec::Drain<'a, T>,
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<T> Iterator for Drain<'_, T> {
+    type Item = T;
+
+    #[inline]
+    fn next(&mut self) -> Option<T> {
+        self.iter.next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<T> DoubleEndedIterator for Drain<'_, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<T> {
+        self.iter.next_back()
+    }
+}
+
+#[stable(feature = "drain", since = "1.6.0")]
+impl<T> ExactSizeIterator for Drain<'_, T> {
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T> FusedIterator for Drain<'_, T> {}
+
+/// A draining iterator over the elements of a `BinaryHeap`.
+///
+/// This `struct` is created by [`BinaryHeap::drain_sorted()`]. See its
+/// documentation for more.
+///
+/// [`drain_sorted`]: BinaryHeap::drain_sorted
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+#[derive(Debug)]
+pub struct DrainSorted<'a, T: Ord> {
+    inner: &'a mut BinaryHeap<T>,
+}
+
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+impl<'a, T: Ord> Drop for DrainSorted<'a, T> {
+    /// Removes heap elements in heap order.
+    fn drop(&mut self) {
+        struct DropGuard<'r, 'a, T: Ord>(&'r mut DrainSorted<'a, T>);
+
+        impl<'r, 'a, T: Ord> Drop for DropGuard<'r, 'a, T> {
+            fn drop(&mut self) {
+                while self.0.inner.pop().is_some() {}
+            }
+        }
+
+        while let Some(item) = self.inner.pop() {
+            let guard = DropGuard(self);
+            drop(item);
+            mem::forget(guard);
+        }
+    }
+}
+
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+impl<T: Ord> Iterator for DrainSorted<'_, T> {
+    type Item = T;
+
+    #[inline]
+    fn next(&mut self) -> Option<T> {
+        self.inner.pop()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let exact = self.inner.len();
+        (exact, Some(exact))
+    }
+}
+
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+impl<T: Ord> ExactSizeIterator for DrainSorted<'_, T> {}
+
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+impl<T: Ord> FusedIterator for DrainSorted<'_, T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T: Ord> TrustedLen for DrainSorted<'_, T> {}
+
+#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
+impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
+    /// Converts a `Vec<T>` into a `BinaryHeap<T>`.
+    ///
+    /// This conversion happens in-place, and has *O*(*n*) time complexity.
+    fn from(vec: Vec<T>) -> BinaryHeap<T> {
+        let mut heap = BinaryHeap { data: vec };
+        heap.rebuild();
+        heap
+    }
+}
+
+#[stable(feature = "std_collections_from_array", since = "1.56.0")]
+impl<T: Ord, const N: usize> From<[T; N]> for BinaryHeap<T> {
+    /// ```
+    /// use std::collections::BinaryHeap;
+    ///
+    /// let mut h1 = BinaryHeap::from([1, 4, 2, 3]);
+    /// let mut h2: BinaryHeap<_> = [1, 4, 2, 3].into();
+    /// while let Some((a, b)) = h1.pop().zip(h2.pop()) {
+    ///     assert_eq!(a, b);
+    /// }
+    /// ```
+    fn from(arr: [T; N]) -> Self {
+        Self::from_iter(arr)
+    }
+}
+
+#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
+impl<T> From<BinaryHeap<T>> for Vec<T> {
+    /// Converts a `BinaryHeap<T>` into a `Vec<T>`.
+    ///
+    /// This conversion requires no data movement or allocation, and has
+    /// constant time complexity.
+    fn from(heap: BinaryHeap<T>) -> Vec<T> {
+        heap.data
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Ord> FromIterator<T> for BinaryHeap<T> {
+    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> BinaryHeap<T> {
+        BinaryHeap::from(iter.into_iter().collect::<Vec<_>>())
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> IntoIterator for BinaryHeap<T> {
+    type Item = T;
+    type IntoIter = IntoIter<T>;
+
+    /// Creates a consuming iterator, that is, one that moves each value out of
+    /// the binary heap in arbitrary order. The binary heap cannot be used
+    /// after calling this.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::collections::BinaryHeap;
+    /// let heap = BinaryHeap::from([1, 2, 3, 4]);
+    ///
+    /// // Print 1, 2, 3, 4 in arbitrary order
+    /// for x in heap.into_iter() {
+    ///     // x has type i32, not &i32
+    ///     println!("{x}");
+    /// }
+    /// ```
+    fn into_iter(self) -> IntoIter<T> {
+        IntoIter { iter: self.data.into_iter() }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> IntoIterator for &'a BinaryHeap<T> {
+    type Item = &'a T;
+    type IntoIter = Iter<'a, T>;
+
+    fn into_iter(self) -> Iter<'a, T> {
+        self.iter()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Ord> Extend<T> for BinaryHeap<T> {
+    #[inline]
+    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+        <Self as SpecExtend<I>>::spec_extend(self, iter);
+    }
+
+    #[inline]
+    fn extend_one(&mut self, item: T) {
+        self.push(item);
+    }
+
+    #[inline]
+    fn extend_reserve(&mut self, additional: usize) {
+        self.reserve(additional);
+    }
+}
+
+impl<T: Ord, I: IntoIterator<Item = T>> SpecExtend<I> for BinaryHeap<T> {
+    default fn spec_extend(&mut self, iter: I) {
+        self.extend_desugared(iter.into_iter());
+    }
+}
+
+impl<T: Ord> SpecExtend<Vec<T>> for BinaryHeap<T> {
+    fn spec_extend(&mut self, ref mut other: Vec<T>) {
+        let start = self.data.len();
+        self.data.append(other);
+        self.rebuild_tail(start);
+    }
+}
+
+impl<T: Ord> SpecExtend<BinaryHeap<T>> for BinaryHeap<T> {
+    fn spec_extend(&mut self, ref mut other: BinaryHeap<T>) {
+        self.append(other);
+    }
+}
+
+impl<T: Ord> BinaryHeap<T> {
+    fn extend_desugared<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+        let iterator = iter.into_iter();
+        let (lower, _) = iterator.size_hint();
+
+        self.reserve(lower);
+
+        iterator.for_each(move |elem| self.push(elem));
+    }
+}
+
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap<T> {
+    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
+        self.extend(iter.into_iter().cloned());
+    }
+
+    #[inline]
+    fn extend_one(&mut self, &item: &'a T) {
+        self.push(item);
+    }
+
+    #[inline]
+    fn extend_reserve(&mut self, additional: usize) {
+        self.reserve(additional);
+    }
+}
index 59c516374c0e2790d6c2357b6ed1566afa7c2344..ffbb6c80ac01847999294b6dee8af0b81fa0dc4f 100644 (file)
@@ -1,6 +1,7 @@
 use super::*;
 use crate::boxed::Box;
 use crate::testing::crash_test::{CrashTestDummy, Panic};
+use core::mem;
 use std::iter::TrustedLen;
 use std::panic::{catch_unwind, AssertUnwindSafe};
 
@@ -146,6 +147,24 @@ fn test_peek_mut() {
     assert_eq!(heap.peek(), Some(&9));
 }
 
+#[test]
+fn test_peek_mut_leek() {
+    let data = vec![4, 2, 7];
+    let mut heap = BinaryHeap::from(data);
+    let mut max = heap.peek_mut().unwrap();
+    *max = -1;
+
+    // The PeekMut object's Drop impl would have been responsible for moving the
+    // -1 out of the max position of the BinaryHeap, but we don't run it.
+    mem::forget(max);
+
+    // Absent some mitigation like leak amplification, the -1 would incorrectly
+    // end up in the last position of the returned Vec, with the rest of the
+    // heap's original contents in front of it in sorted order.
+    let sorted_vec = heap.into_sorted_vec();
+    assert!(sorted_vec.is_sorted(), "{:?}", sorted_vec);
+}
+
 #[test]
 fn test_peek_mut_pop() {
     let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
index 4e812529c2cc846d7934672a05202a0eb9db7218..afc3a3dc6a8c6bb646b725f281052558f61e7844 100644 (file)
 #![feature(hasher_prefixfree_extras)]
 #![feature(inline_const)]
 #![feature(inplace_iteration)]
+#![cfg_attr(test, feature(is_sorted))]
 #![feature(iter_advance_by)]
 #![feature(iter_next_chunk)]
 #![feature(iter_repeat_n)]
index c1d853ed652160149e6911c5577e8cc93891f1a9..c9aa23fc4af1f275e98ff6352e4e34480d6044cb 100644 (file)
@@ -2179,7 +2179,7 @@ pub struct Weak<T: ?Sized> {
     // This is a `NonNull` to allow optimizing the size of this type in enums,
     // but it is not necessarily a valid pointer.
     // `Weak::new` sets this to `usize::MAX` so that it doesn’t need
-    // to allocate space on the heap.  That's not a value a real pointer
+    // to allocate space on the heap. That's not a value a real pointer
     // will ever have because RcBox has alignment at least 2.
     // This is only possible when `T: Sized`; unsized `T` never dangle.
     ptr: NonNull<RcBox<T>>,
index d833d4d1dfbd327a5f53b606498e5e717cbcae69..bab7f5f53657a58cfa55f9614684a6a8b4978700 100644 (file)
@@ -295,7 +295,7 @@ pub struct Weak<T: ?Sized> {
     // This is a `NonNull` to allow optimizing the size of this type in enums,
     // but it is not necessarily a valid pointer.
     // `Weak::new` sets this to `usize::MAX` so that it doesn’t need
-    // to allocate space on the heap.  That's not a value a real pointer
+    // to allocate space on the heap. That's not a value a real pointer
     // will ever have because RcBox has alignment at least 2.
     // This is only possible when `T: Sized`; unsized `T` never dangle.
     ptr: NonNull<ArcInner<T>>,
@@ -1656,7 +1656,7 @@ fn is_unique(&mut self) -> bool {
         //
         // The acquire label here ensures a happens-before relationship with any
         // writes to `strong` (in particular in `Weak::upgrade`) prior to decrements
-        // of the `weak` count (via `Weak::drop`, which uses release).  If the upgraded
+        // of the `weak` count (via `Weak::drop`, which uses release). If the upgraded
         // weak ref was never dropped, the CAS here will fail so we do not care to synchronize.
         if self.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() {
             // This needs to be an `Acquire` to synchronize with the decrement of the `strong`
@@ -1712,7 +1712,7 @@ fn drop(&mut self) {
         }
 
         // This fence is needed to prevent reordering of use of the data and
-        // deletion of the data.  Because it is marked `Release`, the decreasing
+        // deletion of the data. Because it is marked `Release`, the decreasing
         // of the reference count synchronizes with this `Acquire` fence. This
         // means that use of the data happens before decreasing the reference
         // count, which happens before this fence, which happens before the
@@ -2172,7 +2172,7 @@ fn clone(&self) -> Weak<T> {
         } else {
             return Weak { ptr: self.ptr };
         };
-        // See comments in Arc::clone() for why this is relaxed.  This can use a
+        // See comments in Arc::clone() for why this is relaxed. This can use a
         // fetch_add (ignoring the lock) because the weak count is only locked
         // where are *no other* weak pointers in existence. (So we can't be
         // running this code in that case).
index b207b3210f1aa22ae6edcf989ab68b7f5b14bff1..37966007eb7e43eb1fb661d8925567b303f905ba 100644 (file)
@@ -40,7 +40,7 @@ pub struct IntoIter<
     // to avoid dropping the allocator twice we need to wrap it into ManuallyDrop
     pub(super) alloc: ManuallyDrop<A>,
     pub(super) ptr: *const T,
-    pub(super) end: *const T, // If T is a ZST, this is actually ptr+len.  This encoding is picked so that
+    pub(super) end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
                               // ptr == end is a quick test for the Iterator being empty, that works
                               // for both ZST and non-ZST.
 }
@@ -146,9 +146,9 @@ pub(crate) fn into_vecdeque(self) -> VecDeque<T, A> {
         let mut this = ManuallyDrop::new(self);
 
         // SAFETY: This allocation originally came from a `Vec`, so it passes
-        // all those checks.  We have `this.buf` ≤ `this.ptr` ≤ `this.end`,
+        // all those checks. We have `this.buf` ≤ `this.ptr` ≤ `this.end`,
         // so the `sub_ptr`s below cannot wrap, and will produce a well-formed
-        // range.  `end` ≤ `buf + cap`, so the range will be in-bounds.
+        // range. `end` ≤ `buf + cap`, so the range will be in-bounds.
         // Taking `alloc` is ok because nothing else is going to look at it,
         // since our `Drop` impl isn't going to run so there's no more code.
         unsafe {
index 8e652d676dc010a740a44f60a92934b99bd0c11e..26120270c0cb0da8402a60b346e0999acf2873f8 100644 (file)
@@ -57,7 +57,7 @@ fn is_zero(&self) -> bool {
     #[inline]
     fn is_zero(&self) -> bool {
         // Because this is generated as a runtime check, it's not obvious that
-        // it's worth doing if the array is really long.  The threshold here
+        // it's worth doing if the array is really long. The threshold here
         // is largely arbitrary, but was picked because as of 2022-07-01 LLVM
         // fails to const-fold the check in `vec![[1; 32]; n]`
         // See https://github.com/rust-lang/rust/pull/97581#issuecomment-1166628022
index 36cfac8ee9e17da0dde403e785c0a09efd324898..36b0b3c9e7cc072aca6f39d2f165d277d52cbdc3 100644 (file)
@@ -2429,7 +2429,7 @@ pub fn extend_from_within<R>(&mut self, src: R)
         self.reserve(range.len());
 
         // SAFETY:
-        // - `slice::range` guarantees  that the given range is valid for indexing self
+        // - `slice::range` guarantees that the given range is valid for indexing self
         unsafe {
             self.spec_extend_from_within(range);
         }
@@ -2686,7 +2686,7 @@ fn clone(&self) -> Self {
 
     // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
     // required for this method definition, is not available. Instead use the
-    // `slice::to_vec`  function which is only available with cfg(test)
+    // `slice::to_vec` function which is only available with cfg(test)
     // NB see the slice::hack module in slice.rs for more information
     #[cfg(test)]
     fn clone(&self) -> Self {
index 87adcead8f62d69ba7dbcdcb4c5f331aa276b414..2f07c2911a50264aee57ab1a67b966a869045ef3 100644 (file)
@@ -1849,7 +1849,7 @@ fn next_then_drop<I: Iterator>(mut i: I) {
     }
 
     // Test that, if we reserved enough space, adding and removing elements does not
-    // invalidate references into the vector (such as `v0`).  This test also
+    // invalidate references into the vector (such as `v0`). This test also
     // runs in Miri, which would detect such problems.
     // Note that this test does *not* constitute a stable guarantee that all these functions do not
     // reallocate! Only what is explicitly documented at
index b91c630183d4fe707231b70e483f4b202d5dafde..8259c087d22e4ff13cce9566ed8a828a169f0977 100644 (file)
@@ -109,8 +109,8 @@ impl<T, const N: usize> IntoIter<T, N> {
     /// use std::array::IntoIter;
     /// use std::mem::MaybeUninit;
     ///
-    /// # // Hi!  Thanks for reading the code.  This is restricted to `Copy` because
-    /// # // otherwise it could leak.  A fully-general version this would need a drop
+    /// # // Hi!  Thanks for reading the code. This is restricted to `Copy` because
+    /// # // otherwise it could leak. A fully-general version this would need a drop
     /// # // guard to handle panics from the iterator, but this works for an example.
     /// fn next_chunk<T: Copy, const N: usize>(
     ///     it: &mut impl Iterator<Item = T>,
@@ -211,7 +211,7 @@ pub const fn empty() -> Self {
         let initialized = 0..0;
 
         // SAFETY: We're telling it that none of the elements are initialized,
-        // which is trivially true.  And ∀N: usize, 0 <= N.
+        // which is trivially true. And ∀N: usize, 0 <= N.
         unsafe { Self::new_unchecked(buffer, initialized) }
     }
 
index 51e6a76cea848c540ac8a6beda22fa434c7a6e88..fa5073e3304d72e93dff7a042804e043b234caa8 100644 (file)
@@ -174,6 +174,11 @@ fn write_char(&mut self, c: char) -> Result {
     /// This method should generally not be invoked manually, but rather through
     /// the [`write!`] macro itself.
     ///
+    /// # Errors
+    ///
+    /// This function will return an instance of [`Error`] on error. Please see
+    /// [write_str](Write::write_str) for details.
+    ///
     /// # Examples
     ///
     /// ```
index ac7b389b15b4d5e9e00e99ef2a4740a7c51b2971..b5739f2f3c0b057d286ecff2095d80f861c5ca18 100644 (file)
@@ -756,7 +756,7 @@ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
     where
         Self: TrustedRandomAccessNoCoerce,
     {
-        // SAFETY: The TrustedRandomAccess contract requires that callers only  pass an index
+        // SAFETY: The TrustedRandomAccess contract requires that callers only pass an index
         // that is in bounds.
         // Additionally Self: TrustedRandomAccess is only implemented for Copy types
         // which means even repeated reads of the same index would be safe.
index 8e7cbd34a4f664b6c1496d6fa65591ca11ce8537..4cbe731b222f920131e999b0bd409747aa387a88 100644 (file)
@@ -1,3 +1,4 @@
+use crate::fmt;
 use crate::ops::{Generator, GeneratorState};
 use crate::pin::Pin;
 
 /// ```
 #[inline]
 #[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")]
-pub fn from_generator<G: Generator<Return = ()> + Unpin>(
-    generator: G,
-) -> impl Iterator<Item = G::Yield> {
+pub fn from_generator<G: Generator<Return = ()> + Unpin>(generator: G) -> FromGenerator<G> {
     FromGenerator(generator)
 }
 
-struct FromGenerator<G>(G);
+/// An iterator over the values yielded by an underlying generator.
+///
+/// This `struct` is created by the [`iter::from_generator()`] function. See its documentation for
+/// more.
+///
+/// [`iter::from_generator()`]: from_generator
+#[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")]
+#[derive(Clone)]
+pub struct FromGenerator<G>(G);
 
+#[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")]
 impl<G: Generator<Return = ()> + Unpin> Iterator for FromGenerator<G> {
     type Item = G::Yield;
 
@@ -41,3 +49,10 @@ fn next(&mut self) -> Option<Self::Item> {
         }
     }
 }
+
+#[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")]
+impl<G> fmt::Debug for FromGenerator<G> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("FromGenerator").finish()
+    }
+}
index ec5fa45fdaddd72489d612d87617c14ed7ce8012..3806977f70ee4598d6a78aa88483b10086460b36 100644 (file)
@@ -26,7 +26,7 @@ mod fpu_precision {
     /// Developer's Manual (Volume 1).
     ///
     /// The only field which is relevant for the following code is PC, Precision Control. This
-    /// field determines the precision of the operations performed by the  FPU. It can be set to:
+    /// field determines the precision of the operations performed by the FPU. It can be set to:
     ///  - 0b00, single precision i.e., 32-bits
     ///  - 0b10, double precision i.e., 64-bits
     ///  - 0b11, double extended precision i.e., 80-bits (default state)
index 21518a3f551807356dbbf2dc484f4af1387490fc..2cae98b8e494334e640b3c936181cb1c6db32555 100644 (file)
@@ -1538,7 +1538,7 @@ pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
         ///
         /// ```
         /// #![feature(bigint_helper_methods)]
-        /// // Only the  most significant word is signed.
+        /// // Only the most significant word is signed.
         /// //
         #[doc = concat!("//   10  MAX    (a = 10 × 2^", stringify!($BITS), " + 2^", stringify!($BITS), " - 1)")]
         #[doc = concat!("// + -5    9    (b = -5 × 2^", stringify!($BITS), " + 9)")]
@@ -1625,7 +1625,7 @@ pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
         /// overflow.
         ///
         /// Performs "ternary subtraction" by subtracting both an integer
-        /// operandand a borrow-in bit from `self`, and returns a tuple of the
+        /// operand and a borrow-in bit from `self`, and returns a tuple of the
         /// difference along with a boolean indicating whether an arithmetic
         /// overflow would occur. On overflow, the wrapped value is returned.
         ///
@@ -1646,7 +1646,7 @@ pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
         ///
         /// ```
         /// #![feature(bigint_helper_methods)]
-        /// // Only the  most significant word is signed.
+        /// // Only the most significant word is signed.
         /// //
         #[doc = concat!("//    6    8    (a = 6 × 2^", stringify!($BITS), " + 8)")]
         #[doc = concat!("// - -5    9    (b = -5 × 2^", stringify!($BITS), " + 9)")]
index 39462dca4ff3ea46b1f7c8ecf7216eb9b34b624a..7cc00e3f8d1b7205b3e470b8302d52bcc8ddaba4 100644 (file)
@@ -652,13 +652,14 @@ pub const fn is_none(&self) -> bool {
     ///
     /// # Examples
     ///
-    /// Converts an <code>Option<[String]></code> into an <code>Option<[usize]></code>, preserving
-    /// the original. The [`map`] method takes the `self` argument by value, consuming the original,
-    /// so this technique uses `as_ref` to first take an `Option` to a reference
-    /// to the value inside the original.
+    /// Calculates the length of an <code>Option<[String]></code> as an <code>Option<[usize]></code>
+    /// without moving the [`String`]. The [`map`] method takes the `self` argument by value,
+    /// consuming the original, so this technique uses `as_ref` to first take an `Option` to a
+    /// reference to the value inside the original.
     ///
     /// [`map`]: Option::map
     /// [String]: ../../std/string/struct.String.html "String"
+    /// [`String`]: ../../std/string/struct.String.html "String"
     ///
     /// ```
     /// let text: Option<String> = Some("Hello, world!".to_string());
@@ -946,8 +947,8 @@ pub const fn unwrap_or_default(self) -> T
     ///
     /// # Examples
     ///
-    /// Converts an <code>Option<[String]></code> into an <code>Option<[usize]></code>, consuming
-    /// the original:
+    /// Calculates the length of an <code>Option<[String]></code> as an
+    /// <code>Option<[usize]></code>, consuming the original:
     ///
     /// [String]: ../../std/string/struct.String.html "String"
     /// ```
index 2eb29d4f9c57410081309ed539b6c6f2fb34d1ac..ec0c9984841e68089536f9836cfe70e5bb7dcd81 100644 (file)
@@ -753,7 +753,7 @@ pub fn set(&mut self, value: P::Target)
 impl<'a, T: ?Sized> Pin<&'a T> {
     /// Constructs a new pin by mapping the interior value.
     ///
-    /// For example, if you  wanted to get a `Pin` of a field of something,
+    /// For example, if you wanted to get a `Pin` of a field of something,
     /// you could use this to get access to that field in one line of code.
     /// However, there are several gotchas with these "pinning projections";
     /// see the [`pin` module] documentation for further details on that topic.
@@ -856,7 +856,7 @@ pub const fn get_mut(self) -> &'a mut T
 
     /// Construct a new pin by mapping the interior value.
     ///
-    /// For example, if you  wanted to get a `Pin` of a field of something,
+    /// For example, if you wanted to get a `Pin` of a field of something,
     /// you could use this to get access to that field in one line of code.
     /// However, there are several gotchas with these "pinning projections";
     /// see the [`pin` module] documentation for further details on that topic.
index 5f30029eaa07d5c8d9be41bd6a6f221e13b0b43e..1ad9af1549a47fcdf12e46b391e12891c2fba0bd 100644 (file)
@@ -1701,7 +1701,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
         // offset is not a multiple of `stride`, the input pointer was misaligned and no pointer
         // offset will be able to produce a `p` aligned to the specified `a`.
         //
-        // The naive `-p (mod a)` equation  inhibits LLVM's ability to select instructions
+        // The naive `-p (mod a)` equation inhibits LLVM's ability to select instructions
         // like `lea`. We compute `(round_up_to_next_alignment(p, a) - p)` instead. This
         // redistributes operations around the load-bearing, but pessimizing `and` instruction
         // sufficiently for LLVM to be able to utilize the various optimizations it knows about.
index 06228976719f52f8e25c59010c4fab554b7ae4f5..90ab43d1289f0d22b3b2dcfecc81ccb5e71bdc88 100644 (file)
@@ -6,7 +6,7 @@
 use crate::cmp;
 use crate::cmp::Ordering;
 use crate::fmt;
-use crate::intrinsics::{assume, exact_div, unchecked_sub};
+use crate::intrinsics::assume;
 use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
 use crate::marker::{PhantomData, Send, Sized, Sync};
 use crate::mem::{self, SizedTypeProperties};
@@ -35,12 +35,6 @@ fn into_iter(self) -> IterMut<'a, T> {
     }
 }
 
-// Macro helper functions
-#[inline(always)]
-fn size_from_ptr<T>(_: *const T) -> usize {
-    mem::size_of::<T>()
-}
-
 /// Immutable slice iterator
 ///
 /// This struct is created by the [`iter`] method on [slices].
@@ -65,7 +59,7 @@ fn size_from_ptr<T>(_: *const T) -> usize {
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 pub struct Iter<'a, T: 'a> {
     ptr: NonNull<T>,
-    end: *const T, // If T is a ZST, this is actually ptr+len.  This encoding is picked so that
+    end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
     // ptr == end is a quick test for the Iterator being empty, that works
     // for both ZST and non-ZST.
     _marker: PhantomData<&'a T>,
@@ -186,7 +180,7 @@ fn as_ref(&self) -> &[T] {
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 pub struct IterMut<'a, T: 'a> {
     ptr: NonNull<T>,
-    end: *mut T, // If T is a ZST, this is actually ptr+len.  This encoding is picked so that
+    end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
     // ptr == end is a quick test for the Iterator being empty, that works
     // for both ZST and non-ZST.
     _marker: PhantomData<&'a mut T>,
index ce51d48e3e551901457c3af8d9783f9c544e2af5..0fd57b197aa97daa8838687de60165d6d3518372 100644 (file)
@@ -9,30 +9,20 @@ macro_rules! is_empty {
     };
 }
 
-// To get rid of some bounds checks (see `position`), we compute the length in a somewhat
-// unexpected way. (Tested by `codegen/slice-position-bounds-check`.)
 macro_rules! len {
     ($self: ident) => {{
         #![allow(unused_unsafe)] // we're sometimes used within an unsafe block
 
         let start = $self.ptr;
-        let size = size_from_ptr(start.as_ptr());
-        if size == 0 {
-            // This _cannot_ use `unchecked_sub` because we depend on wrapping
+        if T::IS_ZST {
+            // This _cannot_ use `ptr_sub` because we depend on wrapping
             // to represent the length of long ZST slice iterators.
             $self.end.addr().wrapping_sub(start.as_ptr().addr())
         } else {
-            // We know that `start <= end`, so can do better than `offset_from`,
-            // which needs to deal in signed.  By setting appropriate flags here
-            // we can tell LLVM this, which helps it remove bounds checks.
-            // SAFETY: By the type invariant, `start <= end`
-            let diff = unsafe { unchecked_sub($self.end.addr(), start.as_ptr().addr()) };
-            // By also telling LLVM that the pointers are apart by an exact
-            // multiple of the type size, it can optimize `len() == 0` down to
-            // `start == end` instead of `(end - start) < size`.
-            // SAFETY: By the type invariant, the pointers are aligned so the
-            //         distance between them must be a multiple of pointee size
-            unsafe { exact_div(diff, size) }
+            // To get rid of some bounds checks (see `position`), we use ptr_sub instead of
+            // offset_from (Tested by `codegen/slice-position-bounds-check`.)
+            // SAFETY: by the type invariant pointers are aligned and `start <= end`
+            unsafe { $self.end.sub_ptr(start.as_ptr()) }
         }
     }};
 }
index 2995cf0c6443f8a03eb37ae1201a0ecffeb1b272..df7fe2bf76dcda7568976ec874956de7aa6eb3f1 100644 (file)
@@ -703,7 +703,7 @@ const fn revswap<T>(a: &mut [T], b: &mut [T], n: usize) {
 
             // Because this function is first compiled in isolation,
             // this check tells LLVM that the indexing below is
-            // in-bounds.  Then after inlining -- once the actual
+            // in-bounds. Then after inlining -- once the actual
             // lengths of the slices are known -- it's removed.
             let (a, b) = (&mut a[..n], &mut b[..n]);
 
@@ -1248,7 +1248,7 @@ pub fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N> {
         ArrayChunksMut::new(self)
     }
 
-    /// Returns an iterator over overlapping windows of `N` elements of  a slice,
+    /// Returns an iterator over overlapping windows of `N` elements of a slice,
     /// starting at the beginning of the slice.
     ///
     /// This is the const generic equivalent of [`windows`].
@@ -2476,7 +2476,7 @@ pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
             let mid = left + size / 2;
 
             // SAFETY: the while condition means `size` is strictly positive, so
-            // `size/2 < size`.  Thus `left + size/2 < left + size`, which
+            // `size/2 < size`. Thus `left + size/2 < left + size`, which
             // coupled with the `left + size <= self.len()` invariant means
             // we have `left + size/2 < self.len()`, and this is in-bounds.
             let cmp = f(unsafe { self.get_unchecked(mid) });
index b8c0c3fd9493285b10117fb8ede4d341ee733607..4d2fcd917849caf5378a0c04f70a2a0dbf593fd4 100644 (file)
@@ -18,9 +18,9 @@ struct CopyOnDrop<T> {
 
 impl<T> Drop for CopyOnDrop<T> {
     fn drop(&mut self) {
-        // SAFETY:  This is a helper class.
-        //          Please refer to its usage for correctness.
-        //          Namely, one must be sure that `src` and `dst` does not overlap as required by `ptr::copy_nonoverlapping`.
+        // SAFETY: This is a helper class.
+        //         Please refer to its usage for correctness.
+        //         Namely, one must be sure that `src` and `dst` does not overlap as required by `ptr::copy_nonoverlapping`.
         unsafe {
             ptr::copy_nonoverlapping(self.src, self.dest, 1);
         }
index edc68d6fae51bcb03f01a099ff20b0f489af9780..14367eb09bc75e0e00c13ec9a4025638df8630f0 100644 (file)
@@ -1786,6 +1786,42 @@ pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T {
         // SAFETY: data races are prevented by atomic intrinsics.
         unsafe { atomic_xor(self.p.get(), core::ptr::invalid_mut(val), order).cast() }
     }
+
+    /// Returns a mutable pointer to the underlying pointer.
+    ///
+    /// Doing non-atomic reads and writes on the resulting integer can be a data race.
+    /// This method is mostly useful for FFI, where the function signature may use
+    /// `*mut *mut T` instead of `&AtomicPtr<T>`.
+    ///
+    /// Returning an `*mut` pointer from a shared reference to this atomic is safe because the
+    /// atomic types work with interior mutability. All modifications of an atomic change the value
+    /// through a shared reference, and can do so safely as long as they use atomic operations. Any
+    /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
+    /// restriction: operations on it must be atomic.
+    ///
+    /// # Examples
+    ///
+    /// ```ignore (extern-declaration)
+    /// #![feature(atomic_mut_ptr)]
+    //// use std::sync::atomic::AtomicPtr;
+    ///
+    /// extern "C" {
+    ///     fn my_atomic_op(arg: *mut *mut u32);
+    /// }
+    ///
+    /// let mut value = 17;
+    /// let atomic = AtomicPtr::new(&mut value);
+    ///
+    /// // SAFETY: Safe as long as `my_atomic_op` is atomic.
+    /// unsafe {
+    ///     my_atomic_op(atomic.as_mut_ptr());
+    /// }
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_mut_ptr", reason = "recently added", issue = "66893")]
+    pub fn as_mut_ptr(&self) -> *mut *mut T {
+        self.p.get()
+    }
 }
 
 #[cfg(target_has_atomic_load_store = "8")]
@@ -2678,9 +2714,9 @@ pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
             #[doc = concat!("    fn my_atomic_op(arg: *mut ", stringify!($int_type), ");")]
             /// }
             ///
-            #[doc = concat!("let mut atomic = ", stringify!($atomic_type), "::new(1);")]
+            #[doc = concat!("let atomic = ", stringify!($atomic_type), "::new(1);")]
             ///
-            // SAFETY: Safe as long as `my_atomic_op` is atomic.
+            /// // SAFETY: Safe as long as `my_atomic_op` is atomic.
             /// unsafe {
             ///     my_atomic_op(atomic.as_mut_ptr());
             /// }
index fd35d96c3fef814bd7952fb8b13afbcd7f31354f..39559cdbb5ea9c275b9b3db5b1db08291ec90c64 100644 (file)
@@ -1488,7 +1488,7 @@ macro_rules! panic_cases {
                 // optional:
                 //
                 // one or more similar inputs for which data[input] succeeds,
-                // and the corresponding output as an array.  This helps validate
+                // and the corresponding output as an array. This helps validate
                 // "critical points" where an input range straddles the boundary
                 // between valid and invalid.
                 // (such as the input `len..len`, which is just barely valid)
index 5c5ef0b1125a0d712a5ef787ce99ab5f0ec801f0..286ad68fd13e8fdf70efab2fb31cb122ec23286d 100644 (file)
@@ -1512,7 +1512,7 @@ pub fn is_dir(&self) -> bool {
     }
 
     /// Tests whether this file type represents a regular file.
-    /// The result is  mutually exclusive to the results of
+    /// The result is mutually exclusive to the results of
     /// [`is_dir`] and [`is_symlink`]; only zero or one of these
     /// tests may pass.
     ///
index f4e688eb926cc7bff8962f1f79ecca455d7c27bc..4c1b7d57684ddcf01b890b8742bc4732588248e8 100644 (file)
@@ -288,8 +288,8 @@ fn seek(&mut self, _: SeekFrom) -> io::Result<u64> {
     let mut reader = BufReader::with_capacity(5, ErrAfterFirstSeekReader { first_seek: true });
     assert_eq!(reader.fill_buf().ok(), Some(&[0, 0, 0, 0, 0][..]));
 
-    // The following seek will require two underlying seeks.  The first will
-    // succeed but the second will fail.  This should still invalidate the
+    // The following seek will require two underlying seeks. The first will
+    // succeed but the second will fail. This should still invalidate the
     // buffer.
     assert!(reader.seek(SeekFrom::Current(i64::MIN)).is_err());
     assert_eq!(reader.buffer().len(), 0);
index c6aa7c77dbc41d74ff1fb776de1d82c13be3a8bc..35de4860fe24925b215e84578bbba65c6a151fe5 100644 (file)
@@ -3,7 +3,7 @@
 //! This module is supported on Unix platforms and WASI, which both use a
 //! similar file descriptor system for referencing OS resources.
 
-#![stable(feature = "io_safety", since = "1.63.0")]
+#![stable(feature = "os_fd", since = "1.66.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 // `RawFd`, `AsRawFd`, etc.
@@ -19,7 +19,7 @@
 mod tests;
 
 // Export the types and traits for the public API.
-#[unstable(feature = "os_fd", issue = "98699")]
+#[stable(feature = "os_fd", since = "1.66.0")]
 pub use owned::*;
-#[unstable(feature = "os_fd", issue = "98699")]
+#[stable(feature = "os_fd", since = "1.66.0")]
 pub use raw::*;
index c16518577f7c466794127c9db77be3136e3d4c46..c41e093a7e5c6442f7022cd09d7f587f680af185 100644 (file)
@@ -100,7 +100,7 @@ pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
 
         // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
         // will never be supported, as this is a bare metal framework with
-        // no capabilities for multi-process execution.  While F_DUPFD is also
+        // no capabilities for multi-process execution. While F_DUPFD is also
         // not supported yet, it might be (currently it returns ENOSYS).
         #[cfg(target_os = "espidf")]
         let cmd = libc::F_DUPFD;
index b30dd8eecd84c210d709d998cd15a95e77b5d2dc..b0db3112e22fd34470d06fa910b73ef4d118f4a7 100644 (file)
@@ -306,11 +306,11 @@ pub mod panic_count {
     // and after increase and decrease, but not necessarily during their execution.
     //
     // Additionally, the top bit of GLOBAL_PANIC_COUNT (GLOBAL_ALWAYS_ABORT_FLAG)
-    // records whether panic::always_abort() has been called.  This can only be
+    // records whether panic::always_abort() has been called. This can only be
     // set, never cleared.
     // panic::always_abort() is usually called to prevent memory allocations done by
     // the panic handling in the child created by `libc::fork`.
-    // Memory allocations performed in  a child created with `libc::fork` are undefined
+    // Memory allocations performed in a child created with `libc::fork` are undefined
     // behavior in most operating systems.
     // Accessing LOCAL_PANIC_COUNT in a child created by `libc::fork` would lead to a memory
     // allocation. Only GLOBAL_PANIC_COUNT can be accessed in this situation. This is
index 82d68369312f9d09d6fd867c4c422c720246d076..c3593264e520b3243f98c01cbf80f12e9fa0b44c 100644 (file)
@@ -607,7 +607,7 @@ pub struct Components<'a> {
 
     // true if path *physically* has a root separator; for most Windows
     // prefixes, it may have a "logical" root separator for the purposes of
-    // normalization, e.g.,  \\server\share == \\server\share\.
+    // normalization, e.g., \\server\share == \\server\share\.
     has_physical_root: bool,
 
     // The iterator is double-ended, and these two states keep track of what has
@@ -3177,9 +3177,9 @@ fn into_iter(self) -> Iter<'a> {
 }
 
 macro_rules! impl_cmp {
-    ($lhs:ty, $rhs: ty) => {
+    (<$($life:lifetime),*> $lhs:ty, $rhs: ty) => {
         #[stable(feature = "partialeq_path", since = "1.6.0")]
-        impl<'a, 'b> PartialEq<$rhs> for $lhs {
+        impl<$($life),*> PartialEq<$rhs> for $lhs {
             #[inline]
             fn eq(&self, other: &$rhs) -> bool {
                 <Path as PartialEq>::eq(self, other)
@@ -3187,7 +3187,7 @@ fn eq(&self, other: &$rhs) -> bool {
         }
 
         #[stable(feature = "partialeq_path", since = "1.6.0")]
-        impl<'a, 'b> PartialEq<$lhs> for $rhs {
+        impl<$($life),*> PartialEq<$lhs> for $rhs {
             #[inline]
             fn eq(&self, other: &$lhs) -> bool {
                 <Path as PartialEq>::eq(self, other)
@@ -3195,7 +3195,7 @@ fn eq(&self, other: &$lhs) -> bool {
         }
 
         #[stable(feature = "cmp_path", since = "1.8.0")]
-        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
+        impl<$($life),*> PartialOrd<$rhs> for $lhs {
             #[inline]
             fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
                 <Path as PartialOrd>::partial_cmp(self, other)
@@ -3203,7 +3203,7 @@ fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
         }
 
         #[stable(feature = "cmp_path", since = "1.8.0")]
-        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
+        impl<$($life),*> PartialOrd<$lhs> for $rhs {
             #[inline]
             fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
                 <Path as PartialOrd>::partial_cmp(self, other)
@@ -3212,16 +3212,16 @@ fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
     };
 }
 
-impl_cmp!(PathBuf, Path);
-impl_cmp!(PathBuf, &'a Path);
-impl_cmp!(Cow<'a, Path>, Path);
-impl_cmp!(Cow<'a, Path>, &'b Path);
-impl_cmp!(Cow<'a, Path>, PathBuf);
+impl_cmp!(<> PathBuf, Path);
+impl_cmp!(<'a> PathBuf, &'a Path);
+impl_cmp!(<'a> Cow<'a, Path>, Path);
+impl_cmp!(<'a, 'b> Cow<'a, Path>, &'b Path);
+impl_cmp!(<'a> Cow<'a, Path>, PathBuf);
 
 macro_rules! impl_cmp_os_str {
-    ($lhs:ty, $rhs: ty) => {
+    (<$($life:lifetime),*> $lhs:ty, $rhs: ty) => {
         #[stable(feature = "cmp_path", since = "1.8.0")]
-        impl<'a, 'b> PartialEq<$rhs> for $lhs {
+        impl<$($life),*> PartialEq<$rhs> for $lhs {
             #[inline]
             fn eq(&self, other: &$rhs) -> bool {
                 <Path as PartialEq>::eq(self, other.as_ref())
@@ -3229,7 +3229,7 @@ fn eq(&self, other: &$rhs) -> bool {
         }
 
         #[stable(feature = "cmp_path", since = "1.8.0")]
-        impl<'a, 'b> PartialEq<$lhs> for $rhs {
+        impl<$($life),*> PartialEq<$lhs> for $rhs {
             #[inline]
             fn eq(&self, other: &$lhs) -> bool {
                 <Path as PartialEq>::eq(self.as_ref(), other)
@@ -3237,7 +3237,7 @@ fn eq(&self, other: &$lhs) -> bool {
         }
 
         #[stable(feature = "cmp_path", since = "1.8.0")]
-        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
+        impl<$($life),*> PartialOrd<$rhs> for $lhs {
             #[inline]
             fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
                 <Path as PartialOrd>::partial_cmp(self, other.as_ref())
@@ -3245,7 +3245,7 @@ fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
         }
 
         #[stable(feature = "cmp_path", since = "1.8.0")]
-        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
+        impl<$($life),*> PartialOrd<$lhs> for $rhs {
             #[inline]
             fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
                 <Path as PartialOrd>::partial_cmp(self.as_ref(), other)
@@ -3254,20 +3254,20 @@ fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
     };
 }
 
-impl_cmp_os_str!(PathBuf, OsStr);
-impl_cmp_os_str!(PathBuf, &'a OsStr);
-impl_cmp_os_str!(PathBuf, Cow<'a, OsStr>);
-impl_cmp_os_str!(PathBuf, OsString);
-impl_cmp_os_str!(Path, OsStr);
-impl_cmp_os_str!(Path, &'a OsStr);
-impl_cmp_os_str!(Path, Cow<'a, OsStr>);
-impl_cmp_os_str!(Path, OsString);
-impl_cmp_os_str!(&'a Path, OsStr);
-impl_cmp_os_str!(&'a Path, Cow<'b, OsStr>);
-impl_cmp_os_str!(&'a Path, OsString);
-impl_cmp_os_str!(Cow<'a, Path>, OsStr);
-impl_cmp_os_str!(Cow<'a, Path>, &'b OsStr);
-impl_cmp_os_str!(Cow<'a, Path>, OsString);
+impl_cmp_os_str!(<> PathBuf, OsStr);
+impl_cmp_os_str!(<'a> PathBuf, &'a OsStr);
+impl_cmp_os_str!(<'a> PathBuf, Cow<'a, OsStr>);
+impl_cmp_os_str!(<> PathBuf, OsString);
+impl_cmp_os_str!(<> Path, OsStr);
+impl_cmp_os_str!(<'a> Path, &'a OsStr);
+impl_cmp_os_str!(<'a> Path, Cow<'a, OsStr>);
+impl_cmp_os_str!(<> Path, OsString);
+impl_cmp_os_str!(<'a> &'a Path, OsStr);
+impl_cmp_os_str!(<'a, 'b> &'a Path, Cow<'b, OsStr>);
+impl_cmp_os_str!(<'a> &'a Path, OsString);
+impl_cmp_os_str!(<'a> Cow<'a, Path>, OsStr);
+impl_cmp_os_str!(<'a, 'b> Cow<'a, Path>, &'b OsStr);
+impl_cmp_os_str!(<'a> Cow<'a, Path>, OsString);
 
 #[stable(since = "1.7.0", feature = "strip_prefix")]
 impl fmt::Display for StripPrefixError {
index f71edc6c525a2aeb61abe424c19588741786326b..c1e3e48b04468c8c501d45392b3c06b35fa34ac8 100644 (file)
@@ -168,7 +168,7 @@ fn start_send(&self, token: &mut Token) -> bool {
                         return true;
                     }
                     Err(_) => {
-                        backoff.spin();
+                        backoff.spin_light();
                         tail = self.tail.load(Ordering::Relaxed);
                     }
                 }
@@ -182,11 +182,11 @@ fn start_send(&self, token: &mut Token) -> bool {
                     return false;
                 }
 
-                backoff.spin();
+                backoff.spin_light();
                 tail = self.tail.load(Ordering::Relaxed);
             } else {
                 // Snooze because we need to wait for the stamp to get updated.
-                backoff.snooze();
+                backoff.spin_heavy();
                 tail = self.tail.load(Ordering::Relaxed);
             }
         }
@@ -251,7 +251,7 @@ fn start_recv(&self, token: &mut Token) -> bool {
                         return true;
                     }
                     Err(_) => {
-                        backoff.spin();
+                        backoff.spin_light();
                         head = self.head.load(Ordering::Relaxed);
                     }
                 }
@@ -273,11 +273,11 @@ fn start_recv(&self, token: &mut Token) -> bool {
                     }
                 }
 
-                backoff.spin();
+                backoff.spin_light();
                 head = self.head.load(Ordering::Relaxed);
             } else {
                 // Snooze because we need to wait for the stamp to get updated.
-                backoff.snooze();
+                backoff.spin_heavy();
                 head = self.head.load(Ordering::Relaxed);
             }
         }
@@ -330,7 +330,7 @@ pub(crate) fn send(
                 if backoff.is_completed() {
                     break;
                 } else {
-                    backoff.spin();
+                    backoff.spin_light();
                 }
             }
 
index 2d5b2fb3b231d35c6bc86c575ae58be990e885b2..ec6c0726ac790304403e374be47c6246c50f66dc 100644 (file)
@@ -46,7 +46,7 @@ impl<T> Slot<T> {
     fn wait_write(&self) {
         let backoff = Backoff::new();
         while self.state.load(Ordering::Acquire) & WRITE == 0 {
-            backoff.snooze();
+            backoff.spin_heavy();
         }
     }
 }
@@ -82,7 +82,7 @@ fn wait_next(&self) -> *mut Block<T> {
             if !next.is_null() {
                 return next;
             }
-            backoff.snooze();
+            backoff.spin_heavy();
         }
     }
 
@@ -191,7 +191,7 @@ fn start_send(&self, token: &mut Token) -> bool {
 
             // If we reached the end of the block, wait until the next one is installed.
             if offset == BLOCK_CAP {
-                backoff.snooze();
+                backoff.spin_heavy();
                 tail = self.tail.index.load(Ordering::Acquire);
                 block = self.tail.block.load(Ordering::Acquire);
                 continue;
@@ -247,7 +247,7 @@ fn start_send(&self, token: &mut Token) -> bool {
                     return true;
                 },
                 Err(_) => {
-                    backoff.spin();
+                    backoff.spin_light();
                     tail = self.tail.index.load(Ordering::Acquire);
                     block = self.tail.block.load(Ordering::Acquire);
                 }
@@ -286,7 +286,7 @@ fn start_recv(&self, token: &mut Token) -> bool {
 
             // If we reached the end of the block, wait until the next one is installed.
             if offset == BLOCK_CAP {
-                backoff.snooze();
+                backoff.spin_heavy();
                 head = self.head.index.load(Ordering::Acquire);
                 block = self.head.block.load(Ordering::Acquire);
                 continue;
@@ -320,7 +320,7 @@ fn start_recv(&self, token: &mut Token) -> bool {
             // The block can be null here only if the first message is being sent into the channel.
             // In that case, just wait until it gets initialized.
             if block.is_null() {
-                backoff.snooze();
+                backoff.spin_heavy();
                 head = self.head.index.load(Ordering::Acquire);
                 block = self.head.block.load(Ordering::Acquire);
                 continue;
@@ -351,7 +351,7 @@ fn start_recv(&self, token: &mut Token) -> bool {
                     return true;
                 },
                 Err(_) => {
-                    backoff.spin();
+                    backoff.spin_light();
                     head = self.head.index.load(Ordering::Acquire);
                     block = self.head.block.load(Ordering::Acquire);
                 }
@@ -542,7 +542,7 @@ fn discard_all_messages(&self) {
             // New updates to tail will be rejected by MARK_BIT and aborted unless it's
             // at boundary. We need to wait for the updates take affect otherwise there
             // can be memory leaks.
-            backoff.snooze();
+            backoff.spin_heavy();
             tail = self.tail.index.load(Ordering::Acquire);
         }
 
index cef99c58843009bda1d5ddbe5b02fd64c93f32e2..7a602cecd3b896455a8882b66a9517b3885670ca 100644 (file)
@@ -43,7 +43,7 @@
 use crate::fmt;
 use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::time::{Duration, Instant};
-use error::*;
+pub use error::*;
 
 /// Creates a channel of unbounded capacity.
 ///
index e030c55ce8f6161753b3e517535fef6f49861344..cfe42750d5239a6a46ab629027581df795c12129 100644 (file)
@@ -91,9 +91,8 @@ fn deref_mut(&mut self) -> &mut T {
 }
 
 const SPIN_LIMIT: u32 = 6;
-const YIELD_LIMIT: u32 = 10;
 
-/// Performs exponential backoff in spin loops.
+/// Performs quadratic backoff in spin loops.
 pub struct Backoff {
     step: Cell<u32>,
 }
@@ -104,25 +103,27 @@ pub fn new() -> Self {
         Backoff { step: Cell::new(0) }
     }
 
-    /// Backs off in a lock-free loop.
+    /// Backs off using lightweight spinning.
     ///
-    /// This method should be used when we need to retry an operation because another thread made
-    /// progress.
+    /// This method should be used for:
+    ///     - Retrying an operation because another thread made progress. i.e. on CAS failure.
+    ///     - Waiting for an operation to complete by spinning optimistically for a few iterations
+    ///     before falling back to parking the thread (see `Backoff::is_completed`).
     #[inline]
-    pub fn spin(&self) {
+    pub fn spin_light(&self) {
         let step = self.step.get().min(SPIN_LIMIT);
         for _ in 0..step.pow(2) {
             crate::hint::spin_loop();
         }
 
-        if self.step.get() <= SPIN_LIMIT {
-            self.step.set(self.step.get() + 1);
-        }
+        self.step.set(self.step.get() + 1);
     }
 
-    /// Backs off in a blocking loop.
+    /// Backs off using heavyweight spinning.
+    ///
+    /// This method should be used in blocking loops where parking the thread is not an option.
     #[inline]
-    pub fn snooze(&self) {
+    pub fn spin_heavy(&self) {
         if self.step.get() <= SPIN_LIMIT {
             for _ in 0..self.step.get().pow(2) {
                 crate::hint::spin_loop()
@@ -131,14 +132,12 @@ pub fn snooze(&self) {
             crate::thread::yield_now();
         }
 
-        if self.step.get() <= YIELD_LIMIT {
-            self.step.set(self.step.get() + 1);
-        }
+        self.step.set(self.step.get() + 1);
     }
 
-    /// Returns `true` if quadratic backoff has completed and blocking the thread is advised.
+    /// Returns `true` if quadratic backoff has completed and parking the thread is advised.
     #[inline]
     pub fn is_completed(&self) -> bool {
-        self.step.get() > YIELD_LIMIT
+        self.step.get() > SPIN_LIMIT
     }
 }
index fccd6c29a7e462f5993bb30c72526d3fe44c0913..33f768dcbe90296d9a98cbc191ad65adc4ce01aa 100644 (file)
@@ -57,7 +57,7 @@ fn message_on_stack(msg: T) -> Packet<T> {
     fn wait_ready(&self) {
         let backoff = Backoff::new();
         while !self.ready.load(Ordering::Acquire) {
-            backoff.snooze();
+            backoff.spin_heavy();
         }
     }
 }
index adb488d4378f0391140e6eadf604603720f8776f..6e3c28f10bb1ba9e31298fa90d34b54029ae32bd 100644 (file)
@@ -738,6 +738,15 @@ pub fn send(&self, t: T) -> Result<(), SendError<T>> {
     pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
         self.inner.try_send(t)
     }
+
+    // Attempts to send for a value on this receiver, returning an error if the
+    // corresponding channel has hung up, or if it waits more than `timeout`.
+    //
+    // This method is currently private and only used for tests.
+    #[allow(unused)]
+    fn send_timeout(&self, t: T, timeout: Duration) -> Result<(), mpmc::SendTimeoutError<T>> {
+        self.inner.send_timeout(t, timeout)
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
index 63c79436974d592cf6bb9a6a6f017e6dc5ea0fb5..9d2f92ffc9b1415ec6e93a93189f10f64ed35042 100644 (file)
@@ -1,5 +1,6 @@
 use super::*;
 use crate::env;
+use crate::sync::mpmc::SendTimeoutError;
 use crate::thread;
 use crate::time::Duration;
 
@@ -41,6 +42,13 @@ fn recv_timeout() {
     assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1));
 }
 
+#[test]
+fn send_timeout() {
+    let (tx, _rx) = sync_channel::<i32>(1);
+    assert_eq!(tx.send_timeout(1, Duration::from_millis(1)), Ok(()));
+    assert_eq!(tx.send_timeout(1, Duration::from_millis(1)), Err(SendTimeoutError::Timeout(1)));
+}
+
 #[test]
 fn smoke_threads() {
     let (tx, rx) = sync_channel::<i32>(0);
index 535703be33f06474724a37802df9b6d6fb4f7353..19350b83fab884d8cf3ebd0efdabb7b9de30d4a3 100644 (file)
@@ -294,7 +294,7 @@ fn drop(&mut self) {
                 // Terminate and delete the task
                 // Safety: `self.task` still represents a task we own (because
                 //         this method or `join_inner` is called only once for
-                //         each `Thread`). The task  indicated that it's safe to
+                //         each `Thread`). The task indicated that it's safe to
                 //         delete by entering the `FINISHED` state.
                 unsafe { terminate_and_delete_task(self.task) };
 
index aea0c26ee8b60e8a2045208b6228a0dc5812d7b5..8e1f35d6cc92011cac5704c196d5384390e3de3c 100644 (file)
@@ -149,12 +149,13 @@ unsafe fn try_statx(
     ) -> Option<io::Result<FileAttr>> {
         use crate::sync::atomic::{AtomicU8, Ordering};
 
-        // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx`
-        // We store the availability in global to avoid unnecessary syscalls.
-        // 0: Unknown
-        // 1: Not available
-        // 2: Available
-        static STATX_STATE: AtomicU8 = AtomicU8::new(0);
+        // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx`.
+        // We check for it on first failure and remember availability to avoid having to
+        // do it again.
+        #[repr(u8)]
+        enum STATX_STATE{ Unknown = 0, Present, Unavailable }
+        static STATX_SAVED_STATE: AtomicU8 = AtomicU8::new(STATX_STATE::Unknown as u8);
+
         syscall! {
             fn statx(
                 fd: c_int,
@@ -165,31 +166,44 @@ fn statx(
             ) -> c_int
         }
 
-        match STATX_STATE.load(Ordering::Relaxed) {
-            0 => {
-                // It is a trick to call `statx` with null pointers to check if the syscall
-                // is available. According to the manual, it is expected to fail with EFAULT.
-                // We do this mainly for performance, since it is nearly hundreds times
-                // faster than a normal successful call.
-                let err = cvt(statx(0, ptr::null(), 0, libc::STATX_ALL, ptr::null_mut()))
-                    .err()
-                    .and_then(|e| e.raw_os_error());
-                // We don't check `err == Some(libc::ENOSYS)` because the syscall may be limited
-                // and returns `EPERM`. Listing all possible errors seems not a good idea.
-                // See: https://github.com/rust-lang/rust/issues/65662
-                if err != Some(libc::EFAULT) {
-                    STATX_STATE.store(1, Ordering::Relaxed);
-                    return None;
-                }
-                STATX_STATE.store(2, Ordering::Relaxed);
-            }
-            1 => return None,
-            _ => {}
+        if STATX_SAVED_STATE.load(Ordering::Relaxed) == STATX_STATE::Unavailable as u8 {
+            return None;
         }
 
         let mut buf: libc::statx = mem::zeroed();
         if let Err(err) = cvt(statx(fd, path, flags, mask, &mut buf)) {
-            return Some(Err(err));
+            if STATX_SAVED_STATE.load(Ordering::Relaxed) == STATX_STATE::Present as u8 {
+                return Some(Err(err));
+            }
+
+            // Availability not checked yet.
+            //
+            // First try the cheap way.
+            if err.raw_os_error() == Some(libc::ENOSYS) {
+                STATX_SAVED_STATE.store(STATX_STATE::Unavailable as u8, Ordering::Relaxed);
+                return None;
+            }
+
+            // Error other than `ENOSYS` is not a good enough indicator -- it is
+            // known that `EPERM` can be returned as a result of using seccomp to
+            // block the syscall.
+            // Availability is checked by performing a call which expects `EFAULT`
+            // if the syscall is usable.
+            // See: https://github.com/rust-lang/rust/issues/65662
+            // FIXME this can probably just do the call if `EPERM` was received, but
+            // previous iteration of the code checked it for all errors and for now
+            // this is retained.
+            // FIXME what about transient conditions like `ENOMEM`?
+            let err2 = cvt(statx(0, ptr::null(), 0, libc::STATX_ALL, ptr::null_mut()))
+                .err()
+                .and_then(|e| e.raw_os_error());
+            if err2 == Some(libc::EFAULT) {
+                STATX_SAVED_STATE.store(STATX_STATE::Present as u8, Ordering::Relaxed);
+                return Some(Err(err));
+            } else {
+                STATX_SAVED_STATE.store(STATX_STATE::Unavailable as u8, Ordering::Relaxed);
+                return None;
+            }
         }
 
         // We cannot fill `stat64` exhaustively because of private padding fields.
@@ -600,13 +614,13 @@ fn next(&mut self) -> Option<io::Result<DirEntry>> {
             loop {
                 // As of POSIX.1-2017, readdir() is not required to be thread safe; only
                 // readdir_r() is. However, readdir_r() cannot correctly handle platforms
-                // with unlimited or variable NAME_MAX.  Many modern platforms guarantee
+                // with unlimited or variable NAME_MAX. Many modern platforms guarantee
                 // thread safety for readdir() as long an individual DIR* is not accessed
                 // concurrently, which is sufficient for Rust.
                 super::os::set_errno(0);
                 let entry_ptr = readdir64(self.inner.dirp.0);
                 if entry_ptr.is_null() {
-                    // We either encountered an error, or reached the end.  Either way,
+                    // We either encountered an error, or reached the end. Either way,
                     // the next call to next() should return None.
                     self.end_of_stream = true;
 
index 0f7107122b7e86ecbba33e56b46efcd52ef2fcbc..73b9bef7e2ac9b68b3b8480d27a2e288a7c4cd24 100644 (file)
@@ -587,7 +587,7 @@ fn copy_file_range(
                         // - copy_file_range file is immutable or syscall is blocked by seccomp¹ (EPERM)
                         // - copy_file_range cannot be used with pipes or device nodes (EINVAL)
                         // - the writer fd was opened with O_APPEND (EBADF²)
-                        // and no bytes were written successfully yet.  (All these errnos should
+                        // and no bytes were written successfully yet. (All these errnos should
                         // not be returned if something was already written, but they happen in
                         // the wild, see #91152.)
                         //
index 4c99d758c93a3156e1ccfafe6252443c4f4468b5..d4c7e58b34d2ef85c2d5864962928745d6eebd14 100644 (file)
@@ -262,7 +262,7 @@ pub fn signal(&self) -> Option<i32> {
     // available on Fuchsia.
     //
     // It does not appear that Fuchsia is Unix-like enough to implement ExitStatus (or indeed many
-    // other things from std::os::unix) properly.  This veneer is always going to be a bodge.  So
+    // other things from std::os::unix) properly. This veneer is always going to be a bodge. So
     // while I don't know if these implementations are actually correct, I think they will do for
     // now at least.
     pub fn core_dumped(&self) -> bool {
@@ -277,9 +277,9 @@ pub fn continued(&self) -> bool {
 
     pub fn into_raw(&self) -> c_int {
         // We don't know what someone who calls into_raw() will do with this value, but it should
-        // have the conventional Unix representation.  Despite the fact that this is not
+        // have the conventional Unix representation. Despite the fact that this is not
         // standardised in SuS or POSIX, all Unix systems encode the signal and exit status the
-        // same way.  (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every
+        // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every
         // Unix.)
         //
         // The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may
@@ -287,14 +287,14 @@ pub fn into_raw(&self) -> c_int {
         // different Unix variant.
         //
         // The other view would be to say that the caller on Fuchsia ought to know that `into_raw`
-        // will give a raw Fuchsia status (whatever that is - I don't know, personally).  That is
+        // will give a raw Fuchsia status (whatever that is - I don't know, personally). That is
         // not possible here because we must return a c_int because that's what Unix (including
         // SuS and POSIX) say a wait status is, but Fuchsia apparently uses a u64, so it won't
         // necessarily fit.
         //
         // It seems to me that the right answer would be to provide std::os::fuchsia with its
         // own ExitStatusExt, rather that trying to provide a not very convincing imitation of
-        // Unix.  Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia.  But
+        // Unix. Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia. But
         // fixing this up that is beyond the scope of my efforts now.
         let exit_status_as_if_unix: u8 = self.0.try_into().expect("Fuchsia process return code bigger than 8 bits, but std::os::unix::ExitStatusExt::into_raw() was called to try to convert the value into a traditional Unix-style wait status, which cannot represent values greater than 255.");
         let wait_status_as_if_unix = (exit_status_as_if_unix as c_int) << 8;
index 39d1c8b1d8ebc75d0da500c882e4683bd167ba40..c2c4aa1c9dfceff80d98f79999e772fd324c28de 100644 (file)
@@ -666,11 +666,11 @@ fn exited(&self) -> bool {
     }
 
     pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
-        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0.  This is
+        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
         // true on all actual versions of Unix, is widely assumed, and is specified in SuS
-        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html .  If it is not
+        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not
         // true for a platform pretending to be Unix, the tests (our doctests, and also
-        // procsss_unix/tests.rs) will spot it.  `ExitStatusError::code` assumes this too.
+        // procsss_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
         match NonZero_c_int::try_from(self.0) {
             /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
             /* was zero, couldn't convert */ Err(_) => Ok(()),
index 4c87f633a260919fb958b204c0cdf6c1a2ff9aaf..e5e1f956bc351e43c16878ea2d37b6b65d876025 100644 (file)
@@ -19,17 +19,17 @@ fn exitstatus_display_tests() {
     t(0x00000, "exit status: 0");
     t(0x0ff00, "exit status: 255");
 
-    // On MacOS, 0x0137f is WIFCONTINUED, not WIFSTOPPED.  Probably *BSD is similar.
+    // On MacOS, 0x0137f is WIFCONTINUED, not WIFSTOPPED. Probably *BSD is similar.
     //   https://github.com/rust-lang/rust/pull/82749#issuecomment-790525956
     // The purpose of this test is to test our string formatting, not our understanding of the wait
-    // status magic numbers.  So restrict these to Linux.
+    // status magic numbers. So restrict these to Linux.
     if cfg!(target_os = "linux") {
         t(0x0137f, "stopped (not terminated) by signal: 19 (SIGSTOP)");
         t(0x0ffff, "continued (WIFCONTINUED)");
     }
 
     // Testing "unrecognised wait status" is hard because the wait.h macros typically
-    // assume that the value came from wait and isn't mad.  With the glibc I have here
+    // assume that the value came from wait and isn't mad. With the glibc I have here
     // this works:
     if cfg!(all(target_os = "linux", target_env = "gnu")) {
         t(0x000ff, "unrecognised wait status: 255 0xff");
index f549d37c301165fad9019ca014f5770398cdcf5c..569a4b149125d618bd8847691b7b4434d8ab0cb7 100644 (file)
@@ -195,11 +195,11 @@ fn exited(&self) -> bool {
     }
 
     pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
-        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0.  This is
+        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
         // true on all actual versions of Unix, is widely assumed, and is specified in SuS
-        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html .  If it is not
+        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not
         // true for a platform pretending to be Unix, the tests (our doctests, and also
-        // procsss_unix/tests.rs) will spot it.  `ExitStatusError::code` assumes this too.
+        // procsss_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
         match NonZero_c_int::try_from(self.0) {
             Ok(failure) => Err(ExitStatusError(failure)),
             Err(_) => Ok(()),
index b251949bda207e1bf0fcfa99750e7311f4412dce..2a1830d060edc5cb934998bd1cac294e3512d281 100644 (file)
@@ -73,7 +73,7 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
                 n => {
                     assert_eq!(n, libc::EINVAL);
                     // EINVAL means |stack_size| is either too small or not a
-                    // multiple of the system page size.  Because it's definitely
+                    // multiple of the system page size. Because it's definitely
                     // >= PTHREAD_STACK_MIN, it must be an alignment issue.
                     // Round up to the nearest page and try again.
                     let page_size = os::page_size();
@@ -755,10 +755,10 @@ pub unsafe fn init() -> Option<Guard> {
         if cfg!(all(target_os = "linux", not(target_env = "musl"))) {
             // Linux doesn't allocate the whole stack right away, and
             // the kernel has its own stack-guard mechanism to fault
-            // when growing too close to an existing mapping.  If we map
+            // when growing too close to an existing mapping. If we map
             // our own guard, then the kernel starts enforcing a rather
             // large gap above that, rendering much of the possible
-            // stack space useless.  See #43052.
+            // stack space useless. See #43052.
             //
             // Instead, we'll just note where we expect rlimit to start
             // faulting, so our handler can report "stack overflow", and
@@ -774,14 +774,14 @@ pub unsafe fn init() -> Option<Guard> {
             None
         } else if cfg!(target_os = "freebsd") {
             // FreeBSD's stack autogrows, and optionally includes a guard page
-            // at the bottom.  If we try to remap the bottom of the stack
-            // ourselves, FreeBSD's guard page moves upwards.  So we'll just use
+            // at the bottom. If we try to remap the bottom of the stack
+            // ourselves, FreeBSD's guard page moves upwards. So we'll just use
             // the builtin guard page.
             let stackptr = get_stack_start_aligned()?;
             let guardaddr = stackptr.addr();
             // Technically the number of guard pages is tunable and controlled
             // by the security.bsd.stack_guard_page sysctl, but there are
-            // few reasons to change it from the default.  The default value has
+            // few reasons to change it from the default. The default value has
             // been 1 ever since FreeBSD 11.1 and 10.4.
             const GUARD_PAGES: usize = 1;
             let guard = guardaddr..guardaddr + GUARD_PAGES * page_size;
@@ -877,9 +877,9 @@ pub unsafe fn current() -> Option<Guard> {
             } else if cfg!(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))
             {
                 // glibc used to include the guard area within the stack, as noted in the BUGS
-                // section of `man pthread_attr_getguardsize`.  This has been corrected starting
+                // section of `man pthread_attr_getguardsize`. This has been corrected starting
                 // with glibc 2.27, and in some distro backports, so the guard is now placed at the
-                // end (below) the stack.  There's no easy way for us to know which we have at
+                // end (below) the stack. There's no easy way for us to know which we have at
                 // runtime, so we'll just match any fault in the range right above or below the
                 // stack base to call that fault a stack overflow.
                 Some(stackaddr - guardsize..stackaddr + guardsize)
index 352337ba322371d77b89aedc5d1a7cc756351f0d..d7adeb266ed93f30918a8fab50137fec6852be98 100644 (file)
@@ -157,7 +157,7 @@ fn next(&mut self) -> Option<PathBuf> {
         // Double quotes are used as a way of introducing literal semicolons
         // (since c:\some;dir is a valid Windows path). Double quotes are not
         // themselves permitted in path names, so there is no way to escape a
-        // double quote.  Quoted regions can appear in arbitrary locations, so
+        // double quote. Quoted regions can appear in arbitrary locations, so
         //
         //   c:\foo;c:\som"e;di"r;c:\bar
         //
index c5c9e97e646fb94fa6960c1da38ba09f1265f04b..1cb576c95947a5aeddde2a708fd0665ec9c49a56 100644 (file)
@@ -26,7 +26,7 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
 
         // FIXME On UNIX, we guard against stack sizes that are too small but
         // that's because pthreads enforces that stacks are at least
-        // PTHREAD_STACK_MIN bytes big.  Windows has no such lower limit, it's
+        // PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's
         // just that below a certain threshold you can't do anything useful.
         // That threshold is application and architecture-specific, however.
         let ret = c::CreateThread(
index 30dc4ff855315d2c0f0bca55669d580e50d7f92e..69fb529d7f563b56e310bb85cf6b7a1f8282b6f6 100644 (file)
@@ -116,7 +116,7 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt
     } else {
         if !opts.nocapture {
             // If we encounter a non-unwinding panic, flush any captured output from the current test,
-            // and stop  capturing output to ensure that the non-unwinding panic message is visible.
+            // and stop capturing output to ensure that the non-unwinding panic message is visible.
             // We also acquire the locks for both output streams to prevent output from other threads
             // from interleaving with the panic message or appearing after it.
             let builtin_panic_hook = panic::take_hook();
index 87b91f34498a37085fd81b98fbbe8e60f798e54f..3e8ccc91ab0517fd8ef676174a3e1d56c5ef9d59 100644 (file)
@@ -30,7 +30,7 @@ pub(crate) fn get_dbpath_for_term(term: &str) -> Option<PathBuf> {
         }
     } else {
         // Found nothing in TERMINFO_DIRS, use the default paths:
-        // According to  /etc/terminfo/README, after looking at
+        // According to /etc/terminfo/README, after looking at
         // ~/.terminfo, ncurses will search /etc/terminfo, then
         // /lib/terminfo, and eventually /usr/share/terminfo.
         // On Haiku the database can be found at /boot/system/data/terminfo
index 90ab802697088002cf3021cfe280d2d55d72da75..7b357da2ffc475c9497b3f13e67fa6fa53449a83 100644 (file)
@@ -1,8 +1,7 @@
-This directory contains the source code of the rust project, including:
+This directory contains some source code for the Rust project, including:
 
-- The test suite
 - The bootstrapping build system
-- Various submodules for tools, like cargo, etc.
+- Various submodules for tools, like cargo, tidy, etc.
 
 For more information on how various parts of the compiler work, see the [rustc dev guide].
 
index 1d5260228121bd18ce80dcb003f23e6b41d0284f..9611c866df5990c038640b5af106f7e0b79838e7 100644 (file)
@@ -154,6 +154,41 @@ fn main() {
         cmd.arg("-Z").arg("force-unstable-if-unmarked");
     }
 
+    // allow-features is handled from within this rustc wrapper because of
+    // issues with build scripts. Some packages use build scripts to
+    // dynamically detect if certain nightly features are available.
+    // There are different ways this causes problems:
+    //
+    // * rustix runs `rustc` on a small test program to see if the feature is
+    //   available (and sets a `cfg` if it is). It does not honor
+    //   CARGO_ENCODED_RUSTFLAGS.
+    // * proc-macro2 detects if `rustc -vV` says "nighty" or "dev" and enables
+    //   nightly features. It will scan CARGO_ENCODED_RUSTFLAGS for
+    //   -Zallow-features. Unfortunately CARGO_ENCODED_RUSTFLAGS is not set
+    //   for build-dependencies when --target is used.
+    //
+    // The issues above means we can't just use RUSTFLAGS, and we can't use
+    // `cargo -Zallow-features=…`. Passing it through here ensures that it
+    // always gets set. Unfortunately that also means we need to enable more
+    // features than we really want (like those for proc-macro2), but there
+    // isn't much of a way around it.
+    //
+    // I think it is unfortunate that build scripts are doing this at all,
+    // since changes to nightly features can cause crates to break even if the
+    // user didn't want or care about the use of the nightly features. I think
+    // nightly features should be opt-in only. Unfortunately the dynamic
+    // checks are now too wide spread that we just need to deal with it.
+    //
+    // If you want to try to remove this, I suggest working with the crate
+    // authors to remove the dynamic checking. Another option is to pursue
+    // https://github.com/rust-lang/cargo/issues/11244 and
+    // https://github.com/rust-lang/cargo/issues/4423, which will likely be
+    // very difficult, but could help expose -Zallow-features into build
+    // scripts so they could try to honor them.
+    if let Ok(allow_features) = env::var("RUSTC_ALLOW_FEATURES") {
+        cmd.arg(format!("-Zallow-features={allow_features}"));
+    }
+
     if let Ok(flags) = env::var("MAGIC_EXTRA_RUSTFLAGS") {
         for flag in flags.split(' ') {
             cmd.arg(flag);
index 52a83fa29c7047b3596a30d78a675cba601293bd..b4fc1d4f28da75e7a9513d723cad17118763e3dc 100644 (file)
@@ -1381,18 +1381,29 @@ pub fn cargo(
         // this), as well as #63012 which is the tracking issue for this
         // feature on the rustc side.
         cargo.arg("-Zbinary-dep-depinfo");
-        match mode {
-            Mode::ToolBootstrap => {
-                // Restrict the allowed features to those passed by rustbuild, so we don't depend on nightly accidentally.
-                rustflags.arg("-Zallow-features=binary-dep-depinfo");
-            }
-            Mode::ToolStd => {
-                // Right now this is just compiletest and a few other tools that build on stable.
-                // Allow them to use `feature(test)`, but nothing else.
-                rustflags.arg("-Zallow-features=binary-dep-depinfo,test,proc_macro_internals,proc_macro_diagnostic,proc_macro_span");
+        let allow_features = match mode {
+            Mode::ToolBootstrap | Mode::ToolStd => {
+                // Restrict the allowed features so we don't depend on nightly
+                // accidentally.
+                //
+                // binary-dep-depinfo is used by rustbuild itself for all
+                // compilations.
+                //
+                // Lots of tools depend on proc_macro2 and proc-macro-error.
+                // Those have build scripts which assume nightly features are
+                // available if the `rustc` version is "nighty" or "dev". See
+                // bin/rustc.rs for why that is a problem. Instead of labeling
+                // those features for each individual tool that needs them,
+                // just blanket allow them here.
+                //
+                // If this is ever removed, be sure to add something else in
+                // its place to keep the restrictions in place (or make a way
+                // to unset RUSTC_BOOTSTRAP).
+                "binary-dep-depinfo,proc_macro_span,proc_macro_span_shrink,proc_macro_diagnostic"
+                    .to_string()
             }
-            Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {}
-        }
+            Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustc => String::new(),
+        };
 
         cargo.arg("-j").arg(self.jobs().to_string());
 
@@ -1915,7 +1926,7 @@ pub fn cargo(
             }
         }
 
-        Cargo { command: cargo, rustflags, rustdocflags }
+        Cargo { command: cargo, rustflags, rustdocflags, allow_features }
     }
 
     /// Ensure that a given step is built, returning its output. This will
@@ -2094,6 +2105,7 @@ pub struct Cargo {
     command: Command,
     rustflags: Rustflags,
     rustdocflags: Rustflags,
+    allow_features: String,
 }
 
 impl Cargo {
@@ -2138,6 +2150,18 @@ pub fn current_dir(&mut self, dir: &Path) -> &mut Cargo {
         self.command.current_dir(dir);
         self
     }
+
+    /// Adds nightly-only features that this invocation is allowed to use.
+    ///
+    /// By default, all nightly features are allowed. Once this is called, it
+    /// will be restricted to the given set.
+    pub fn allow_features(&mut self, features: &str) -> &mut Cargo {
+        if !self.allow_features.is_empty() {
+            self.allow_features.push(',');
+        }
+        self.allow_features.push_str(features);
+        self
+    }
 }
 
 impl From<Cargo> for Command {
@@ -2152,6 +2176,10 @@ fn from(mut cargo: Cargo) -> Command {
             cargo.command.env("RUSTDOCFLAGS", rustdocflags);
         }
 
+        if !cargo.allow_features.is_empty() {
+            cargo.command.env("RUSTC_ALLOW_FEATURES", cargo.allow_features);
+        }
+
         cargo.command
     }
 }
index 2771bd2264ce2b55c9a06c928097ea7da119149a..4b8a58e87b64eb893a87c090b233b8866ab4ae60 100644 (file)
@@ -346,9 +346,7 @@ fn run(self, builder: &Builder<'_>) {
             &["rust-analyzer/in-rust-tree".to_owned()],
         );
 
-        cargo.rustflag(
-            "-Zallow-features=proc_macro_internals,proc_macro_diagnostic,proc_macro_span",
-        );
+        cargo.allow_features(crate::tool::RustAnalyzer::ALLOW_FEATURES);
 
         // For ./x.py clippy, don't check those targets because
         // linting tests and benchmarks can produce very noisy results
index 159f2fba671c99c6f1e46bbe1ca43ea604a0b906..6078e39ac9d3b8af5a7214921d91edff4c238385 100644 (file)
@@ -378,6 +378,7 @@ fn run(self, builder: &Builder<'_>) {
             SourceType::InTree,
             &["sysroot-abi".to_owned()],
         );
+        cargo.allow_features(tool::RustAnalyzer::ALLOW_FEATURES);
 
         let dir = builder.src.join(workspace_path);
         // needed by rust-analyzer to find its own text fixtures, cf.
@@ -690,7 +691,7 @@ fn run(self, builder: &Builder<'_>) {
         // We need `ToolStd` for the locally-built sysroot because
         // compiletest uses unstable features of the `test` crate.
         builder.ensure(compile::Std::new(compiler, host));
-        let cargo = tool::prepare_tool_cargo(
+        let mut cargo = tool::prepare_tool_cargo(
             builder,
             compiler,
             Mode::ToolStd,
@@ -700,6 +701,7 @@ fn run(self, builder: &Builder<'_>) {
             SourceType::InTree,
             &[],
         );
+        cargo.allow_features("test");
 
         try_run(builder, &mut cargo.into());
     }
index 24b033cc0dc5eb4f6e63104efc065a507d35a114..9a2100c2fb785e6b6b264ecdf6cf76778bcaf562 100644 (file)
@@ -29,6 +29,8 @@ struct ToolBuild {
     is_optional_tool: bool,
     source_type: SourceType,
     extra_features: Vec<String>,
+    /// Nightly-only features that are allowed (comma-separated list).
+    allow_features: &'static str,
 }
 
 impl Step for ToolBuild {
@@ -59,7 +61,7 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
             _ => panic!("unexpected Mode for tool build"),
         }
 
-        let cargo = prepare_tool_cargo(
+        let mut cargo = prepare_tool_cargo(
             builder,
             compiler,
             self.mode,
@@ -69,6 +71,9 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
             self.source_type,
             &self.extra_features,
         );
+        if !self.allow_features.is_empty() {
+            cargo.allow_features(self.allow_features);
+        }
 
         builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target));
         let mut duplicates = Vec::new();
@@ -292,6 +297,7 @@ macro_rules! bootstrap_tool {
         $name:ident, $path:expr, $tool_name:expr
         $(,is_external_tool = $external:expr)*
         $(,is_unstable_tool = $unstable:expr)*
+        $(,allow_features = $allow_features:expr)?
         ;
     )+) => {
         #[derive(Copy, PartialEq, Eq, Clone)]
@@ -355,6 +361,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
                         SourceType::InTree
                     },
                     extra_features: vec![],
+                    allow_features: concat!($($allow_features)*),
                 }).expect("expected to build -- essential tool")
             }
         }
@@ -368,7 +375,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
     Tidy, "src/tools/tidy", "tidy";
     Linkchecker, "src/tools/linkchecker", "linkchecker";
     CargoTest, "src/tools/cargotest", "cargotest";
-    Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true;
+    Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = "test";
     BuildManifest, "src/tools/build-manifest", "build-manifest";
     RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
     RustInstaller, "src/tools/rust-installer", "rust-installer", is_external_tool = true;
@@ -435,6 +442,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
                 is_optional_tool: false,
                 source_type: SourceType::InTree,
                 extra_features: Vec::new(),
+                allow_features: "",
             })
             .expect("expected to build -- essential tool")
     }
@@ -471,6 +479,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
                 is_optional_tool: false,
                 source_type: SourceType::InTree,
                 extra_features: Vec::new(),
+                allow_features: "",
             })
             .expect("expected to build -- essential tool")
     }
@@ -622,6 +631,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
                 is_optional_tool: false,
                 source_type: SourceType::Submodule,
                 extra_features: Vec::new(),
+                allow_features: "",
             })
             .expect("expected to build -- essential tool");
 
@@ -637,6 +647,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
                 is_optional_tool: true,
                 source_type: SourceType::Submodule,
                 extra_features: Vec::new(),
+                allow_features: "",
             });
         };
 
@@ -684,6 +695,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
                 is_optional_tool: false,
                 source_type: SourceType::InTree,
                 extra_features: Vec::new(),
+                allow_features: "",
             })
             .expect("expected to build -- essential tool");
 
@@ -697,6 +709,11 @@ pub struct RustAnalyzer {
     pub target: TargetSelection,
 }
 
+impl RustAnalyzer {
+    pub const ALLOW_FEATURES: &str =
+        "proc_macro_internals,proc_macro_diagnostic,proc_macro_span,proc_macro_span_shrink";
+}
+
 impl Step for RustAnalyzer {
     type Output = Option<PathBuf>;
     const DEFAULT: bool = true;
@@ -731,6 +748,7 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
             extra_features: vec!["rust-analyzer/in-rust-tree".to_owned()],
             is_optional_tool: false,
             source_type: SourceType::InTree,
+            allow_features: RustAnalyzer::ALLOW_FEATURES,
         })
     }
 }
@@ -769,6 +787,7 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
             extra_features: vec!["proc-macro-srv/sysroot-abi".to_owned()],
             is_optional_tool: false,
             source_type: SourceType::InTree,
+            allow_features: RustAnalyzer::ALLOW_FEATURES,
         })?;
 
         // Copy `rust-analyzer-proc-macro-srv` to `<sysroot>/libexec/`
@@ -788,6 +807,7 @@ macro_rules! tool_extended {
        $tool_name:expr,
        stable = $stable:expr
        $(,tool_std = $tool_std:literal)?
+       $(,allow_features = $allow_features:expr)?
        ;)+) => {
         $(
             #[derive(Debug, Clone, Hash, PartialEq, Eq)]
@@ -839,6 +859,7 @@ fn run(mut $sel, $builder: &Builder<'_>) -> Option<PathBuf> {
                     extra_features: $sel.extra_features,
                     is_optional_tool: true,
                     source_type: SourceType::InTree,
+                    allow_features: concat!($($allow_features)*),
                 })
             }
         }
index 67cee0148b24ec4cbb9a3e47f1aa379879106319..5fbce36c39d2844ba3b6be365f97822913f1e2a0 100755 (executable)
@@ -10,7 +10,7 @@ bin="$PWD/clang+llvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04/bin"
 git clone https://github.com/WebAssembly/wasi-libc
 
 cd wasi-libc
-git reset --hard 8b7148f69ae241a2749b3defe4606da8143b72e0
+git reset --hard 4362b1885fd369e042a7c0ecd8df3b6cd47fb4e8
 make -j$(nproc) \
     CC="$bin/clang" \
     NM="$bin/llvm-nm" \
index adf6bb4b37752431eee9885f32ac49bd9ea299a2..d5bc76eeb23daee6779672485caf84fcf53ac877 100644 (file)
@@ -45,6 +45,7 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
            python3 ../x.py test --stage 0 src/tools/compiletest && \
            python3 ../x.py test --stage 0 core alloc std test proc_macro && \
            # Build both public and internal documentation.
+           RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 compiler && \
            RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 library/test && \
            /scripts/validate-toolstate.sh && \
            /scripts/validate-error-codes.sh && \
index 2bd5d42c9956369132228da6409f0e68da56c51a..2cd1b5593d26dc6a03c20f8619187ad4b2485552 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2bd5d42c9956369132228da6409f0e68da56c51a
+Subproject commit 2cd1b5593d26dc6a03c20f8619187ad4b2485552
index 8ca261268068d80c0969260fff15199bad87b587..960d610e7f33889a2577f5f17c26f0d5c82b30df 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8ca261268068d80c0969260fff15199bad87b587
+Subproject commit 960d610e7f33889a2577f5f17c26f0d5c82b30df
index 3ae62681ff236d5528ef7c8c28ba7c6b2ecc6731..2cb0ed9ba56360949f492f9866afe8c293f9f9da 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3ae62681ff236d5528ef7c8c28ba7c6b2ecc6731
+Subproject commit 2cb0ed9ba56360949f492f9866afe8c293f9f9da
index 8888f9428fe9a48f31de6bd2cef9b9bf80791edc..a9fb7d13eadfcc5f457962731f105b97f9a7474a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8888f9428fe9a48f31de6bd2cef9b9bf80791edc
+Subproject commit a9fb7d13eadfcc5f457962731f105b97f9a7474a
index b3e2a6e6c8a3aae5b5d950c63046f23bae07096d..7352353ae91c48b136d2ca7d03822e1448165e1e 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b3e2a6e6c8a3aae5b5d950c63046f23bae07096d
+Subproject commit 7352353ae91c48b136d2ca7d03822e1448165e1e
index 38fd5c96997631d1ce77b3348e88b7754a8ca63b..da91e25595cc760f117b1eb265748e96ce0c4c6b 100644 (file)
@@ -201,6 +201,8 @@ $ RUSTFLAGS="-C instrument-coverage" \
     cargo test --tests
 ```
 
+> **Note**: The default for `LLVM_PROFILE_FILE` is `default_%m_%p.profraw`. Versions prior to 1.65 had a default of `default.profraw`, so if using those earlier versions, it is recommended to explicitly set `LLVM_PROFILE_FILE="default_%m_%p.profraw"` to avoid having multiple tests overwrite the `.profraw` files.
+
 Make note of the test binary file paths, displayed after the word "`Running`" in the test output:
 
 ```text
index bff01d7cb7c14ef5a0544ff0089e30de545133a4..45db3bb9b007b99e1f8f71e21e120fe0863bf482 100644 (file)
@@ -261,7 +261,7 @@ typo mistakes for some common attributes.
 
 ## `invalid_html_tags`
 
-This lint is **allowed by default** and is **nightly-only**. It detects unclosed
+This lint **warns by default**. It detects unclosed
 or invalid HTML tags. For example:
 
 ```rust
index 4d6f1524732f77453e2ce2489cd3eee1b6f848e8..a302750aa1aea341359cb95ad12d718bc501eec2 100644 (file)
@@ -402,15 +402,13 @@ fn make_final_bounds(
                     bound_params: Vec::new(),
                 })
             })
-            .chain(
-                lifetime_to_bounds.into_iter().filter(|&(_, ref bounds)| !bounds.is_empty()).map(
-                    |(lifetime, bounds)| {
-                        let mut bounds_vec = bounds.into_iter().collect();
-                        self.sort_where_bounds(&mut bounds_vec);
-                        WherePredicate::RegionPredicate { lifetime, bounds: bounds_vec }
-                    },
-                ),
-            )
+            .chain(lifetime_to_bounds.into_iter().filter(|(_, bounds)| !bounds.is_empty()).map(
+                |(lifetime, bounds)| {
+                    let mut bounds_vec = bounds.into_iter().collect();
+                    self.sort_where_bounds(&mut bounds_vec);
+                    WherePredicate::RegionPredicate { lifetime, bounds: bounds_vec }
+                },
+            ))
             .collect()
     }
 
index 4ef5747596bb39a7d4900a393c216f84626f3447..e6b2b2349452acff5b992bfbd0d095d7c6c7c509 100644 (file)
@@ -33,7 +33,7 @@ pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
                     trait_def_id,
                     impl_def_id
                 );
-                let trait_ref = cx.tcx.bound_impl_trait_ref(impl_def_id).unwrap();
+                let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap();
                 if !matches!(trait_ref.0.self_ty().kind(), ty::Param(_)) {
                     continue;
                 }
index aad24b4a074927c7d081e9d8fc738bab667d9689..c6939326144ea87aae3bd7c1c08df53081a755b8 100644 (file)
@@ -376,7 +376,7 @@ pub(crate) fn build_impl(
     let _prof_timer = cx.tcx.sess.prof.generic_activity("build_impl");
 
     let tcx = cx.tcx;
-    let associated_trait = tcx.impl_trait_ref(did);
+    let associated_trait = tcx.impl_trait_ref(did).map(ty::EarlyBinder::skip_binder);
 
     // Only inline impl if the implemented trait is
     // reachable in rustdoc generated documentation
index 025a4379f45a31a289177d6daad62200c3aa6302..415e7d5a360d067eeaee6abe84fef949c8b55d42 100644 (file)
@@ -506,7 +506,9 @@ fn clean_generic_param_def<'tcx>(
                     Some(def.def_id),
                 )),
                 default: match has_default {
-                    true => Some(Box::new(cx.tcx.const_param_default(def.def_id).to_string())),
+                    true => Some(Box::new(
+                        cx.tcx.const_param_default(def.def_id).subst_identity().to_string(),
+                    )),
                     false => None,
                 },
             },
index e96a9bab72620970b87e9ab4f3d8acc0839ec664..dbbc25739aa078fa002422c3439b1376c6224283 100644 (file)
@@ -46,7 +46,7 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> ThinVec<WP
 
     // Look for equality predicates on associated types that can be merged into
     // general bound predicates.
-    equalities.retain(|&(ref lhs, ref rhs, ref bound_params)| {
+    equalities.retain(|(lhs, rhs, bound_params)| {
         let Some((ty, trait_did, name)) = lhs.projection() else { return true; };
         let Some((bounds, _)) = tybounds.get_mut(ty) else { return true };
         let bound_params = bound_params
index d027fb6e8763cad8fdc3d1ffd6a237111b5de891..1c78c5b8d280bce1edaf0a8ffcb50a641adcdba7 100644 (file)
@@ -242,7 +242,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         }
 
         // Index this method for searching later on.
-        if let Some(ref s) = item.name.or_else(|| {
+        if let Some(s) = item.name.or_else(|| {
             if item.is_stripped() {
                 None
             } else if let clean::ImportItem(ref i) = *item.kind &&
@@ -296,7 +296,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                             // for where the type was defined. On the other
                             // hand, `paths` always has the right
                             // information if present.
-                            Some(&(ref fqp, _)) => Some(&fqp[..fqp.len() - 1]),
+                            Some((fqp, _)) => Some(&fqp[..fqp.len() - 1]),
                             None => None,
                         };
                         ((did, path), true)
@@ -317,14 +317,15 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                             short_markdown_summary(x.as_str(), &item.link_names(self.cache))
                         });
                         let ty = item.type_();
-                        let name = s.to_string();
-                        if ty != ItemType::StructField || u16::from_str_radix(&name, 10).is_err() {
+                        if ty != ItemType::StructField
+                            || u16::from_str_radix(s.as_str(), 10).is_err()
+                        {
                             // In case this is a field from a tuple struct, we don't add it into
                             // the search index because its name is something like "0", which is
                             // not useful for rustdoc search.
                             self.cache.search_index.push(IndexItem {
                                 ty,
-                                name,
+                                name: s,
                                 path: join_with_double_colon(path),
                                 desc,
                                 parent,
index 5ad24bf2681332b83efb73a192b345bfa4993113..d3dc4065dfc7230d98cc259d7853633a4f2236a4 100644 (file)
@@ -569,7 +569,7 @@ fn generate_macro_def_id_path(
     root_path: Option<&str>,
 ) -> Result<(String, ItemType, Vec<Symbol>), HrefError> {
     let tcx = cx.shared.tcx;
-    let crate_name = tcx.crate_name(def_id.krate).to_string();
+    let crate_name = tcx.crate_name(def_id.krate);
     let cache = cx.cache();
 
     let fqp: Vec<Symbol> = tcx
@@ -584,7 +584,7 @@ fn generate_macro_def_id_path(
             }
         })
         .collect();
-    let mut relative = fqp.iter().map(|elem| elem.to_string());
+    let mut relative = fqp.iter().copied();
     let cstore = CStore::from_tcx(tcx);
     // We need this to prevent a `panic` when this function is used from intra doc links...
     if !cstore.has_crate_data(def_id.krate) {
@@ -602,9 +602,9 @@ fn generate_macro_def_id_path(
     };
 
     let mut path = if is_macro_2 {
-        once(crate_name.clone()).chain(relative).collect()
+        once(crate_name).chain(relative).collect()
     } else {
-        vec![crate_name.clone(), relative.next_back().unwrap()]
+        vec![crate_name, relative.next_back().unwrap()]
     };
     if path.len() < 2 {
         // The minimum we can have is the crate name followed by the macro name. If shorter, then
@@ -614,17 +614,22 @@ fn generate_macro_def_id_path(
     }
 
     if let Some(last) = path.last_mut() {
-        *last = format!("macro.{}.html", last);
+        *last = Symbol::intern(&format!("macro.{}.html", last.as_str()));
     }
 
     let url = match cache.extern_locations[&def_id.krate] {
         ExternalLocation::Remote(ref s) => {
             // `ExternalLocation::Remote` always end with a `/`.
-            format!("{}{}", s, path.join("/"))
+            format!("{}{}", s, path.iter().map(|p| p.as_str()).join("/"))
         }
         ExternalLocation::Local => {
             // `root_path` always end with a `/`.
-            format!("{}{}/{}", root_path.unwrap_or(""), crate_name, path.join("/"))
+            format!(
+                "{}{}/{}",
+                root_path.unwrap_or(""),
+                crate_name,
+                path.iter().map(|p| p.as_str()).join("/")
+            )
         }
         ExternalLocation::Unknown => {
             debug!("crate {} not in cache when linkifying macros", crate_name);
@@ -957,7 +962,7 @@ fn fmt_type<'cx>(
         clean::Tuple(ref typs) => {
             match &typs[..] {
                 &[] => primitive_link(f, PrimitiveType::Unit, "()", cx),
-                &[ref one] => {
+                [one] => {
                     if let clean::Generic(name) = one {
                         primitive_link(f, PrimitiveType::Tuple, &format!("({name},)"), cx)
                     } else {
@@ -1050,7 +1055,7 @@ fn fmt_type<'cx>(
                 _ => String::new(),
             };
             let m = mutability.print_with_space();
-            let amp = if f.alternate() { "&".to_string() } else { "&amp;".to_string() };
+            let amp = if f.alternate() { "&" } else { "&amp;" };
             match **ty {
                 clean::DynTrait(ref bounds, ref trait_lt)
                     if bounds.len() > 1 || trait_lt.is_some() =>
index aeaee524fd4532b820f130d04ccb7912ceb68411..4ff67fe1551dd019f638bc79ce4ee6460047e6bf 100644 (file)
@@ -30,7 +30,7 @@
 use rustc_hir::HirId;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::edition::Edition;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 
 use once_cell::sync::Lazy;
 use std::borrow::Cow;
@@ -198,7 +198,7 @@ fn slugify(c: char) -> Option<char> {
 
 #[derive(Clone, Debug)]
 pub struct Playground {
-    pub crate_name: Option<String>,
+    pub crate_name: Option<Symbol>,
     pub url: String,
 }
 
@@ -290,7 +290,7 @@ fn next(&mut self) -> Option<Self::Item> {
                 .map(|l| map_line(l).for_code())
                 .intersperse("\n".into())
                 .collect::<String>();
-            let krate = krate.as_ref().map(|s| &**s);
+            let krate = krate.as_ref().map(|s| s.as_str());
             let (test, _, _) =
                 doctest::make_test(&test, krate, false, &Default::default(), edition, None);
             let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
index c8899ee62b5f9c7456c96eacc3eaa44600c5a6e8..5cefe9475e77576e63458dc5d3a9dfeb1d469285 100644 (file)
@@ -464,8 +464,7 @@ fn init(
         // If user passed in `--playground-url` arg, we fill in crate name here
         let mut playground = None;
         if let Some(url) = playground_url {
-            playground =
-                Some(markdown::Playground { crate_name: Some(krate.name(tcx).to_string()), url });
+            playground = Some(markdown::Playground { crate_name: Some(krate.name(tcx)), url });
         }
         let mut layout = layout::Layout {
             logo: String::new(),
@@ -491,7 +490,7 @@ fn init(
                 }
                 (sym::html_playground_url, Some(s)) => {
                     playground = Some(markdown::Playground {
-                        crate_name: Some(krate.name(tcx).to_string()),
+                        crate_name: Some(krate.name(tcx)),
                         url: s.to_string(),
                     });
                 }
@@ -639,7 +638,7 @@ fn after_krate(&mut self) -> Result<(), Error> {
                 write!(
                     buf,
                     "<div class=\"main-heading\">\
-                     <h1 class=\"fqn\">Rustdoc settings</h1>\
+                     <h1>Rustdoc settings</h1>\
                      <span class=\"out-of-band\">\
                          <a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
                             Back\
@@ -677,7 +676,7 @@ fn after_krate(&mut self) -> Result<(), Error> {
                 write!(
                     buf,
                     "<div class=\"main-heading\">\
-                     <h1 class=\"fqn\">Rustdoc help</h1>\
+                     <h1>Rustdoc help</h1>\
                      <span class=\"out-of-band\">\
                          <a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
                             Back\
index 8bccf68029aa338c5ea69af74fdcc7a2b50f0b08..f95d8e4303594900aa892473baed229afcceaacb 100644 (file)
@@ -100,7 +100,7 @@ pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
 #[derive(Debug)]
 pub(crate) struct IndexItem {
     pub(crate) ty: ItemType,
-    pub(crate) name: String,
+    pub(crate) name: Symbol,
     pub(crate) path: String,
     pub(crate) desc: String,
     pub(crate) parent: Option<DefId>,
@@ -364,7 +364,7 @@ fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, kind: ItemSection) {
             }
         }
 
-        f.write_str("<h1 class=\"fqn\">List of all items</h1>");
+        f.write_str("<h1>List of all items</h1>");
         // Note: print_entries does not escape the title, because we know the current set of titles
         // doesn't require escaping.
         print_entries(f, &self.structs, ItemSection::Structs);
@@ -394,7 +394,7 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
     let mut ids = IdMap::default();
     format!(
         "<div class=\"main-heading\">\
-            <h1 class=\"fqn\">About scraped examples</h1>\
+            <h1>About scraped examples</h1>\
         </div>\
         <div>{}</div>",
         Markdown {
@@ -513,7 +513,7 @@ fn document_full_inner(
         debug!("Doc block: =====\n{}\n=====", s);
         if is_collapsible {
             w.write_str(
-                "<details class=\"rustdoc-toggle top-doc\" open>\
+                "<details class=\"toggle top-doc\" open>\
                 <summary class=\"hideme\">\
                      <span>Expand description</span>\
                 </summary>",
@@ -1343,7 +1343,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
                     write!(
                         &mut out,
                         "<h3>Notable traits for <code>{}</code></h3>\
-                     <pre class=\"content\"><code>",
+                     <pre><code>",
                         impl_.for_.print(cx)
                     );
                 }
@@ -1514,7 +1514,7 @@ fn doc_impl_item(
         let toggled = !doc_buffer.is_empty();
         if toggled {
             let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
-            write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class);
+            write!(w, "<details class=\"toggle{}\" open><summary>", method_toggle_class);
         }
         match &*item.kind {
             clean::MethodItem(..) | clean::TyMethodItem(_) => {
@@ -1730,7 +1730,7 @@ fn render_default_items(
             close_tags.insert_str(0, "</details>");
             write!(
                 w,
-                "<details class=\"rustdoc-toggle implementors-toggle\"{}>",
+                "<details class=\"toggle implementors-toggle\"{}>",
                 if rendering_params.toggle_open_by_default { " open" } else { "" }
             );
             write!(w, "<summary>")
@@ -2769,8 +2769,8 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
     let mut work = VecDeque::new();
 
     let mut process_path = |did: DefId| {
-        let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone());
-        let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern);
+        let get_extern = || cache.external_paths.get(&did).map(|s| &s.0);
+        let fqp = cache.exact_paths.get(&did).or_else(get_extern);
 
         if let Some(path) = fqp {
             out.push(join_with_double_colon(&path));
@@ -2999,7 +2999,7 @@ fn sort_criterion<'a>(
     if it.peek().is_some() {
         write!(
             w,
-            "<details class=\"rustdoc-toggle more-examples-toggle\">\
+            "<details class=\"toggle more-examples-toggle\">\
                   <summary class=\"hideme\">\
                      <span>More examples</span>\
                   </summary>\
index c16d6477fc37978c736e7c7ddf296be56f98311e..b93db7e28b2d701de6649819290c3d44b2c79457 100644 (file)
@@ -204,7 +204,7 @@ fn should_hide_fields(n_fields: usize) -> bool {
 fn toggle_open(w: &mut Buffer, text: impl fmt::Display) {
     write!(
         w,
-        "<details class=\"rustdoc-toggle type-contents-toggle\">\
+        "<details class=\"toggle type-contents-toggle\">\
             <summary class=\"hideme\">\
                 <span>Show {}</span>\
             </summary>",
@@ -733,7 +733,7 @@ fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::
         let toggled = !content.is_empty();
         if toggled {
             let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
-            write!(w, "<details class=\"rustdoc-toggle{method_toggle_class}\" open><summary>");
+            write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
         }
         write!(w, "<section id=\"{}\" class=\"method has-srclink\">", id);
         render_rightside(w, cx, m, t, RenderMode::Normal);
@@ -1027,8 +1027,8 @@ fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::
         .chain(std::iter::once("implementors"))
         .collect();
     if let Some(did) = it.item_id.as_def_id() &&
-        let get_extern = { || cache.external_paths.get(&did).map(|s| s.0.clone()) } &&
-        let Some(fqp) = cache.exact_paths.get(&did).cloned().or_else(get_extern) {
+        let get_extern = { || cache.external_paths.get(&did).map(|s| &s.0) } &&
+        let Some(fqp) = cache.exact_paths.get(&did).or_else(get_extern) {
         js_src_path.extend(fqp[..fqp.len() - 1].iter().copied());
         js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), fqp.last().unwrap()));
     } else {
@@ -1840,7 +1840,7 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) {
     if item.is_non_exhaustive() {
         write!(
             w,
-            "<details class=\"rustdoc-toggle non-exhaustive\">\
+            "<details class=\"toggle non-exhaustive\">\
                  <summary class=\"hideme\"><span>{}</span></summary>\
                  <div class=\"docblock\">",
             {
index bc74d9cf969741eb56e3ba7cb91c007ab2900ea3..5b0caac099bc3010c7cb9873dc7a8dba990e3d80 100644 (file)
@@ -29,13 +29,13 @@ pub(crate) fn build_index<'tcx>(
     // Attach all orphan items to the type's definition if the type
     // has since been learned.
     for &OrphanImplItem { parent, ref item, ref impl_generics } in &cache.orphan_impl_items {
-        if let Some(&(ref fqp, _)) = cache.paths.get(&parent) {
+        if let Some((fqp, _)) = cache.paths.get(&parent) {
             let desc = item
                 .doc_value()
                 .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(),
+                name: item.name.unwrap(),
                 path: join_with_double_colon(&fqp[..fqp.len() - 1]),
                 desc,
                 parent: Some(parent),
@@ -58,8 +58,8 @@ pub(crate) fn build_index<'tcx>(
     // Sort search index items. This improves the compressibility of the search index.
     cache.search_index.sort_unstable_by(|k1, k2| {
         // `sort_unstable_by_key` produces lifetime errors
-        let k1 = (&k1.path, &k1.name, &k1.ty, &k1.parent);
-        let k2 = (&k2.path, &k2.name, &k2.ty, &k2.parent);
+        let k1 = (&k1.path, k1.name.as_str(), &k1.ty, &k1.parent);
+        let k2 = (&k2.path, k2.name.as_str(), &k2.ty, &k2.parent);
         std::cmp::Ord::cmp(&k1, &k2)
     });
 
@@ -240,7 +240,7 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             )?;
             crate_data.serialize_field(
                 "n",
-                &self.items.iter().map(|item| &item.name).collect::<Vec<_>>(),
+                &self.items.iter().map(|item| item.name.as_str()).collect::<Vec<_>>(),
             )?;
             crate_data.serialize_field(
                 "q",
@@ -299,7 +299,7 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
             )?;
             crate_data.serialize_field(
                 "p",
-                &self.paths.iter().map(|(it, s)| (it, s.to_string())).collect::<Vec<_>>(),
+                &self.paths.iter().map(|(it, s)| (it, s.as_str())).collect::<Vec<_>>(),
             )?;
             if has_aliases {
                 crate_data.serialize_field("a", &self.aliases)?;
@@ -573,7 +573,7 @@ fn get_fn_inputs_and_outputs<'tcx>(
     let decl = &func.decl;
 
     let combined_generics;
-    let (self_, generics) = if let Some(&(ref impl_self, ref impl_generics)) = impl_generics {
+    let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_generics {
         match (impl_generics.is_empty(), func.generics.is_empty()) {
             (true, _) => (Some(impl_self), &func.generics),
             (_, true) => (Some(impl_self), impl_generics),
index 3ea4c4bea8828fbc4fbfdb8738b76b6501d9726a..ca3e9916487aad060546b9ac358d9f3a7fb20515 100644 (file)
@@ -345,7 +345,7 @@ fn add_path(self: &Rc<Self>, path: &Path) {
             };
 
             let content = format!(
-                "<h1 class=\"fqn\">List of all crates</h1><ul class=\"all-items\">{}</ul>",
+                "<h1>List of all crates</h1><ul class=\"all-items\">{}</ul>",
                 krates
                     .iter()
                     .map(|s| {
index b2fa6e82acce263db35d53ea01688ea98d8cedf2..a08b8d89db67d22454f8d0f59a90db37346c838d 100644 (file)
@@ -139,7 +139,7 @@ h1, h2, h3, h4 {
 .docblock > h6:first-child {
        margin-top: 0;
 }
-h1.fqn {
+.main-heading h1 {
        margin: 0;
        padding: 0;
        flex-grow: 1;
@@ -317,7 +317,7 @@ main {
        margin-right: auto;
 }
 
-details:not(.rustdoc-toggle) summary {
+details:not(.toggle) summary {
        margin-bottom: .6em;
 }
 
@@ -1214,11 +1214,11 @@ a.test-arrow:hover {
        content: "\00a0";
 }
 
-.notable .docblock {
+.notable .content {
        margin: 0.25em 0.5em;
 }
 
-.notable .docblock pre, .notable .docblock code {
+.notable .content pre, .notable .content code {
        background: transparent;
        margin: 0;
        padding: 0;
@@ -1226,6 +1226,10 @@ a.test-arrow:hover {
        white-space: pre-wrap;
 }
 
+.notable .content > h3:first-child {
+       margin: 0 0 5px 0;
+}
+
 .search-failed {
        text-align: center;
        margin-top: 20px;
@@ -1401,7 +1405,7 @@ details.dir-entry a {
        Unfortunately we can't yet specify contain: content or contain: strict
        because the [-]/[+] toggles extend past the boundaries of the <details>
        https://developer.mozilla.org/en-US/docs/Web/CSS/contain */
-details.rustdoc-toggle {
+details.toggle {
        contain: layout;
        position: relative;
 }
@@ -1409,26 +1413,26 @@ details.rustdoc-toggle {
 /* The hideme class is used on summary tags that contain a span with
        placeholder text shown only when the toggle is closed. For instance,
        "Expand description" or "Show methods". */
-details.rustdoc-toggle > summary.hideme {
+details.toggle > summary.hideme {
        cursor: pointer;
        font-size: 1rem;
 }
 
-details.rustdoc-toggle > summary {
+details.toggle > summary {
        list-style: none;
        /* focus outline is shown on `::before` instead of this */
        outline: none;
 }
-details.rustdoc-toggle > summary::-webkit-details-marker,
-details.rustdoc-toggle > summary::marker {
+details.toggle > summary::-webkit-details-marker,
+details.toggle > summary::marker {
        display: none;
 }
 
-details.rustdoc-toggle > summary.hideme > span {
+details.toggle > summary.hideme > span {
        margin-left: 9px;
 }
 
-details.rustdoc-toggle > summary::before {
+details.toggle > summary::before {
        background: url("toggle-plus-1092eb4930d581b0.svg") no-repeat top left;
        content: "";
        cursor: pointer;
@@ -1440,14 +1444,14 @@ details.rustdoc-toggle > summary::before {
        filter: var(--toggle-filter);
 }
 
-details.rustdoc-toggle > summary.hideme > span,
+details.toggle > summary.hideme > span,
 .more-examples-toggle summary, .more-examples-toggle .hide-more {
        color: var(--toggles-color);
 }
 
 /* Screen readers see the text version at the end the line.
        Visual readers see the icon at the start of the line, but small and transparent. */
-details.rustdoc-toggle > summary::after {
+details.toggle > summary::after {
        content: "Expand";
        overflow: hidden;
        width: 0;
@@ -1455,17 +1459,17 @@ details.rustdoc-toggle > summary::after {
        position: absolute;
 }
 
-details.rustdoc-toggle > summary.hideme::after {
+details.toggle > summary.hideme::after {
        /* "hideme" toggles already have a description when they're contracted */
        content: "";
 }
 
-details.rustdoc-toggle > summary:focus::before,
-details.rustdoc-toggle > summary:hover::before {
+details.toggle > summary:focus::before,
+details.toggle > summary:hover::before {
        opacity: 1;
 }
 
-details.rustdoc-toggle > summary:focus-visible::before {
+details.toggle > summary:focus-visible::before {
        /* The SVG is black, and gets turned white using a filter in the dark themes.
           Do the same with the outline.
           The dotted 1px style is copied from Firefox's focus ring style.
@@ -1478,17 +1482,17 @@ details.non-exhaustive {
        margin-bottom: 8px;
 }
 
-details.rustdoc-toggle > summary.hideme::before {
+details.toggle > summary.hideme::before {
        position: relative;
 }
 
-details.rustdoc-toggle > summary:not(.hideme)::before {
+details.toggle > summary:not(.hideme)::before {
        position: absolute;
        left: -24px;
        top: 4px;
 }
 
-.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before {
+.impl-items > details.toggle > summary:not(.hideme)::before {
        position: absolute;
        left: -24px;
 }
@@ -1498,19 +1502,19 @@ details.rustdoc-toggle > summary:not(.hideme)::before {
        affect the layout of the items to its right. To do that, we use
        absolute positioning. Note that we also set position: relative
        on the parent <details> to make this work properly. */
-details.rustdoc-toggle[open] > summary.hideme {
+details.toggle[open] > summary.hideme {
        position: absolute;
 }
 
-details.rustdoc-toggle[open] > summary.hideme > span {
+details.toggle[open] > summary.hideme > span {
        display: none;
 }
 
-details.rustdoc-toggle[open] > summary::before {
+details.toggle[open] > summary::before {
        background: url("toggle-minus-31bbd6e4c77f5c96.svg") no-repeat top left;
 }
 
-details.rustdoc-toggle[open] > summary::after {
+details.toggle[open] > summary::after {
        content: "Collapse";
 }
 
@@ -1660,8 +1664,8 @@ in storage.js
                display: block;
        }
 
-       #main-content > details.rustdoc-toggle > summary::before,
-       #main-content > div > details.rustdoc-toggle > summary::before {
+       #main-content > details.toggle > summary::before,
+       #main-content > div > details.toggle > summary::before {
                left: -11px;
        }
 
@@ -1715,12 +1719,12 @@ in storage.js
        }
 
        /* Position of the "[-]" element. */
-       details.rustdoc-toggle:not(.top-doc) > summary {
+       details.toggle:not(.top-doc) > summary {
                margin-left: 10px;
        }
-       .impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
-       #main-content > details.rustdoc-toggle:not(.top-doc) > summary::before,
-       #main-content > div > details.rustdoc-toggle > summary::before {
+       .impl-items > details.toggle > summary:not(.hideme)::before,
+       #main-content > details.toggle:not(.top-doc) > summary::before,
+       #main-content > div > details.toggle > summary::before {
                left: -11px;
        }
 
@@ -1753,8 +1757,8 @@ in storage.js
 
 @media print {
        nav.sidebar, nav.sub, .out-of-band, a.srclink, #copy-path,
-       details.rustdoc-toggle[open] > summary::before, details.rustdoc-toggle > summary::before,
-       details.rustdoc-toggle.top-doc > summary {
+       details.toggle[open] > summary::before, details.toggle > summary::before,
+       details.toggle.top-doc > summary {
                display: none;
        }
 
@@ -1796,24 +1800,24 @@ in storage.js
 .impl,
 #implementors-list > .docblock,
 .impl-items > section,
-.impl-items > .rustdoc-toggle > summary,
+.impl-items > .toggle > summary,
 .methods > section,
-.methods > .rustdoc-toggle > summary
+.methods > .toggle > summary
 {
        margin-bottom: 0.75em;
 }
 
 .variants > .docblock,
 .implementors-toggle > .docblock,
-.impl-items > .rustdoc-toggle[open]:not(:last-child),
-.methods > .rustdoc-toggle[open]:not(:last-child),
+.impl-items > .toggle[open]:not(:last-child),
+.methods > .toggle[open]:not(:last-child),
 .implementors-toggle[open]:not(:last-child) {
        margin-bottom: 2em;
 }
 
-#trait-implementations-list .impl-items > .rustdoc-toggle:not(:last-child),
-#synthetic-implementations-list .impl-items > .rustdoc-toggle:not(:last-child),
-#blanket-implementations-list .impl-items > .rustdoc-toggle:not(:last-child) {
+#trait-implementations-list .impl-items > .toggle:not(:last-child),
+#synthetic-implementations-list .impl-items > .toggle:not(:last-child),
+#blanket-implementations-list .impl-items > .toggle:not(:last-child) {
        margin-bottom: 1em;
 }
 
index 875a260c8115ebdb849b8f26593ed7d4981cb4ba..91419093147d728bbdda9478eecda9305db4621e 100644 (file)
@@ -9,7 +9,7 @@
 }
 
 .setting-line .radio-line input,
-.setting-line .toggle input {
+.setting-line .settings-toggle input {
        margin-right: 0.3em;
        height: 1.2rem;
        width: 1.2rem;
 .setting-line .radio-line input {
        border-radius: 50%;
 }
-.setting-line .toggle input:checked {
+.setting-line .settings-toggle input:checked {
        content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">\
                <path d="M7,25L17,32L33,12" fill="none" stroke="black" stroke-width="5"/>\
                <path d="M7,23L17,30L33,10" fill="none" stroke="white" stroke-width="5"/></svg>');
 }
 
 .setting-line .radio-line input + span,
-.setting-line .toggle span {
+.setting-line .settings-toggle span {
        padding-bottom: 1px;
 }
 
@@ -50,7 +50,7 @@
        margin-left: 0.5em;
 }
 
-.toggle {
+.settings-toggle {
        position: relative;
        width: 100%;
        margin-right: 20px;
        box-shadow: inset 0 0 0 3px var(--main-background-color);
        background-color: var(--settings-input-color);
 }
-.setting-line .toggle input:checked {
+.setting-line .settings-toggle input:checked {
        background-color: var(--settings-input-color);
 }
 .setting-line .radio-line input:focus,
-.setting-line .toggle input:focus {
+.setting-line .settings-toggle input:focus {
        box-shadow: 0 0 1px 1px var(--settings-input-color);
 }
 /* In here we combine both `:focus` and `:checked` properties. */
@@ -80,6 +80,6 @@
                0 0 2px 2px var(--settings-input-color);
 }
 .setting-line .radio-line input:hover,
-.setting-line .toggle input:hover {
+.setting-line .settings-toggle input:hover {
        border-color: var(--settings-input-color) !important;
 }
index 51aee8e7c899212193006655b56e51c394fb3c1d..f52229d80953630ec0696743d5534b0e9faf3b59 100644 (file)
@@ -526,7 +526,7 @@ function loadCss(cssUrl) {
         }
 
         let currentNbImpls = implementors.getElementsByClassName("impl").length;
-        const traitName = document.querySelector("h1.fqn > .trait").textContent;
+        const traitName = document.querySelector(".main-heading h1 > .trait").textContent;
         const baseIdName = "impl-" + traitName + "-";
         const libs = Object.getOwnPropertyNames(imp);
         // We don't want to include impls from this JS file, when the HTML already has them.
@@ -620,7 +620,7 @@ function loadCss(cssUrl) {
     function expandAllDocs() {
         const innerToggle = document.getElementById(toggleAllDocsId);
         removeClass(innerToggle, "will-expand");
-        onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+        onEachLazy(document.getElementsByClassName("toggle"), e => {
             if (!hasClass(e, "type-contents-toggle") && !hasClass(e, "more-examples-toggle")) {
                 e.open = true;
             }
@@ -632,7 +632,7 @@ function loadCss(cssUrl) {
     function collapseAllDocs() {
         const innerToggle = document.getElementById(toggleAllDocsId);
         addClass(innerToggle, "will-expand");
-        onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+        onEachLazy(document.getElementsByClassName("toggle"), e => {
             if (e.parentNode.id !== "implementations-list" ||
                 (!hasClass(e, "implementors-toggle") &&
                  !hasClass(e, "type-contents-toggle"))
@@ -680,7 +680,7 @@ function loadCss(cssUrl) {
             setImplementorsTogglesOpen("blanket-implementations-list", false);
         }
 
-        onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
+        onEachLazy(document.getElementsByClassName("toggle"), e => {
             if (!hideLargeItemContents && hasClass(e, "type-contents-toggle")) {
                 e.open = true;
             }
@@ -823,7 +823,7 @@ function loadCss(cssUrl) {
         });
     });
 
-    onEachLazy(document.querySelectorAll(".rustdoc-toggle > summary:not(.hideme)"), el => {
+    onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"), el => {
         el.addEventListener("click", e => {
             if (e.target.tagName !== "SUMMARY" && e.target.tagName !== "A") {
                 e.preventDefault();
@@ -847,7 +847,7 @@ function loadCss(cssUrl) {
         window.hideAllModals(false);
         const ty = e.getAttribute("data-ty");
         const wrapper = document.createElement("div");
-        wrapper.innerHTML = "<div class=\"docblock\">" + window.NOTABLE_TRAITS[ty] + "</div>";
+        wrapper.innerHTML = "<div class=\"content\">" + window.NOTABLE_TRAITS[ty] + "</div>";
         wrapper.className = "notable popover";
         const focusCatcher = document.createElement("div");
         focusCatcher.setAttribute("tabindex", "0");
index 589bfc79360ce17f1bdf2d8bcb9c2026b2339e28..9ed8f63610ff6b336d940e934043a6a7f53dd540 100644 (file)
                 });
                 output += "</div></div>";
             } else {
-                // This is a toggle.
+                // This is a checkbox toggle.
                 const checked = setting["default"] === true ? " checked" : "";
                 output += `\
-<label class="toggle">\
+<label class="settings-toggle">\
     <input type="checkbox" id="${js_data_name}"${checked}>\
     <span class="label">${setting_name}</span>\
 </label>`;
index 611d124d4b91bedc99a68472752817b222517bf9..ee2880bf6d195e23a91bedf640a667c29052cbc3 100644 (file)
@@ -1,5 +1,5 @@
 <div class="main-heading"> {#- -#}
-    <h1 class="fqn"> {#- -#}
+    <h1> {#- -#}
         {{-typ-}}
         {#- The breadcrumbs of the item path, like std::string -#}
         {%- for component in path_components -%}
index ed77de200a9b7ac21bba20ada87ed9e654e054b0..86454e1f2eb7316d239d4544c3adeec49e917e89 100644 (file)
@@ -772,7 +772,6 @@ fn main_args(at_args: &[String]) -> MainResult {
     let crate_version = options.crate_version.clone();
 
     let output_format = options.output_format;
-    let externs = options.externs.clone();
     let scrape_examples_options = options.scrape_examples_options.clone();
     let bin_crate = options.bin_crate;
 
@@ -805,9 +804,7 @@ fn main_args(at_args: &[String]) -> MainResult {
                 let resolver_caches = resolver.borrow_mut().access(|resolver| {
                     collect_intra_doc_links::early_resolve_intra_doc_links(
                         resolver,
-                        sess,
                         krate,
-                        externs,
                         render_options.document_private,
                     )
                 });
index 4f0eb8b8076e5fae8214dfb8a71ace1658385d36..075951312a6393d738fab17772a2778f9b2085b9 100644 (file)
@@ -786,7 +786,7 @@ fn trait_impls_for<'a>(
         tcx.find_map_relevant_impl(trait_, ty, |impl_| {
             let trait_ref = tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
             // Check if these are the same type.
-            let impl_type = trait_ref.self_ty();
+            let impl_type = trait_ref.skip_binder().self_ty();
             trace!(
                 "comparing type {} with kind {:?} against type {:?}",
                 impl_type,
index 1b373cfe5bb793d590e239717525608d594a9bec..42677bd8497483cce642162000a7ffc4848b07e8 100644 (file)
@@ -12,8 +12,6 @@
 use rustc_hir::TraitCandidate;
 use rustc_middle::ty::{DefIdTree, Visibility};
 use rustc_resolve::{ParentScope, Resolver};
-use rustc_session::config::Externs;
-use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::{Symbol, SyntaxContext};
 
 
 pub(crate) fn early_resolve_intra_doc_links(
     resolver: &mut Resolver<'_>,
-    sess: &Session,
     krate: &ast::Crate,
-    externs: Externs,
     document_private_items: bool,
 ) -> ResolverCaches {
     let parent_scope =
         ParentScope::module(resolver.expect_module(CRATE_DEF_ID.to_def_id()), resolver);
     let mut link_resolver = EarlyDocLinkResolver {
         resolver,
-        sess,
         parent_scope,
         visited_mods: Default::default(),
         markdown_links: Default::default(),
@@ -52,7 +47,9 @@ pub(crate) fn early_resolve_intra_doc_links(
     // the known necessary crates. Load them all unconditionally until we find a way to fix this.
     // DO NOT REMOVE THIS without first testing on the reproducer in
     // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
-    for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) {
+    for (extern_name, _) in
+        link_resolver.resolver.sess().opts.externs.iter().filter(|(_, entry)| entry.add_prelude)
+    {
         link_resolver.resolver.resolve_rustdoc_path(extern_name, TypeNS, parent_scope);
     }
 
@@ -73,7 +70,6 @@ fn doc_attrs<'a>(attrs: impl Iterator<Item = &'a ast::Attribute>) -> Attributes
 
 struct EarlyDocLinkResolver<'r, 'ra> {
     resolver: &'r mut Resolver<'ra>,
-    sess: &'r Session,
     parent_scope: ParentScope<'ra>,
     visited_mods: DefIdSet,
     markdown_links: FxHashMap<String, Vec<PreprocessedMarkdownLink>>,
@@ -166,7 +162,7 @@ fn process_extern_impls(&mut self) {
     fn resolve_doc_links_extern_impl(&mut self, def_id: DefId, is_inherent: bool) {
         self.resolve_doc_links_extern_outer_fixme(def_id, def_id);
         let assoc_item_def_ids = Vec::from_iter(
-            self.resolver.cstore().associated_item_def_ids_untracked(def_id, self.sess),
+            self.resolver.cstore().associated_item_def_ids_untracked(def_id, self.resolver.sess()),
         );
         for assoc_def_id in assoc_item_def_ids {
             if !is_inherent || self.resolver.cstore().visibility_untracked(assoc_def_id).is_public()
@@ -191,7 +187,9 @@ fn resolve_doc_links_extern_outer(&mut self, def_id: DefId, scope_id: DefId) {
         if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
             return;
         }
-        let attrs = Vec::from_iter(self.resolver.cstore().item_attrs_untracked(def_id, self.sess));
+        let attrs = Vec::from_iter(
+            self.resolver.cstore().item_attrs_untracked(def_id, self.resolver.sess()),
+        );
         let parent_scope = ParentScope::module(
             self.resolver.get_nearest_non_block_module(
                 self.resolver.opt_parent(scope_id).unwrap_or(scope_id),
@@ -205,7 +203,9 @@ fn resolve_doc_links_extern_inner(&mut self, def_id: DefId) {
         if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
             return;
         }
-        let attrs = Vec::from_iter(self.resolver.cstore().item_attrs_untracked(def_id, self.sess));
+        let attrs = Vec::from_iter(
+            self.resolver.cstore().item_attrs_untracked(def_id, self.resolver.sess()),
+        );
         let parent_scope = ParentScope::module(self.resolver.expect_module(def_id), self.resolver);
         self.resolve_doc_links(doc_attrs(attrs.iter()), parent_scope);
     }
@@ -321,7 +321,7 @@ fn process_module_children_or_reexports(&mut self, module_id: DefId) {
                         let field_def_ids = Vec::from_iter(
                             self.resolver
                                 .cstore()
-                                .associated_item_def_ids_untracked(def_id, self.sess),
+                                .associated_item_def_ids_untracked(def_id, self.resolver.sess()),
                         );
                         for field_def_id in field_def_ids {
                             self.resolve_doc_links_extern_outer(field_def_id, scope_id);
index f5501b3d5238b82c1ef80326f4a85061e0ddd0da..048ed2646233c45284f6a029b4c37dcf548a9c5c 100644 (file)
@@ -97,17 +97,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             }
 
             // handled in the `strip-priv-imports` pass
-            clean::ExternCrateItem { .. } => {}
-            clean::ImportItem(ref imp) => {
-                // Because json doesn't inline imports from private modules, we need to mark
-                // the imported item as retained so it's impls won't be stripped.
-                //
-                // FIXME: Is it necessary to check for json output here: See
-                // https://github.com/rust-lang/rust/pull/100325#discussion_r941495215
-                if let Some(did) = imp.source.did && self.is_json_output {
-                    self.retained.insert(did.into());
-                }
-            }
+            clean::ExternCrateItem { .. } | clean::ImportItem(_) => {}
 
             clean::ImplItem(..) => {}
 
index d992ab4e9034930e7809749f04077045af8f4d79..1cd6d3803dfb0b342272862a8590f5dfc9f72573 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d992ab4e9034930e7809749f04077045af8f4d79
+Subproject commit 1cd6d3803dfb0b342272862a8590f5dfc9f72573
index f4b15e0916dbf47bca1aa427e5d46f35d9bfa45a..248d7388410673c3da902461a252936750345e67 100644 (file)
@@ -251,7 +251,7 @@ fn check_hash_peq<'tcx>(
 
                 // Only care about `impl PartialEq<Foo> for Foo`
                 // For `impl PartialEq<B> for A, input_types is [A, B]
-                if trait_ref.substs.type_at(1) == ty {
+                if trait_ref.subst_identity().substs.type_at(1) == ty {
                     span_lint_and_then(
                         cx,
                         DERIVED_HASH_WITH_MANUAL_EQ,
@@ -299,7 +299,7 @@ fn check_ord_partial_ord<'tcx>(
 
                 // Only care about `impl PartialOrd<Foo> for Foo`
                 // For `impl PartialOrd<B> for A, input_types is [A, B]
-                if trait_ref.substs.type_at(1) == ty {
+                if trait_ref.subst_identity().substs.type_at(1) == ty {
                     let mess = if partial_ord_is_automatically_derived {
                         "you are implementing `Ord` explicitly but have derived `PartialOrd`"
                     } else {
index 9a1058470e18e6155af9a4c5a1ee711dde9553da..2ef547526d4f7961027d20dbb77f7e846435b992 100644 (file)
@@ -56,7 +56,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
         if_chain! {
             if let hir::ItemKind::Impl(impl_) = &item.kind;
             if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
-            if cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.def_id);
+            if cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.skip_binder().def_id);
             then {
                 lint_impl_body(cx, item.span, impl_.items);
             }
index a92f7548ff254d16a2f51b255675650d139e8734..bd66ace4500a8d305f55ec1e430e1785e09d3348 100644 (file)
@@ -76,7 +76,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             && let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
             // `impl Into<target_ty> for self_ty`
             && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
-            && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+            && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(ty::EarlyBinder::subst_identity)
             && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
             && !matches!(middle_trait_ref.substs.type_at(1).kind(), ty::Alias(ty::Opaque, _))
         {
index 758ce47cf114b8dc3aba594b3ba2ad3d24710a72..5a459548153aab242c7a0d4b6aa800e50d522fc2 100644 (file)
@@ -155,7 +155,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
         let container_id = assoc_item.container_id(cx.tcx);
         let trait_def_id = match assoc_item.container {
             TraitContainer => Some(container_id),
-            ImplContainer => cx.tcx.impl_trait_ref(container_id).map(|t| t.def_id),
+            ImplContainer => cx.tcx.impl_trait_ref(container_id).map(|t| t.skip_binder().def_id),
         };
 
         if let Some(trait_def_id) = trait_def_id {
index 714c0ff227bf829d01f535ea5fc89a944d362b91..839c3a3815c29ef5a55b0bcf877b680916a41923 100644 (file)
@@ -90,7 +90,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             if send_trait == trait_id;
             if hir_impl.polarity == ImplPolarity::Positive;
             if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
-            if let self_ty = ty_trait_ref.self_ty();
+            if let self_ty = ty_trait_ref.subst_identity().self_ty();
             if let ty::Adt(adt_def, impl_trait_substs) = self_ty.kind();
             then {
                 let mut non_send_fields = Vec::new();
index 7722a476d7b4e5182abeea83af939b5653c7bc32..7b1d974f2f877e51f0c1d4fe29a89d57d383fb87 100644 (file)
@@ -244,7 +244,7 @@ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) {
             })) => {
                 #[allow(trivial_casts)]
                 if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into())
-                    && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+                    && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(|t| t.subst_identity())
                     && let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id
                 {
                     (
index 4c755d812a0e0fe93c319fc6fa534be220d71022..6ae9d9d63538006d7d4e759b17217a07d98424b5 100644 (file)
@@ -137,7 +137,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_
             then {
                 // `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
                 // `Self`.
-                let self_ty = impl_trait_ref.self_ty();
+                let self_ty = impl_trait_ref.subst_identity().self_ty();
 
                 // `trait_method_sig` is the signature of the function, how it is declared in the
                 // trait, not in the impl of the trait.
index f1838cf64f7feefbf5d5b0a01f7e8c5e3fe7fd9a..d6d19a3fe8159ccc66ceb1ad7cf44e9ba9da742b 100644 (file)
@@ -22,7 +22,8 @@ fn main() {
     }
 
     // test `stat`
-    assert_eq!(fs::metadata("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied);
+    let err = fs::metadata("foo.txt").unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::PermissionDenied);
     // check that it is the right kind of `PermissionDenied`
-    assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EACCES));
+    assert_eq!(err.raw_os_error(), Some(libc::EACCES));
 }
index 33c051804081cfaf90ec6c66a8d7621da869fe25..b296aa2f4e6d619f1493d42df410f8daff7ab733 100644 (file)
@@ -5,10 +5,10 @@ license = "MIT OR Apache-2.0"
 edition = "2021"
 
 [dependencies]
-clap = "3.1.1"
+clap = "4.0.32"
 env_logger = "0.7.1"
 
 [dependencies.mdbook]
-version = "0.4.21"
+version = "0.4.25"
 default-features = false
 features = ["search"]
index 3c7dc0183d7761e62b8a3bb839edcf7ec7299108..1368ec653de115fc8a474ea8a04b42f88b922c72 100644 (file)
@@ -9,18 +9,21 @@
 use mdbook::MDBook;
 
 fn main() {
-    let crate_version = format!("v{}", crate_version!());
+    let crate_version = concat!("v", crate_version!());
     env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init();
     let d_arg = arg!(-d --"dest-dir" <DEST_DIR>
 "The output directory for your book\n(Defaults to ./book when omitted)")
-    .required(false);
-    let dir_arg = arg!([dir]
-"A directory for your book\n(Defaults to Current Directory when omitted)");
+    .required(false)
+    .value_parser(clap::value_parser!(PathBuf));
+
+    let dir_arg = arg!([dir] "Root directory for the book\n\
+                              (Defaults to the current directory when omitted)")
+    .value_parser(clap::value_parser!(PathBuf));
 
     let matches = Command::new("rustbook")
         .about("Build a book with mdBook")
         .author("Steve Klabnik <steve@steveklabnik.com>")
-        .version(&*crate_version)
+        .version(crate_version)
         .subcommand_required(true)
         .arg_required_else_help(true)
         .subcommand(
@@ -60,8 +63,8 @@ pub fn build(args: &ArgMatches) -> Result3<()> {
     // Set this to allow us to catch bugs in advance.
     book.config.build.create_missing = false;
 
-    if let Some(dest_dir) = args.value_of("dest-dir") {
-        book.config.build.build_dir = PathBuf::from(dest_dir);
+    if let Some(dest_dir) = args.get_one::<PathBuf>("dest-dir") {
+        book.config.build.build_dir = dest_dir.into();
     }
 
     book.build()?;
@@ -76,10 +79,9 @@ fn test(args: &ArgMatches) -> Result3<()> {
 }
 
 fn get_book_dir(args: &ArgMatches) -> PathBuf {
-    if let Some(dir) = args.value_of("dir") {
+    if let Some(p) = args.get_one::<PathBuf>("dir") {
         // Check if path is relative from current dir, or absolute...
-        let p = Path::new(dir);
-        if p.is_relative() { env::current_dir().unwrap().join(dir) } else { p.to_path_buf() }
+        if p.is_relative() { env::current_dir().unwrap().join(p) } else { p.to_path_buf() }
     } else {
         env::current_dir().unwrap()
     }
index fff83a1d097b3f6364c180781b8bfdb6ec886dc6..19812fc6f55b630f9e557d2216e0a45f548a37c6 100644 (file)
@@ -6,6 +6,7 @@ autobins = false
 
 [dependencies]
 cargo_metadata = "0.14"
+cargo-platform = "0.1.2"
 regex = "1"
 miropt-test-tools = { path = "../miropt-test-tools" }
 lazy_static = "1"
index 29501d2d3b6be975e94faa0b46e06beacc1426f4..bc2edf634de2b617b5f0c46da2c20051f379784c 100644 (file)
@@ -1,7 +1,7 @@
 //! Checks the licenses of third-party dependencies.
 
-use cargo_metadata::{Metadata, Package, PackageId, Resolve};
-use std::collections::{BTreeSet, HashSet};
+use cargo_metadata::{DepKindInfo, Metadata, Package, PackageId};
+use std::collections::HashSet;
 use std::path::Path;
 
 /// These are licenses that are allowed for all crates, including the runtime,
     "autocfg",
     "bitflags",
     "block-buffer",
-    "bumpalo", // Included in Cargo's dep graph but only activated on wasm32-*-unknown.
     "cc",
     "cfg-if",
     "chalk-derive",
     "chalk-engine",
     "chalk-ir",
     "chalk-solve",
-    "chrono",
     "convert_case", // dependency of derive_more
     "compiler_builtins",
     "cpufeatures",
     "dlmalloc",
     "either",
     "ena",
-    "env_logger",
     "expect-test",
     "fallible-iterator", // dependency of `thorin`
     "fastrand",
-    "filetime",
     "fixedbitset",
     "flate2",
     "fluent-bundle",
     "gsgdt",
     "hashbrown",
     "hermit-abi",
-    "humantime",
     "icu_list",
     "icu_locid",
     "icu_provider",
     "icu_provider_adapters",
     "icu_provider_macros",
-    "if_chain",
     "indexmap",
     "instant",
     "intl-memoizer",
     "itertools",
     "itoa",
     "jobserver",
-    "js-sys", // Included in Cargo's dep graph but only activated on wasm32-*-unknown.
     "lazy_static",
     "libc",
     "libloading",
     "memmap2",
     "memoffset",
     "miniz_oxide",
-    "num-integer",
-    "num-traits",
     "num_cpus",
     "object",
     "odht",
     "proc-macro2",
     "psm",
     "punycode",
-    "quick-error",
     "quote",
     "rand",
     "rand_chacha",
     "serde",
     "serde_derive",
     "serde_json",
-    "sha-1",
+    "sha1",
     "sha2",
     "sharded-slab",
     "smallvec",
     "thiserror-impl",
     "thorin-dwp",
     "thread_local",
-    "time",
     "tinystr",
     "tinyvec",
     "tinyvec_macros",
     "valuable",
     "version_check",
     "wasi",
-    // vvv Included in Cargo's dep graph but only activated on wasm32-*-unknown.
-    "wasm-bindgen",
-    "wasm-bindgen-backend",
-    "wasm-bindgen-macro",
-    "wasm-bindgen-macro-support",
-    "wasm-bindgen-shared",
-    // ^^^ Included in Cargo's dep graph but only activated on wasm32-*-unknown.
     "winapi",
     "winapi-i686-pc-windows-gnu",
     "winapi-util",
@@ -485,73 +467,55 @@ fn check_permitted_dependencies(
     restricted_dependency_crates: &[&'static str],
     bad: &mut bool,
 ) {
+    let mut deps = HashSet::new();
+    for to_check in restricted_dependency_crates {
+        let to_check = pkg_from_name(metadata, to_check);
+        use cargo_platform::Cfg;
+        use std::str::FromStr;
+        // We don't expect the compiler to ever run on wasm32, so strip
+        // out those dependencies to avoid polluting the permitted list.
+        deps_of_filtered(metadata, &to_check.id, &mut deps, &|dep_kinds| {
+            dep_kinds.iter().any(|dep_kind| {
+                dep_kind
+                    .target
+                    .as_ref()
+                    .map(|target| {
+                        !target.matches(
+                            "wasm32-unknown-unknown",
+                            &[
+                                Cfg::from_str("target_arch=\"wasm32\"").unwrap(),
+                                Cfg::from_str("target_os=\"unknown\"").unwrap(),
+                            ],
+                        )
+                    })
+                    .unwrap_or(true)
+            })
+        });
+    }
+
     // Check that the PERMITTED_DEPENDENCIES does not have unused entries.
-    for name in permitted_dependencies {
-        if !metadata.packages.iter().any(|p| p.name == *name) {
+    for permitted in permitted_dependencies {
+        if !deps.iter().any(|dep_id| &pkg_from_id(metadata, dep_id).name == permitted) {
             tidy_error!(
                 bad,
-                "could not find allowed package `{}`\n\
+                "could not find allowed package `{permitted}`\n\
                 Remove from PERMITTED_DEPENDENCIES list if it is no longer used.",
-                name
             );
         }
     }
-    // Get the list in a convenient form.
-    let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect();
-
-    // Check dependencies.
-    let mut visited = BTreeSet::new();
-    let mut unapproved = BTreeSet::new();
-    for &krate in restricted_dependency_crates.iter() {
-        let pkg = pkg_from_name(metadata, krate);
-        let mut bad =
-            check_crate_dependencies(&permitted_dependencies, metadata, &mut visited, pkg);
-        unapproved.append(&mut bad);
-    }
-
-    if !unapproved.is_empty() {
-        tidy_error!(bad, "Dependencies for {} not explicitly permitted:", descr);
-        for dep in unapproved {
-            println!("* {dep}");
-        }
-    }
-}
-
-/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
-/// the list of permitted dependencies. Returns a list of disallowed dependencies.
-fn check_crate_dependencies<'a>(
-    permitted_dependencies: &'a HashSet<&'static str>,
-    metadata: &'a Metadata,
-    visited: &mut BTreeSet<&'a PackageId>,
-    krate: &'a Package,
-) -> BTreeSet<&'a PackageId> {
-    // This will contain bad deps.
-    let mut unapproved = BTreeSet::new();
-
-    // Check if we have already visited this crate.
-    if visited.contains(&krate.id) {
-        return unapproved;
-    }
 
-    visited.insert(&krate.id);
+    // Get in a convenient form.
+    let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect();
 
-    // If this path is in-tree, we don't require it to be explicitly permitted.
-    if krate.source.is_some() {
-        // If this dependency is not on `PERMITTED_DEPENDENCIES`, add to bad set.
-        if !permitted_dependencies.contains(krate.name.as_str()) {
-            unapproved.insert(&krate.id);
+    for dep in deps {
+        let dep = pkg_from_id(metadata, dep);
+        // If this path is in-tree, we don't require it to be explicitly permitted.
+        if dep.source.is_some() {
+            if !permitted_dependencies.contains(dep.name.as_str()) {
+                tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id);
+            }
         }
     }
-
-    // Do a DFS in the crate graph.
-    let to_check = deps_of(metadata, &krate.id);
-
-    for dep in to_check {
-        let mut bad = check_crate_dependencies(permitted_dependencies, metadata, visited, dep);
-        unapproved.append(&mut bad);
-    }
-
-    unapproved
 }
 
 /// Prevents multiple versions of some expensive crates.
@@ -588,24 +552,6 @@ fn check_crate_duplicate(
     }
 }
 
-/// Returns a list of dependencies for the given package.
-fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> {
-    let resolve = metadata.resolve.as_ref().unwrap();
-    let node = resolve
-        .nodes
-        .iter()
-        .find(|n| &n.id == pkg_id)
-        .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
-    node.deps
-        .iter()
-        .map(|dep| {
-            metadata.packages.iter().find(|pkg| pkg.id == dep.pkg).unwrap_or_else(|| {
-                panic!("could not find dep `{}` for pkg `{}` in resolve", dep.pkg, pkg_id)
-            })
-        })
-        .collect()
-}
-
 /// Finds a package with the given name.
 fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package {
     let mut i = metadata.packages.iter().filter(|p| p.name == name);
@@ -615,41 +561,57 @@ fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package
     result
 }
 
+fn pkg_from_id<'a>(metadata: &'a Metadata, id: &PackageId) -> &'a Package {
+    metadata.packages.iter().find(|p| &p.id == id).unwrap()
+}
+
 /// Finds all the packages that are in the rust runtime.
 fn compute_runtime_crates<'a>(metadata: &'a Metadata) -> HashSet<&'a PackageId> {
-    let resolve = metadata.resolve.as_ref().unwrap();
     let mut result = HashSet::new();
     for name in RUNTIME_CRATES {
         let id = &pkg_from_name(metadata, name).id;
-        normal_deps_of_r(resolve, id, &mut result);
+        deps_of_filtered(metadata, id, &mut result, &|_| true);
     }
     result
 }
 
-/// Recursively find all normal dependencies.
-fn normal_deps_of_r<'a>(
-    resolve: &'a Resolve,
+/// Recursively find all dependencies.
+fn deps_of_filtered<'a>(
+    metadata: &'a Metadata,
     pkg_id: &'a PackageId,
     result: &mut HashSet<&'a PackageId>,
+    filter: &dyn Fn(&[DepKindInfo]) -> bool,
 ) {
     if !result.insert(pkg_id) {
         return;
     }
-    let node = resolve
+    let node = metadata
+        .resolve
+        .as_ref()
+        .unwrap()
         .nodes
         .iter()
         .find(|n| &n.id == pkg_id)
         .unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
     for dep in &node.deps {
-        normal_deps_of_r(resolve, &dep.pkg, result);
+        if !filter(&dep.dep_kinds) {
+            continue;
+        }
+        deps_of_filtered(metadata, &dep.pkg, result, filter);
     }
 }
 
+fn direct_deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> {
+    let resolve = metadata.resolve.as_ref().unwrap();
+    let node = resolve.nodes.iter().find(|n| &n.id == pkg_id).unwrap();
+    node.deps.iter().map(|dep| pkg_from_id(metadata, &dep.pkg)).collect()
+}
+
 fn check_rustfix(metadata: &Metadata, bad: &mut bool) {
     let cargo = pkg_from_name(metadata, "cargo");
     let compiletest = pkg_from_name(metadata, "compiletest");
-    let cargo_deps = deps_of(metadata, &cargo.id);
-    let compiletest_deps = deps_of(metadata, &compiletest.id);
+    let cargo_deps = direct_deps_of(metadata, &cargo.id);
+    let compiletest_deps = direct_deps_of(metadata, &compiletest.id);
     let cargo_rustfix = cargo_deps.iter().find(|p| p.name == "rustfix").unwrap();
     let compiletest_rustfix = compiletest_deps.iter().find(|p| p.name == "rustfix").unwrap();
     if cargo_rustfix.version != compiletest_rustfix.version {
index 40375f1306d629700f41b8e81369de264d843636..97e56720b985260a6cfd1a04b87986339aea3deb 100644 (file)
@@ -62,6 +62,7 @@ fn tidy_error(bad: &mut bool, args: impl Display) -> std::io::Result<()> {
 pub mod mir_opt_tests;
 pub mod pal;
 pub mod primitive_docs;
+pub mod rustdoc_gui_tests;
 pub mod style;
 pub mod target_specific_tests;
 pub mod tests_placement;
index ea2886a3c2f8fda013abaf1c581a466939f36694..0b9a1b37e947ec81b58a9c7f46aa1132e9994f27 100644 (file)
@@ -80,6 +80,7 @@ macro_rules! check {
         check!(debug_artifacts, &tests_path);
         check!(ui_tests, &tests_path);
         check!(mir_opt_tests, &tests_path, bless);
+        check!(rustdoc_gui_tests, &tests_path);
 
         // Checks that only make sense for the compiler.
         check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
diff --git a/src/tools/tidy/src/rustdoc_gui_tests.rs b/src/tools/tidy/src/rustdoc_gui_tests.rs
new file mode 100644 (file)
index 0000000..feb513d
--- /dev/null
@@ -0,0 +1,33 @@
+//! Tidy check to ensure that rustdoc GUI tests start with a small description.
+
+use std::path::Path;
+
+pub fn check(path: &Path, bad: &mut bool) {
+    crate::walk::walk(
+        &path.join("rustdoc-gui"),
+        &mut |p| {
+            // If there is no extension, it's very likely a folder and we want to go into it.
+            p.extension().map(|e| e != "goml").unwrap_or(false)
+        },
+        &mut |entry, content| {
+            for line in content.lines() {
+                if !line.starts_with("// ") {
+                    tidy_error!(
+                        bad,
+                        "{}: rustdoc-gui tests must start with a small description",
+                        entry.path().display(),
+                    );
+                    return;
+                } else if line.starts_with("// ") {
+                    let parts = line[2..].trim();
+                    // We ignore tidy comments.
+                    if parts.starts_with("// tidy-") {
+                        continue;
+                    }
+                    // All good!
+                    return;
+                }
+            }
+        },
+    );
+}
index aa59c713b7846dabbb55cce82be977b148eb91f8..1daa213fc821392f6ebefe5ce99ca36387af7c17 100644 (file)
@@ -2,6 +2,7 @@
 // prevent optimizing away bounds checks
 
 // compile-flags: -O
+// ignore-debug: the debug assertions get in the way
 
 #![crate_type="rlib"]
 
index ff4fe1a93246ec0406679043402502f1e7d6a9f2..16d10eb5968c1b897b178a2fa30cd0526e370b8c 100644 (file)
@@ -18,8 +18,8 @@ fn consts<const C: u32>() {
     })
 }
 
-static S: i32 = 5;
-static mut T: i32 = 10;
+static S: i32 = 0x05050505;
+static mut T: i32 = 0x0a0a0a0a;
 // EMIT_MIR consts.statics.built.after.mir
 #[custom_mir(dialect = "built")]
 fn statics() {
index ee768e263ecdf9d536a824f6600cd04194461847..bfef976aa02726b299276088ac0e5e343b97b3b3 100644 (file)
@@ -19,9 +19,9 @@ fn statics() -> () {
 }
 
 alloc2 (static: T, size: 4, align: 4) {
-    0a 00 00 00                                     │ ....
+    0a 0a 0a 0a                                     │ ....
 }
 
 alloc1 (static: S, size: 4, align: 4) {
-    05 00 00 00                                     │ ....
+    05 05 05 05                                     │ ....
 }
index b9d551c5e5fc26a318b368d671927eb65ac77146..7fa29cccd50d602b0e01bc4ed258c20cadc8564a 100644 (file)
@@ -38,6 +38,6 @@
   }
   
   alloc1 (static: STATIC, size: 4, align: 4) {
-      2a 00 00 00                                     │ *...
+      42 42 42 42                                     │ BBBB
   }
   
index 8c23c5fcf0f88948a0952e751394e693bd26ca30..b69ec931a6311360a097698f26319e9e7b57a899 100644 (file)
@@ -1,7 +1,7 @@
 // unit-test
 // compile-flags: -O
 
-static mut STATIC: u32 = 42;
+static mut STATIC: u32 = 0x42424242;
 
 // EMIT_MIR mutable_variable_no_prop.main.ConstProp.diff
 fn main() {
index 2a4dc9e3e809919ed553686727fbb420e1594fb4..a28da146e378659e68193505aeba97c8cb3d0d08 100644 (file)
       let mut _6: ();                      // in scope 0 at $DIR/inline_into_box_place.rs:+1:42: +1:43
       let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43
 +     let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
++     let mut _9: std::vec::Vec<u32>;      // in scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
       scope 1 {
           debug _x => _1;                  // in scope 1 at $DIR/inline_into_box_place.rs:+1:9: +1:11
       }
       scope 2 {
       }
 +     scope 3 (inlined Vec::<u32>::new) {  // at $DIR/inline_into_box_place.rs:8:33: 8:43
-+         let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         let mut _10: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +     }
   
       bb0: {
@@ -37,8 +38,9 @@
 -         (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
 +         StorageLive(_8);                 // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
 +         _8 = &mut (*_7);                 // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
-+         StorageLive(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         _9 = const _;                    // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageLive(_9);                 // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
++         StorageLive(_10);                // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         _10 = const _;                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
                                            // mir::Constant
 -                                          // + span: $DIR/inline_into_box_place.rs:8:33: 8:41
 -                                          // + user_ty: UserType(1)
 +                                          // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
-+         Deinit((*_8));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         Deinit(_9);                      // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         (_9.0: alloc::raw_vec::RawVec<u32>) = move _10; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         (_9.1: usize) = const 0_usize;   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageDead(_10);                // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         (*_8) = move _9;                 // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
++         StorageDead(_9);                 // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
 +         StorageDead(_8);                 // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
           _1 = move _5;                    // scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43
           StorageDead(_5);                 // scope 0 at $DIR/inline_into_box_place.rs:+1:42: +1:43
diff --git a/tests/mir-opt/inline/issue_106141.outer.Inline.diff b/tests/mir-opt/inline/issue_106141.outer.Inline.diff
new file mode 100644 (file)
index 0000000..97361fa
--- /dev/null
@@ -0,0 +1,55 @@
+- // MIR for `outer` before Inline
++ // MIR for `outer` after Inline
+  
+  fn outer() -> usize {
+      let mut _0: usize;                   // return place in scope 0 at $DIR/issue_106141.rs:+0:19: +0:24
++     scope 1 (inlined inner) {            // at $DIR/issue_106141.rs:2:5: 2:12
++         let mut _1: bool;                // in scope 1 at $DIR/issue_106141.rs:13:8: 13:21
++         let mut _2: bool;                // in scope 1 at $DIR/issue_106141.rs:13:8: 13:21
++         let mut _3: &[bool; 1];          // in scope 1 at $DIR/issue_106141.rs:11:18: 11:25
++         scope 2 {
++             debug buffer => _3;          // in scope 2 at $DIR/issue_106141.rs:11:9: 11:15
++             scope 3 {
++                 debug index => _0;       // in scope 3 at $DIR/issue_106141.rs:12:9: 12:14
++             }
++         }
++     }
+  
+      bb0: {
+-         _0 = inner() -> bb1;             // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
++         StorageLive(_3);                 // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
++         _3 = const _;                    // scope 1 at $DIR/issue_106141.rs:11:18: 11:25
+                                           // mir::Constant
+-                                          // + span: $DIR/issue_106141.rs:2:5: 2:10
+-                                          // + literal: Const { ty: fn() -> usize {inner}, val: Value(<ZST>) }
++                                          // + span: $DIR/issue_106141.rs:11:18: 11:25
++                                          // + literal: Const { ty: &[bool; 1], val: Unevaluated(inner, [], Some(promoted[0])) }
++         _0 = index() -> bb1;             // scope 2 at $DIR/issue_106141.rs:12:17: 12:24
++                                          // mir::Constant
++                                          // + span: $DIR/issue_106141.rs:12:17: 12:22
++                                          // + literal: Const { ty: fn() -> usize {index}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
++         StorageLive(_1);                 // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++         _2 = Lt(_0, const 1_usize);      // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++         assert(move _2, "index out of bounds: the length is {} but the index is {}", const 1_usize, _0) -> bb2; // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++     }
++ 
++     bb2: {
++         _1 = (*_3)[_0];                  // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++         switchInt(move _1) -> [0: bb3, otherwise: bb4]; // scope 3 at $DIR/issue_106141.rs:13:8: 13:21
++     }
++ 
++     bb3: {
++         _0 = const 0_usize;              // scope 3 at $DIR/issue_106141.rs:16:9: 16:10
++         goto -> bb4;                     // scope 3 at $DIR/issue_106141.rs:13:5: 17:6
++     }
++ 
++     bb4: {
++         StorageDead(_1);                 // scope 3 at $DIR/issue_106141.rs:17:5: 17:6
++         StorageDead(_3);                 // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12
+          return;                          // scope 0 at $DIR/issue_106141.rs:+2:2: +2:2
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/issue_106141.rs b/tests/mir-opt/inline/issue_106141.rs
new file mode 100644 (file)
index 0000000..c8288b7
--- /dev/null
@@ -0,0 +1,24 @@
+pub fn outer() -> usize {
+    inner()
+}
+
+fn index() -> usize {
+    loop {}
+}
+
+#[inline]
+fn inner() -> usize {
+    let buffer = &[true];
+    let index = index();
+    if buffer[index] {
+        index
+    } else {
+        0
+    }
+}
+
+fn main() {
+    outer();
+}
+
+// EMIT_MIR issue_106141.outer.Inline.diff
index 1c69a6232d60631e30f8b36dc538819916abf6bc..93804780371cd41d11207b768bdad81a67f63269 100644 (file)
@@ -26,7 +26,7 @@
           _3 = _1;                         // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52
           _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53
                                            // mir::Constant
-                                           // + span: $DIR/issue_75439.rs:7:37: 7:46
+                                           // + span: $DIR/issue_75439.rs:8:37: 8:46
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(<ZST>) }
       }
   
@@ -49,7 +49,7 @@
           _6 = _4;                         // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35
           _5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36
                                            // mir::Constant
-                                           // + span: $DIR/issue_75439.rs:10:23: 10:32
+                                           // + span: $DIR/issue_75439.rs:11:23: 11:32
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(<ZST>) }
       }
   
index ae2e036312e88373f7f3804d191bed8932afc681..4c749a150c091f5159defd11c28594e7cd22633c 100644 (file)
@@ -1,4 +1,5 @@
 // EMIT_MIR issue_75439.foo.MatchBranchSimplification.diff
+// ignore-endian-big
 
 use std::mem::transmute;
 
index c9b53a1a0f76c5b207c43377583f3bde26b310df..85cb72274208c4184b2edaee0642a6faac64718c 100644 (file)
@@ -2,7 +2,7 @@
 
 define-function: (
     "check-colors",
-    (theme, main_color, title_color, fqn_color, fqn_type_color, src_link_color, sidebar_link_color),
+    (theme, main_color, title_color, main_heading_color, main_heading_type_color, src_link_color, sidebar_link_color),
     block {
         goto: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
         // This is needed to ensure that the text color is computed.
@@ -14,8 +14,8 @@ define-function: (
         reload:
 
         assert-css: ("#toggle-all-docs", {"color": |main_color|})
-        assert-css: (".fqn a:nth-of-type(1)", {"color": |fqn_color|})
-        assert-css: (".fqn a:nth-of-type(2)", {"color": |fqn_type_color|})
+        assert-css: (".main-heading h1 a:nth-of-type(1)", {"color": |main_heading_color|})
+        assert-css: (".main-heading a:nth-of-type(2)", {"color": |main_heading_type_color|})
         assert-css: (
              ".rightside .srclink",
              {"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|},
@@ -57,7 +57,7 @@ define-function: (
         assert-css: ("#top-doc-prose-title", {"color": |title_color|})
 
         assert-css: (".sidebar a", {"color": |sidebar_link_color|})
-        assert-css: ("h1.fqn a", {"color": |title_color|})
+        assert-css: (".main-heading h1 a", {"color": |title_color|})
 
         // We move the cursor over the "Implementations" title so the anchor is displayed.
         move-cursor-to: "h2#implementations"
@@ -77,8 +77,8 @@ call-function: (
         "theme": "ayu",
         "main_color": "rgb(197, 197, 197)",
         "title_color": "rgb(255, 255, 255)",
-        "fqn_color": "rgb(255, 255, 255)",
-        "fqn_type_color": "rgb(255, 160, 165)",
+        "main_heading_color": "rgb(255, 255, 255)",
+        "main_heading_type_color": "rgb(255, 160, 165)",
         "src_link_color": "rgb(57, 175, 215)",
         "sidebar_link_color": "rgb(83, 177, 219)",
     },
@@ -89,8 +89,8 @@ call-function: (
         "theme": "dark",
         "main_color": "rgb(221, 221, 221)",
         "title_color": "rgb(221, 221, 221)",
-        "fqn_color": "rgb(221, 221, 221)",
-        "fqn_type_color": "rgb(45, 191, 184)",
+        "main_heading_color": "rgb(221, 221, 221)",
+        "main_heading_type_color": "rgb(45, 191, 184)",
         "src_link_color": "rgb(210, 153, 29)",
         "sidebar_link_color": "rgb(253, 191, 53)",
     },
@@ -101,8 +101,8 @@ call-function: (
         "theme": "light",
         "main_color": "rgb(0, 0, 0)",
         "title_color": "rgb(0, 0, 0)",
-        "fqn_color": "rgb(0, 0, 0)",
-        "fqn_type_color": "rgb(173, 55, 138)",
+        "main_heading_color": "rgb(0, 0, 0)",
+        "main_heading_type_color": "rgb(173, 55, 138)",
         "src_link_color": "rgb(56, 115, 173)",
         "sidebar_link_color": "rgb(53, 109, 164)",
     },
index 108cf8abcb529d2bf238733f3487c4430a053766..971c2f9480ea2fb00a6bb7f235af31d5865bec01 100644 (file)
@@ -1,3 +1,5 @@
+// Small test to ensure the "src-line-numbers" element is only present once on
+// the page.
 goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
 click: ".srclink"
 wait-for: ".src-line-numbers"
index 45b3fee26e413dc054a6ded9605a9f9b32434afd..e4ba5f1246d91f7a3ec9854c34bec1ce31a2475c 100644 (file)
@@ -13,7 +13,7 @@
 // 14px  0.875rem
 goto: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
 
-assert-css: ("h1.fqn", {"font-size": "24px"})
+assert-css: (".main-heading h1", {"font-size": "24px"})
 
 assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
@@ -52,7 +52,7 @@ assert-css: ("h6#sub-sub-heading-for-struct-impl-item-doc", {"font-size": "14px"
 
 goto: "file://" + |DOC_PATH| + "/test_docs/enum.HeavilyDocumentedEnum.html"
 
-assert-css: ("h1.fqn", {"font-size": "24px"})
+assert-css: (".main-heading h1", {"font-size": "24px"})
 
 assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
@@ -111,7 +111,7 @@ assert-css: ("//ul[@class='block mod']/preceding-sibling::h3", {"border-bottom-w
 
 goto: "file://" + |DOC_PATH| + "/test_docs/union.HeavilyDocumentedUnion.html"
 
-assert-css: ("h1.fqn", {"font-size": "24px"})
+assert-css: (".main-heading h1", {"font-size": "24px"})
 
 assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
@@ -143,7 +143,7 @@ assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"border-bottom-width": "
 
 goto: "file://" + |DOC_PATH| + "/test_docs/macro.heavily_documented_macro.html"
 
-assert-css: ("h1.fqn", {"font-size": "24px"})
+assert-css: (".main-heading h1", {"font-size": "24px"})
 
 assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
index ed36bcdec17d2261f9ad058f6b3a1724006fa910..720268a9e7eb1d6cf721aa7d068fc393e227bd80 100644 (file)
@@ -1,18 +1,18 @@
 // This test ensures that the margins on methods are coherent inside an impl block.
 goto: "file://" + |DOC_PATH| + "/test_docs/trait_members/struct.HasTrait.html#impl-TraitMembers-for-HasTrait"
 
-assert-count: ("#trait-implementations-list > .rustdoc-toggle", 1)
+assert-count: ("#trait-implementations-list > .toggle", 1)
 
 compare-elements-css: (
     // compare margin on type with margin on method
-    "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(1) > summary",
-    "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(2) > summary",
+    "#trait-implementations-list .impl-items > .toggle:nth-child(1) > summary",
+    "#trait-implementations-list .impl-items > .toggle:nth-child(2) > summary",
     ["margin"]
 )
 
 compare-elements-css: (
     // compare margin on type with margin on method
-    "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(1)",
-    "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(2)",
+    "#trait-implementations-list .impl-items > .toggle:nth-child(1)",
+    "#trait-implementations-list .impl-items > .toggle:nth-child(2)",
     ["margin"]
 )
index 10651a3f6696d5ef41eaef999ee37c527446b97a..1b5c3a0d202a0cfd1bd88fb96cb528764ff69822 100644 (file)
@@ -1,3 +1,5 @@
+// This test ensures that the scraped examples buttons are working as expecting
+// when 'Enter' key is pressed when they're focused.
 goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html"
 
 // The next/prev buttons vertically scroll the code viewport between examples
index 994fd87c9966fb396f4f05d6fae6a307bfbbd78b..f444baa6ce10bb3fb56433ff251899bae646ab9b 100644 (file)
@@ -3,17 +3,17 @@
 // First, we check that the first page doesn't have the string we're looking for to ensure
 // that the feature is changing page as expected.
 goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
-assert-text-false: (".fqn", "Struct test_docs::Foo")
+assert-text-false: (".main-heading h1", "Struct test_docs::Foo")
 
 // We now check that we land on the search result page if "go_to_first" isn't set.
 goto: "file://" + |DOC_PATH| + "/test_docs/index.html?search=struct%3AFoo"
 // Waiting for the search results to appear...
 wait-for: "#search-tabs"
-assert-text-false: (".fqn", "Struct test_docs::Foo")
+assert-text-false: (".main-heading h1", "Struct test_docs::Foo")
 // Ensure that the search results are displayed, not the "normal" content.
 assert-css: ("#main-content", {"display": "none"})
 
 // Now we can check that the feature is working as expected!
 goto: "file://" + |DOC_PATH| + "/test_docs/index.html?search=struct%3AFoo&go_to_first=true"
 // Waiting for the page to load...
-wait-for-text: (".fqn", "Struct test_docs::Foo")
+wait-for-text: (".main-heading h1", "Struct test_docs::Foo")
index fc3beaa53fafcb396d81b49da63b59930fb61107..f236dc3e0fe7681344504d8677b693de6c59044b 100644 (file)
@@ -159,7 +159,7 @@ assert-text: ("#preferred-light-theme .setting-name", "Preferred light theme")
 // We now check that clicking on the toggles' text is like clicking on the checkbox.
 // To test it, we use the "Disable keyboard shortcuts".
 local-storage: {"rustdoc-disable-shortcuts": "false"}
-click: ".setting-line:last-child .toggle .label"
+click: ".setting-line:last-child .settings-toggle .label"
 assert-local-storage: {"rustdoc-disable-shortcuts": "true"}
 
 // Make sure that "Disable keyboard shortcuts" actually took effect.
@@ -169,7 +169,7 @@ assert-false: "#help-button .popover"
 wait-for-css: ("#settings-menu .popover", {"display": "block"})
 
 // Now turn keyboard shortcuts back on, and see if they work.
-click: ".setting-line:last-child .toggle .label"
+click: ".setting-line:last-child .settings-toggle .label"
 assert-local-storage: {"rustdoc-disable-shortcuts": "false"}
 press-key: "Escape"
 press-key: "?"
index 029403ee13ee1bdd0b0e562e03c97fde5715e56e..ac346f25b8862c5c40aaa2bb71a7962421bb4971 100644 (file)
@@ -1,15 +1,15 @@
 // This test ensures that clicking on a method summary, but not on the "[-]",
 // doesn't toggle the <details>.
 goto: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html"
-assert-attribute: (".impl-items .rustdoc-toggle", {"open": ""})
+assert-attribute: (".impl-items .toggle", {"open": ""})
 click: "h4.code-header" // This is the position of "pub" in "pub fn a_method"
-assert-attribute: (".impl-items .rustdoc-toggle", {"open": ""})
+assert-attribute: (".impl-items .toggle", {"open": ""})
 click-with-offset: (
-    ".impl-items .rustdoc-toggle summary",
+    ".impl-items .toggle summary",
     {"x": -24, "y": 8}, // This is the position of "[-]" next to that pub fn.
 )
-assert-attribute-false: (".impl-items .rustdoc-toggle", {"open": ""})
+assert-attribute-false: (".impl-items .toggle", {"open": ""})
 
 // Click the "Trait" part of "impl Trait" and verify it navigates.
 click: "#impl-Trait-for-Foo h3 a:first-of-type"
-assert-text: (".fqn", "Trait lib2::Trait")
+assert-text: (".main-heading h1", "Trait lib2::Trait")
index 89ce78e3aab4b6274081590cd29ab47dd1adf0c1..c9d236e9bba8a04ab8d5fee055a4e974ed767e0b 100644 (file)
@@ -20,10 +20,10 @@ assert-text: ("#toggle-all-docs", "[−]")
 goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
 // We first check that everything is visible.
 assert-text: ("#toggle-all-docs", "[−]")
-assert-attribute: ("#implementations-list details.rustdoc-toggle", {"open": ""}, ALL)
-assert-attribute: ("#trait-implementations-list details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute: ("#implementations-list details.toggle", {"open": ""}, ALL)
+assert-attribute: ("#trait-implementations-list details.toggle", {"open": ""}, ALL)
 assert-attribute-false: (
-    "#blanket-implementations-list > details.rustdoc-toggle",
+    "#blanket-implementations-list > details.toggle",
     {"open": ""},
     ALL,
 )
@@ -32,18 +32,18 @@ assert-attribute-false: (
 click: "#toggle-all-docs"
 wait-for-text: ("#toggle-all-docs", "[+]")
 // We check that all <details> are collapsed (except for the impl block ones).
-assert-attribute-false: ("details.rustdoc-toggle:not(.implementors-toggle)", {"open": ""}, ALL)
+assert-attribute-false: ("details.toggle:not(.implementors-toggle)", {"open": ""}, ALL)
 assert-attribute: ("#implementations-list > details.implementors-toggle", {"open": ""})
 // We now check that the other impl blocks are collapsed.
 assert-attribute-false: (
-    "#blanket-implementations-list > details.rustdoc-toggle.implementors-toggle",
+    "#blanket-implementations-list > details.toggle.implementors-toggle",
     {"open": ""},
     ALL,
 )
 // We open them all again.
 click: "#toggle-all-docs"
 wait-for-text: ("#toggle-all-docs", "[−]")
-assert-attribute: ("details.rustdoc-toggle", {"open": ""}, ALL)
+assert-attribute: ("details.toggle", {"open": ""}, ALL)
 
 // Checking the toggles style.
 show-text: true
@@ -56,12 +56,12 @@ define-function: (
         // We reload the page so the local storage settings are being used.
         reload:
 
-        assert-css: ("details.rustdoc-toggle > summary::before", {
+        assert-css: ("details.toggle > summary::before", {
             "opacity": "0.5",
             "filter": |filter|,
         }, ALL)
-        move-cursor-to: "details.rustdoc-toggle summary"
-        assert-css: ("details.rustdoc-toggle > summary:hover::before", {
+        move-cursor-to: "details.toggle summary"
+        assert-css: ("details.toggle > summary:hover::before", {
             "opacity": "1",
             "filter": |filter|,
         })
index e4d59b5d72858b54759e9d3c1c1ee3afd73023e0..000293b555f84ad83774da1e782c26cd3720365a 100644 (file)
@@ -2,4 +2,4 @@
 // has all the implementations toggled open by default, so users can
 // find method names in those implementations with Ctrl-F.
 goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
-assert-attribute: (".rustdoc-toggle.implementors-toggle", {"open": ""})
+assert-attribute: (".toggle.implementors-toggle", {"open": ""})
index 597d19e748cb7a1836ec4e8f2f961d0b08b02ee4..6140a06c555f2c5641c68b9a40a911225b3a6be6 100644 (file)
@@ -77,8 +77,6 @@ LL | ///     ```
    |         ^^^
    |
    = note: error from rustc: unknown start of token: `
-   = note: error from rustc: unknown start of token: `
-   = note: error from rustc: unknown start of token: `
 
 warning: could not parse code block as Rust code
   --> $DIR/invalid-syntax.rs:64:5
index 43f30f3d6e80088c23f0c87b125dbad4c8a4dce4..4bdecdc1b79446302261626e67df86d9c77e6ad0 100644 (file)
@@ -76,6 +76,7 @@
     -Z                            llvm-plugins=val -- a list LLVM plugins to enable (space separated)
     -Z                         llvm-time-trace=val -- generate JSON tracing data file from LLVM data (default: no)
     -Z                         location-detail=val -- what location details should be tracked when using caller_location, either `none`, or a comma separated list of location details, for which valid options are `file`, `line`, and `column` (default: `file,line,column`)
+    -Z                           log-backtrace=val -- add a backtrace along with logging
     -Z                                      ls=val -- list the symbols defined by a library crate (default: no)
     -Z                         macro-backtrace=val -- show macro backtraces (default: no)
     -Z             maximal-hir-to-mir-coverage=val -- save as much information as possible about the correspondence between MIR and HIR as source scopes (default: no)
index f2ec8320a05259464874f15483906d95c7581435..46be00a080482818f4af2c588dbdf6612953ea4a 100644 (file)
@@ -1 +1 @@
-<script type="text/json" id="notable-traits-data">{"&amp;'static [SomeStruct]":"&lt;h3&gt;Notable traits for &lt;code&gt;&amp;amp;[&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\"&gt;SomeStruct&lt;/a&gt;]&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait_slice::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &amp;amp;[&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\"&gt;SomeStruct&lt;/a&gt;]&lt;/span&gt;"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"&amp;'static [SomeStruct]":"&lt;h3&gt;Notable traits for &lt;code&gt;&amp;amp;[&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\"&gt;SomeStruct&lt;/a&gt;]&lt;/code&gt;&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait_slice::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &amp;amp;[&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\"&gt;SomeStruct&lt;/a&gt;]&lt;/span&gt;"}</script>
\ No newline at end of file
index b426a4d7a8b7ba660183a36e66f09a120dd763f9..f592e3b375c026061ec0fb7274a8eef453f201b5 100644 (file)
@@ -1 +1 @@
-<script type="text/json" id="notable-traits-data">{"SomeStruct":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/span&gt;"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"SomeStruct":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/span&gt;"}</script>
\ No newline at end of file
index 4f8063807e67dc590cbadd4babd5fb0c2b271c68..384be668954000f0a61b53d43cdccd4249881487 100644 (file)
@@ -1 +1 @@
-<script type="text/json" id="notable-traits-data">{"SomeStruct":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/span&gt;","Wrapper&lt;Self&gt;":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl&amp;lt;T:&amp;nbsp;&lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt;&amp;gt; &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/span&gt;"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"SomeStruct":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/span&gt;","Wrapper&lt;Self&gt;":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl&amp;lt;T:&amp;nbsp;&lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt;&amp;gt; &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/span&gt;"}</script>
\ No newline at end of file
index bed2a38b24a2bb1b3421c94d4abc3e05fa6a6a71..0cc1ee10fd33571f268e88aacd0fe54a185e8013 100644 (file)
@@ -1 +1 @@
-<script type="text/json" id="notable-traits-data">{"Wrapper&lt;Self&gt;":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl&amp;lt;T:&amp;nbsp;&lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt;&amp;gt; &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/span&gt;"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"Wrapper&lt;Self&gt;":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl&amp;lt;T:&amp;nbsp;&lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt;&amp;gt; &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/span&gt;"}</script>
\ No newline at end of file
index 0c947ea2e28788aaab6f11a7b0f38e9a410e6c42..fc755afda4a9cfa2ad24f08502c54101786f291a 100644 (file)
@@ -5,7 +5,7 @@
 #![crate_name = "foo"]
 
 // @has foo/../index.html
-// @has - '//h1[@class="fqn"]' 'List of all crates'
+// @has - '//h1' 'List of all crates'
 // @has - '//ul[@class="all-items"]//a[@href="foo/index.html"]' 'foo'
 // @has - '//ul[@class="all-items"]//a[@href="all_item_types/index.html"]' 'all_item_types'
 pub struct Foo;
index 769f984a274a776c8771eb34bc1b2ede21233dd7..7578d49daa508753c34111b664d431faad397c7a 100644 (file)
@@ -5,7 +5,7 @@
 // @!hasraw - '<span class="attr">#[outer]</span>'
 // @hasraw - '#![inner]</span>'
 // @!hasraw - '<span class="attr">#![inner]</span>'
-// @snapshot 'codeblock' - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]//pre/code'
+// @snapshot 'codeblock' - '//*[@class="toggle top-doc"]/*[@class="docblock"]//pre/code'
 
 /// ```no_run
 /// # # space
index ea1273850912d27035272f46da4df74f8eb575ae..4d047af325515d7c8cfdddf6207be51765fb75c9 100644 (file)
@@ -7,7 +7,7 @@
 // @has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Keywords'
 // @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#keywords'
 // @has foo/keyword.match.html '//a[@class="keyword"]' 'match'
-// @has foo/keyword.match.html '//h1[@class="fqn"]' 'Keyword match'
+// @has foo/keyword.match.html '//h1' 'Keyword match'
 // @has foo/keyword.match.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 // @has foo/index.html '//a/@href' '../foo/index.html'
 // @!has foo/foo/index.html
index 1c8468008dd0afd0eb64d80e32174a1c16c1a93c..5dc857773a393ebf1fb883b674a628132269cb2b 100644 (file)
@@ -4,7 +4,7 @@
 #![crate_name = "foo"]
 
 // @has 'foo/fn.g.html'
-// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' \
+// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' \
 // 'outer module inner module'
 
 mod inner_mod {
index a27c5ae6d0128c95d21a6f8dc791bfd8ca9542ad..010058361faafa33e4a63feb9c9dff718dcd0865 100644 (file)
@@ -1,7 +1,7 @@
 #![crate_name = "foo"]
 
 // @has 'foo/struct.S1.html'
-// @snapshot S1_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+// @snapshot S1_top-doc - '//details[@class="toggle top-doc"]/div[@class="docblock"]'
 
 #[doc = "Hello world!\n\n"]
 /// Goodbye!
@@ -9,7 +9,7 @@
 pub struct S1;
 
 // @has 'foo/struct.S2.html'
-// @snapshot S2_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+// @snapshot S2_top-doc - '//details[@class="toggle top-doc"]/div[@class="docblock"]'
 
 /// Hello world!
 ///
@@ -18,7 +18,7 @@
 pub struct S2;
 
 // @has 'foo/struct.S3.html'
-// @snapshot S3_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+// @snapshot S3_top-doc - '//details[@class="toggle top-doc"]/div[@class="docblock"]'
 /** Par 1
 */ ///
 /// Par 2
index 1daae49cde9d056cfbc76d18c520057c2a119450..29b67c6b2b17bad3c7940138763e76609e14f840 100644 (file)
@@ -21,14 +21,14 @@ mod c {
 }
 
 // @has 'foo/struct.Type.html'
-// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'foo 2 1'
+// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'foo 2 1'
 /// foo
 pub use b::Type;
 // @has 'foo/struct.Whatever.html'
-// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'whatever 3 2 1'
+// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'whatever 3 2 1'
 /// whatever
 pub use c::Type as Whatever;
 // @has 'foo/struct.Woof.html'
-// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' 'a dog 4 2 1'
+// @has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'a dog 4 2 1'
 /// a dog
 pub use c::Woof;
index ea8d2d1660266a45ea9744264a8f572f91270ab9..c3a5eb6d324a475513930b35c91dbff969d7b4d3 100644 (file)
@@ -9,7 +9,7 @@
 // @has - '//div[@class="sidebar-elems"]//li/a/@href' '#primitives'
 // @has foo/primitive.reference.html
 // @has - '//a[@class="primitive"]' 'reference'
-// @has - '//h1[@class="fqn"]' 'Primitive Type reference'
+// @has - '//h1' 'Primitive Type reference'
 // @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 
 // There should be only one implementation listed.
index cdddd6b65078e9f2098d61fd539479ae3203ce96..77922414676101fc548d0758dd62919fb7005737 100644 (file)
@@ -4,7 +4,7 @@
 #![feature(rustdoc_internals)]
 
 // @has foo/primitive.slice.html '//a[@class="primitive"]' 'slice'
-// @has - '//h1[@class="fqn"]' 'Primitive Type slice'
+// @has - '//h1' 'Primitive Type slice'
 // @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 // @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
 // @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T]where T: Send'
index df681457f0f1f27f495a1780bfde020dd220cc7a..4344d24f98650aa5c6db2eea0cc9c52912e5c3ab 100644 (file)
@@ -4,7 +4,7 @@
 #![feature(rustdoc_internals)]
 
 // @has foo/primitive.tuple.html '//a[@class="primitive"]' 'tuple'
-// @has - '//h1[@class="fqn"]' 'Primitive Type tuple'
+// @has - '//h1' 'Primitive Type tuple'
 // @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 // @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
 // @has - '//div[@id="synthetic-implementations-list"]//h3' 'Send'
index 391e33bea616a511a5cb3e0f57b2b69ddba5b65c..61850e2462d887bb545ccc3d65f52dc7ca62faf6 100644 (file)
@@ -4,7 +4,7 @@
 #![feature(rustdoc_internals)]
 
 // @has foo/primitive.unit.html '//a[@class="primitive"]' 'unit'
-// @has - '//h1[@class="fqn"]' 'Primitive Type unit'
+// @has - '//h1' 'Primitive Type unit'
 // @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 // @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
 // @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Send for ()'
index 6347fdac3db53bbbd652a7fa94ee558b35a0313f..516c7c0c6fe9bd40da798b32a95b1b6998ed672c 100644 (file)
@@ -7,7 +7,7 @@
 // @has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Primitive Types'
 // @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#primitives'
 // @has foo/primitive.i32.html '//a[@class="primitive"]' 'i32'
-// @has foo/primitive.i32.html '//h1[@class="fqn"]' 'Primitive Type i32'
+// @has foo/primitive.i32.html '//h1' 'Primitive Type i32'
 // @has foo/primitive.i32.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 // @has foo/index.html '//a/@href' '../foo/index.html'
 // @!has foo/index.html '//span' '🔒'
index 1d02c13ebfb3c2b9b3ed8d1cf34d94fbb6a8f7eb..5f54b7522ae38774e61e4c8cd7c44dc775ad410b 100644 (file)
@@ -1 +1 @@
-<script type="text/json" id="notable-traits-data">{"Odd":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\"&gt;Odd&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html\" title=\"trait core::iter::traits::iterator::Iterator\"&gt;Iterator&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\"&gt;Odd&lt;/a&gt;&lt;/span&gt;&lt;span class=\"where fmt-newline\"&gt;    type &lt;a href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item\" class=\"associatedtype\"&gt;Item&lt;/a&gt; = &lt;a class=\"primitive\" href=\"{{channel}}/std/primitive.usize.html\"&gt;usize&lt;/a&gt;;&lt;/span&gt;"}</script>
\ No newline at end of file
+<script type="text/json" id="notable-traits-data">{"Odd":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\"&gt;Odd&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html\" title=\"trait core::iter::traits::iterator::Iterator\"&gt;Iterator&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\"&gt;Odd&lt;/a&gt;&lt;/span&gt;&lt;span class=\"where fmt-newline\"&gt;    type &lt;a href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item\" class=\"associatedtype\"&gt;Item&lt;/a&gt; = &lt;a class=\"primitive\" href=\"{{channel}}/std/primitive.usize.html\"&gt;usize&lt;/a&gt;;&lt;/span&gt;"}</script>
\ No newline at end of file
index ea28d84f1ffdfe63fd0b41bad05a8c29205c822e..ca4c93f92e0a4f4a705ef02323c9629e450aac33 100644 (file)
@@ -4,7 +4,7 @@
 // block doc comments can have their lines starting with a star.
 
 // @has foo/fn.foo.html
-// @snapshot docblock - '//*[@class="rustdoc-toggle top-doc"]//*[@class="docblock"]'
+// @snapshot docblock - '//*[@class="toggle top-doc"]//*[@class="docblock"]'
 /**
  *     a
  */
index 47a1d62f5a7a3fc5cb81b1d61e8a055262b112e7..87240f233ff2afef5e28f90d16d49c1b6d0c9133 100644 (file)
@@ -1,15 +1,15 @@
 #![allow(unused)]
 
 // @has 'toggle_item_contents/struct.PubStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @count - '//details[@class="toggle type-contents-toggle"]' 0
 pub struct PubStruct {
     pub a: usize,
     pub b: usize,
 }
 
 // @has 'toggle_item_contents/struct.BigPubStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 fields'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 13 fields'
 pub struct BigPubStruct {
     pub a: usize,
     pub b: usize,
@@ -27,8 +27,8 @@ pub struct BigPubStruct {
 }
 
 // @has 'toggle_item_contents/union.BigUnion.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 fields'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 13 fields'
 pub union BigUnion {
     pub a: usize,
     pub b: usize,
@@ -46,7 +46,7 @@ pub union BigUnion {
 }
 
 // @has 'toggle_item_contents/union.Union.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @count - '//details[@class="toggle type-contents-toggle"]' 0
 pub union Union {
     pub a: usize,
     pub b: usize,
@@ -54,7 +54,7 @@ pub union Union {
 }
 
 // @has 'toggle_item_contents/struct.PrivStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @count - '//details[@class="toggle type-contents-toggle"]' 0
 // @has - '//div[@class="item-decl"]' '/* private fields */'
 pub struct PrivStruct {
     a: usize,
@@ -62,7 +62,7 @@ pub struct PrivStruct {
 }
 
 // @has 'toggle_item_contents/enum.Enum.html'
-// @!has - '//details[@class="rustdoc-toggle type-contents-toggle"]' ''
+// @!has - '//details[@class="toggle type-contents-toggle"]' ''
 pub enum Enum {
     A, B, C,
     D {
@@ -72,7 +72,7 @@ pub enum Enum {
 }
 
 // @has 'toggle_item_contents/enum.EnumStructVariant.html'
-// @!has - '//details[@class="rustdoc-toggle type-contents-toggle"]' ''
+// @!has - '//details[@class="toggle type-contents-toggle"]' ''
 pub enum EnumStructVariant {
     A, B, C,
     D {
@@ -81,14 +81,14 @@ pub enum EnumStructVariant {
 }
 
 // @has 'toggle_item_contents/enum.LargeEnum.html'
-// @count - '//*[@class="rust enum"]//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//*[@class="rust enum"]//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 13 variants'
+// @count - '//*[@class="rust enum"]//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//*[@class="rust enum"]//details[@class="toggle type-contents-toggle"]' 'Show 13 variants'
 pub enum LargeEnum {
     A, B, C, D, E, F(u8), G, H, I, J, K, L, M
 }
 
 // @has 'toggle_item_contents/trait.Trait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @count - '//details[@class="toggle type-contents-toggle"]' 0
 pub trait Trait {
     type A;
     #[must_use]
@@ -97,8 +97,8 @@ pub trait Trait {
 }
 
 // @has 'toggle_item_contents/trait.GinormousTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 16 associated items'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 16 associated items'
 pub trait GinormousTrait {
     type A;
     type B;
@@ -120,8 +120,8 @@ pub trait GinormousTrait {
 }
 
 // @has 'toggle_item_contents/trait.HugeTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 12 associated constants and 2 methods'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 12 associated constants and 2 methods'
 pub trait HugeTrait {
     type A;
     const M: usize = 1;
@@ -142,8 +142,8 @@ pub trait HugeTrait {
 }
 
 // @has 'toggle_item_contents/trait.GiganticTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 1 associated constant and 1 method'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 1 associated constant and 1 method'
 pub trait GiganticTrait {
     type A;
     type B;
@@ -163,8 +163,8 @@ pub trait GiganticTrait {
 }
 
 // @has 'toggle_item_contents/trait.BigTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show 14 methods'
+// @count - '//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//details[@class="toggle type-contents-toggle"]' 'Show 14 methods'
 pub trait BigTrait {
     type A;
     #[must_use]
index 1aa74e5965960e56c8abdd6b95d5bc375195db4d..ebc316ca8ad2879ea0e5fcc171a8e70cc9ed294c 100644 (file)
@@ -4,9 +4,9 @@
 // summary. Struct methods with no documentation should not be wrapped.
 //
 // @has foo/struct.Foo.html
-// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
-// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
-// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
+// @has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
+// @has - '//details[@class="toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @!has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
 pub struct Foo {
 }
 
index 0a1f088b9ab5c8fb830f55120be7a6fb3d6b2f64..686a174fc8f954b4aa95e29912acf0b7fcb05ea3 100644 (file)
@@ -4,14 +4,14 @@
 // summary. Trait methods with no documentation should not be wrapped.
 //
 // @has foo/trait.Foo.html
-// @has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'type Item'
-// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'type Item2'
-// @has -  '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
-// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
-// @has -  '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
-// @has -  '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()'
-// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()'
-// @has -  '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
+// @has - '//details[@class="toggle"]//summary//h4[@class="code-header"]' 'type Item'
+// @!has - '//details[@class="toggle"]//summary//h4[@class="code-header"]' 'type Item2'
+// @has -  '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()'
+// @!has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()'
+// @has -  '//details[@class="toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @has -  '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()'
+// @!has - '//details[@class="toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()'
+// @has -  '//details[@class="toggle method-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
 pub trait Foo {
     /// is documented
     type Item;
diff --git a/tests/ui/associated-item/ambiguous-associated-type-with-generics.fixed b/tests/ui/associated-item/ambiguous-associated-type-with-generics.fixed
new file mode 100644 (file)
index 0000000..23f7152
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+trait Trait<A> {}
+
+trait Assoc {
+    type Ty;
+}
+
+impl<A> Assoc for dyn Trait<A> {
+    type Ty = i32;
+}
+
+fn main() {
+    let _x: <dyn Trait<i32> as Assoc>::Ty; //~ ERROR ambiguous associated type
+}
diff --git a/tests/ui/associated-item/ambiguous-associated-type-with-generics.rs b/tests/ui/associated-item/ambiguous-associated-type-with-generics.rs
new file mode 100644 (file)
index 0000000..9c26e33
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+trait Trait<A> {}
+
+trait Assoc {
+    type Ty;
+}
+
+impl<A> Assoc for dyn Trait<A> {
+    type Ty = i32;
+}
+
+fn main() {
+    let _x: <dyn Trait<i32>>::Ty; //~ ERROR ambiguous associated type
+}
diff --git a/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr b/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr
new file mode 100644 (file)
index 0000000..97088b7
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0223]: ambiguous associated type
+  --> $DIR/ambiguous-associated-type-with-generics.rs:13:13
+   |
+LL |     let _x: <dyn Trait<i32>>::Ty;
+   |             ^^^^^^^^^^^^^^^^^^^^ help: use the fully-qualified path: `<dyn Trait<i32> as Assoc>::Ty`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0223`.
index bf4bd634cf1d44d46580ead3479dd09e65d308c9..d0c170620766c4d19a983e0f7dc8fa75d8a77e51 100644 (file)
@@ -13,7 +13,7 @@ error[E0223]: ambiguous associated type
   --> $DIR/associated-item-duplicate-names-3.rs:18:12
    |
 LL |     let x: Baz::Bar = 5;
-   |            ^^^^^^^^ help: use fully-qualified syntax: `<Baz as Trait>::Bar`
+   |            ^^^^^^^^ help: use the fully-qualified path: `<Baz as Foo>::Bar`
 
 error: aborting due to 2 previous errors
 
index 289911779ff710a3800504d021a025c382049c12..00856b55df5ece3ba2e995e921b61b1c3ad93d36 100644 (file)
@@ -2,31 +2,46 @@ error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:6:36
    |
 LL | fn get<T:Get,U:Get>(x: T, y: U) -> Get::Value {}
-   |                                    ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Get>::Value`
+   |                                    ^^^^^^^^^^
+   |
+help: if there were a type named `Example` that implemented `Get`, you could use the fully-qualified path
+   |
+LL | fn get<T:Get,U:Get>(x: T, y: U) -> <Example as Get>::Value {}
+   |                                    ~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:20:17
    |
 LL | trait Foo where Foo::Assoc: Bar {
-   |                 ^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Foo>::Assoc`
+   |                 ^^^^^^^^^^ help: use the fully-qualified path: `<Self as Foo>::Assoc`
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:25:10
    |
 LL | type X = std::ops::Deref::Target;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Deref>::Target`
+   |          ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: if there were a type named `Example` that implemented `Deref`, you could use the fully-qualified path
+   |
+LL | type X = <Example as Deref>::Target;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:11:23
    |
 LL |     fn grab(&self) -> Grab::Value;
-   |                       ^^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Grab>::Value`
+   |                       ^^^^^^^^^^^ help: use the fully-qualified path: `<Self as Grab>::Value`
 
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:14:22
    |
 LL |     fn get(&self) -> Get::Value;
-   |                      ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as Get>::Value`
+   |                      ^^^^^^^^^^
+   |
+help: if there were a type named `Example` that implemented `Get`, you could use the fully-qualified path
+   |
+LL |     fn get(&self) -> <Example as Get>::Value;
+   |                      ~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 5 previous errors
 
index f1677b822b4c97f7ef3d7340270170cb1c15773b..50fa7d1ac4d43635cdefc031274550538bd3e8c7 100644 (file)
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
 LL |     type Assoc = T;
    |                  ^ the trait `Copy` is not implemented for `T`
    |
+note: required for `<T as Complete>::Assoc` to implement `Partial<T>`
+  --> $DIR/issue-43784-associated-type.rs:1:11
+   |
+LL | pub trait Partial<X: ?Sized>: Copy {
+   |           ^^^^^^^
 note: required by a bound in `Complete::Assoc`
   --> $DIR/issue-43784-associated-type.rs:5:17
    |
diff --git a/tests/ui/attributes/log-backtrace.rs b/tests/ui/attributes/log-backtrace.rs
new file mode 100644 (file)
index 0000000..3979d20
--- /dev/null
@@ -0,0 +1,9 @@
+// run-pass
+//
+// This test makes sure that log-backtrace option doesn't give a compilation error.
+//
+// dont-check-compiler-stdout
+// dont-check-compiler-stderr
+// rustc-env:RUSTC_LOG=info
+// compile-flags: -Zlog-backtrace=rustc_metadata::creader
+fn main() {}
diff --git a/tests/ui/borrowck/issue-92157.rs b/tests/ui/borrowck/issue-92157.rs
new file mode 100644 (file)
index 0000000..6ee2320
--- /dev/null
@@ -0,0 +1,40 @@
+#![feature(no_core)]
+#![feature(lang_items)]
+
+#![no_core]
+
+#[cfg(target_os = "linux")]
+#[link(name = "c")]
+extern {}
+
+#[lang = "start"]
+fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+    //~^ ERROR: incorrect number of parameters for the `start` lang item
+    40+2
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    drop_in_place(to_drop)
+}
+
+#[lang = "add"]
+trait Add<RHS> {
+    type Output;
+    fn add(self, other: RHS) -> Self::Output;
+}
+
+impl Add<isize> for isize {
+    type Output = isize;
+    fn add(self, other: isize) -> isize {
+        self + other
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/issue-92157.stderr b/tests/ui/borrowck/issue-92157.stderr
new file mode 100644 (file)
index 0000000..a4010d7
--- /dev/null
@@ -0,0 +1,11 @@
+error: incorrect number of parameters for the `start` lang item
+  --> $DIR/issue-92157.rs:11:1
+   |
+LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `start` lang item should have four parameters, but found 3
+   = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+
+error: aborting due to previous error
+
index 1aed218aeb473c2bef1345b6e08c827f3502fcef..fbebc80d91ced614a38fe76cf3acc64cf3313e9f 100644 (file)
@@ -2,8 +2,12 @@ fn main() {
     let u = 5 as bool; //~ ERROR cannot cast as `bool`
                        //~| HELP compare with zero instead
                        //~| SUGGESTION 5 != 0
+
     let t = (1 + 2) as bool; //~ ERROR cannot cast as `bool`
                              //~| HELP compare with zero instead
                              //~| SUGGESTION (1 + 2) != 0
-    let v = "hello" as bool; //~ ERROR casting `&'static str` as `bool` is invalid
+
+    let v = "hello" as bool;
+    //~^ ERROR casting `&'static str` as `bool` is invalid
+    //~| HELP consider using the `is_empty` method on `&'static str` to determine if it contains anything
 }
index 15d94ab69d88c707016c314e0286620ff5855a94..19ac8f10fec216abdaf92214f69d3086aeb1791b 100644 (file)
@@ -5,16 +5,21 @@ LL |     let u = 5 as bool;
    |             ^^^^^^^^^ help: compare with zero instead: `5 != 0`
 
 error[E0054]: cannot cast as `bool`
-  --> $DIR/cast-as-bool.rs:5:13
+  --> $DIR/cast-as-bool.rs:6:13
    |
 LL |     let t = (1 + 2) as bool;
    |             ^^^^^^^^^^^^^^^ help: compare with zero instead: `(1 + 2) != 0`
 
 error[E0606]: casting `&'static str` as `bool` is invalid
-  --> $DIR/cast-as-bool.rs:8:13
+  --> $DIR/cast-as-bool.rs:10:13
    |
 LL |     let v = "hello" as bool;
    |             ^^^^^^^^^^^^^^^
+   |
+help: consider using the `is_empty` method on `&'static str` to determine if it contains anything
+   |
+LL |     let v = !"hello".is_empty();
+   |             +       ~~~~~~~~~~~
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/cast/issue-106883-is-empty.rs b/tests/ui/cast/issue-106883-is-empty.rs
new file mode 100644 (file)
index 0000000..27e0816
--- /dev/null
@@ -0,0 +1,27 @@
+use std::ops::Deref;
+
+struct Foo;
+
+impl Deref for Foo {
+    type Target = [u8];
+
+    fn deref(&self) -> &Self::Target {
+        &[]
+    }
+}
+
+fn main() {
+    let _ = "foo" as bool;
+    //~^ ERROR casting `&'static str` as `bool` is invalid [E0606]
+
+    let _ = String::from("foo") as bool;
+    //~^ ERROR non-primitive cast: `String` as `bool` [E0605]
+
+    let _ = Foo as bool;
+    //~^ ERROR non-primitive cast: `Foo` as `bool` [E0605]
+}
+
+fn _slice(bar: &[i32]) -> bool {
+    bar as bool
+    //~^ ERROR casting `&[i32]` as `bool` is invalid [E0606]
+}
diff --git a/tests/ui/cast/issue-106883-is-empty.stderr b/tests/ui/cast/issue-106883-is-empty.stderr
new file mode 100644 (file)
index 0000000..7115c77
--- /dev/null
@@ -0,0 +1,58 @@
+error[E0606]: casting `&'static str` as `bool` is invalid
+  --> $DIR/issue-106883-is-empty.rs:14:13
+   |
+LL |     let _ = "foo" as bool;
+   |             ^^^^^^^^^^^^^
+   |
+help: consider using the `is_empty` method on `&'static str` to determine if it contains anything
+   |
+LL |     let _ = !"foo".is_empty();
+   |             +     ~~~~~~~~~~~
+
+error[E0605]: non-primitive cast: `String` as `bool`
+  --> $DIR/issue-106883-is-empty.rs:17:13
+   |
+LL |     let _ = String::from("foo") as bool;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+   |
+note: this expression `Deref`s to `str` which implements `is_empty`
+  --> $DIR/issue-106883-is-empty.rs:17:13
+   |
+LL |     let _ = String::from("foo") as bool;
+   |             ^^^^^^^^^^^^^^^^^^^
+help: consider using the `is_empty` method on `String` to determine if it contains anything
+   |
+LL |     let _ = !String::from("foo").is_empty();
+   |             +                   ~~~~~~~~~~~
+
+error[E0605]: non-primitive cast: `Foo` as `bool`
+  --> $DIR/issue-106883-is-empty.rs:20:13
+   |
+LL |     let _ = Foo as bool;
+   |             ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+   |
+note: this expression `Deref`s to `[u8]` which implements `is_empty`
+  --> $DIR/issue-106883-is-empty.rs:20:13
+   |
+LL |     let _ = Foo as bool;
+   |             ^^^
+help: consider using the `is_empty` method on `Foo` to determine if it contains anything
+   |
+LL |     let _ = !Foo.is_empty();
+   |             +   ~~~~~~~~~~~
+
+error[E0606]: casting `&[i32]` as `bool` is invalid
+  --> $DIR/issue-106883-is-empty.rs:25:5
+   |
+LL |     bar as bool
+   |     ^^^^^^^^^^^
+   |
+help: consider using the `is_empty` method on `&[i32]` to determine if it contains anything
+   |
+LL |     !bar.is_empty()
+   |     +   ~~~~~~~~~~~
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0605, E0606.
+For more information about an error, try `rustc --explain E0605`.
index 86ce42631b4324110414f06909e70cf62145d9a8..1c69b07e3d4af0859656946d6094f3c2bb07e173 100644 (file)
@@ -2,12 +2,21 @@
 // known-bug
 // unset-rustc-env:RUST_BACKTRACE
 // compile-flags:-Z trait-solver=chalk --edition=2021
-// error-pattern:stack backtrace:
+// error-pattern:internal compiler error
 // failure-status:101
-// normalize-stderr-test "note: .*" -> ""
-// normalize-stderr-test "thread 'rustc' .*" -> ""
-// normalize-stderr-test "  .*\n" -> ""
 // normalize-stderr-test "DefId([^)]*)" -> "..."
+// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
+// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
+// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
+// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
+// normalize-stderr-test "thread.*panicked.*\n" -> ""
+// normalize-stderr-test "stack backtrace:\n" -> ""
+// normalize-stderr-test "\s\d{1,}: .*\n" -> ""
+// normalize-stderr-test "\s at .*\n" -> ""
+// normalize-stderr-test ".*note: Some details.*\n" -> ""
+// normalize-stderr-test "\n\n[ ]*\n" -> ""
+// normalize-stderr-test "compiler/.*: projection" -> "projection"
 
 fn main() -> () {}
 
index 7e2466dece43899fefba5b1f7384bd09ffeb11bb..d1508cb17001b4cf807bc3dcb3a0449f2854dd98 100644 (file)
@@ -1,29 +1,47 @@
-error[E0277]: `[async fn body@$DIR/async.rs:14:29: 16:2]` is not a future
-LL |LL | |LL | | }
-
-
-error[E0277]: the size for values of type `<[async fn body@$DIR/async.rs:14:29: 16:2] as Future>::Output` cannot be known at compilation time
-LL |LL | |LL | | }
-
-
-error[E0277]: `[async fn body@$DIR/async.rs:14:29: 16:2]` is not a future
+error[E0277]: `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
+  --> $DIR/async.rs:23:29
+   |
+LL |   async fn foo(x: u32) -> u32 {
+   |  _____________________________-
+LL | |     x
+LL | | }
+   | | ^
+   | | |
+   | |_`[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
+   |   required by a bound introduced by this call
+   |
+   = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]`
+   = note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited
+note: required by a bound in `identity_future`
+  --> $SRC_DIR/core/src/future/mod.rs:LL:COL
+
+error[E0277]: the size for values of type `<[async fn body@$DIR/async.rs:23:29: 25:2] as Future>::Output` cannot be known at compilation time
+  --> $DIR/async.rs:23:29
+   |
+LL |   async fn foo(x: u32) -> u32 {
+   |  _____________________________^
+LL | |     x
+LL | | }
+   | |_^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `<[async fn body@$DIR/async.rs:23:29: 25:2] as Future>::Output`
+note: required by a bound in `identity_future`
+  --> $SRC_DIR/core/src/future/mod.rs:LL:COL
+
+error[E0277]: `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
+  --> $DIR/async.rs:23:25
+   |
 LL | async fn foo(x: u32) -> u32 {
-
-error: internal compiler error: compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs:1114:25: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:14:29: 16:2]], def_id: ...), _use_mk_alias_ty_instead: () }, Term::Ty(u32)), []), depth=0)`
+   |                         ^^^ `[async fn body@$DIR/async.rs:23:29: 25:2]` is not a future
+   |
+   = help: the trait `Future` is not implemented for `[async fn body@$DIR/async.rs:23:29: 25:2]`
+   = note: [async fn body@$DIR/async.rs:23:29: 25:2] must be a future or must implement `IntoFuture` to be awaited
+
+error: internal compiler error: projection clauses should be implied from elsewhere. obligation: `Obligation(predicate=Binder(ProjectionPredicate(AliasTy { substs: [[async fn body@$DIR/async.rs:23:29: 25:2]], def_id: ...), _use_mk_alias_ty_instead: () }, Term::Ty(u32)), []), depth=0)`
+  --> $DIR/async.rs:23:25
+   |
 LL | async fn foo(x: u32) -> u32 {
-
-
-stack backtrace:
-
-
-
-
-
-
-
-
-
-query stack during panic:
+   |                         ^^^query stack during panic:
 #0 [typeck] type-checking `foo`
 #1 [thir_body] building THIR for `foo`
 #2 [mir_built] building MIR for `foo`
index 59607afec8f8da20f901af644eba78a8afe679c3..1cd8949b8c4b71eddab96dc8cd9e7fd2cf802230 100644 (file)
@@ -6,6 +6,13 @@ LL |         Foo(())
    |         |
    |         arguments to this struct are incorrect
    |
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-84128.rs:13:9
+   |
+LL |         Foo(())
+   |         ^^^^--^
+   |             |
+   |             this argument influences the type of `Foo`
 note: tuple struct defined here
   --> $DIR/issue-84128.rs:5:8
    |
index 72337892734e6af3a29009053ff42133f6f92f51..b492251c01691e85ce617249bb91cf1877509608 100644 (file)
@@ -6,6 +6,13 @@ LL |     Ok(())
    |     |
    |     arguments to this enum variant are incorrect
    |
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-87461.rs:10:5
+   |
+LL |     Ok(())
+   |     ^^^--^
+   |        |
+   |        this argument influences the type of `Ok`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
 
@@ -17,6 +24,13 @@ LL |     Ok(())
    |     |
    |     arguments to this enum variant are incorrect
    |
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-87461.rs:17:5
+   |
+LL |     Ok(())
+   |     ^^^--^
+   |        |
+   |        this argument influences the type of `Ok`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
 
@@ -28,6 +42,13 @@ LL |         Ok(())
    |         |
    |         arguments to this enum variant are incorrect
    |
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-87461.rs:26:9
+   |
+LL |         Ok(())
+   |         ^^^--^
+   |            |
+   |            this argument influences the type of `Ok`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
 
index d080c210e6bd291c7c53467d263d631f0993861d..4c1926387b926a4e843b3e6c5176af7d0b964c95 100644 (file)
@@ -2,10 +2,17 @@
 // run-rustfix
 #![warn(unused_braces)]
 
+macro_rules! make_1 {
+    () => {
+        1
+    }
+}
+
 struct A<const N: usize>;
 
 fn main() {
     let _: A<7>; // ok
     let _: A<7>; //~ WARN unnecessary braces
     let _: A<{ 3 + 5 }>; // ok
+    let _: A<{make_1!()}>; // ok
 }
index 47f0f8c1c96c91ba2d08368fc460b3401703b611..e9f15b401807915c0f85cf7893e8e14d67d60ab0 100644 (file)
@@ -2,10 +2,17 @@
 // run-rustfix
 #![warn(unused_braces)]
 
+macro_rules! make_1 {
+    () => {
+        1
+    }
+}
+
 struct A<const N: usize>;
 
 fn main() {
     let _: A<7>; // ok
     let _: A<{ 7 }>; //~ WARN unnecessary braces
     let _: A<{ 3 + 5 }>; // ok
+    let _: A<{make_1!()}>; // ok
 }
index 553a3a0f88ebae22e415562ff78016bcef43657b..2c8031c430020b8f86e38ab53137ab02c3783e30 100644 (file)
@@ -1,5 +1,5 @@
 warning: unnecessary braces around const expression
-  --> $DIR/unused_braces.rs:9:14
+  --> $DIR/unused_braces.rs:15:14
    |
 LL |     let _: A<{ 7 }>;
    |              ^^ ^^
index 1caf1617e213cb198ad9cbf82e80804013bbd664..08fcd1deab1d337549d3acac3b9050f95792a193 100644 (file)
@@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
    |
 LL |     A = { if let 0 = 0 { todo!() } 0 },
    |           ++           ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL |     A = { let _0 = 0; 0 },
+   |               +
 
 error: aborting due to previous error
 
index f038ba1c8ed859314c4aa4140e4018cce0bba1c7..5d86ca4bfd17b632efd346068e0603a8afe5ae73 100644 (file)
@@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
    |
 LL |     let x: [i32; { if let 0 = 0 { todo!() } 0 }] = [];
    |                    ++           ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL |     let x: [i32; { let _0 = 0; 0 }] = [];
+   |                        +
 
 error: aborting due to previous error
 
index b1921f8a41e48db0560471f059b83b6114ab9ec5..c8f66bb0fc027f2d0a59322a3d75753c56633cc2 100644 (file)
@@ -11,6 +11,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
    |
 LL | const X: i32 = { if let 0 = 0 { todo!() } 0 };
    |                  ++           ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL | const X: i32 = { let _0 = 0; 0 };
+   |                      +
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/const-match-check.rs:8:23
@@ -25,6 +29,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
    |
 LL | static Y: i32 = { if let 0 = 0 { todo!() } 0 };
    |                   ++           ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL | static Y: i32 = { let _0 = 0; 0 };
+   |                       +
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/const-match-check.rs:13:26
@@ -39,6 +47,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
    |
 LL |     const X: i32 = { if let 0 = 0 { todo!() } 0 };
    |                      ++           ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL |     const X: i32 = { let _0 = 0; 0 };
+   |                          +
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/const-match-check.rs:19:26
@@ -53,6 +65,10 @@ help: you might want to use `if let` to ignore the variants that aren't matched
    |
 LL |     const X: i32 = { if let 0 = 0 { todo!() } 0 };
    |                      ++           ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL |     const X: i32 = { let _0 = 0; 0 };
+   |                          +
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/dep-graph/dep-graph-dump.rs b/tests/ui/dep-graph/dep-graph-dump.rs
new file mode 100644 (file)
index 0000000..cbc4def
--- /dev/null
@@ -0,0 +1,6 @@
+// Test dump-dep-graph requires query-dep-graph enabled
+
+// incremental
+// compile-flags: -Z dump-dep-graph
+
+fn main() {}
diff --git a/tests/ui/dep-graph/dep-graph-dump.stderr b/tests/ui/dep-graph/dep-graph-dump.stderr
new file mode 100644 (file)
index 0000000..ea44b8b
--- /dev/null
@@ -0,0 +1,2 @@
+error: can't dump dependency graph without `-Z query-dep-graph`
+
index bf0bb3fbdf8f7f26a6a920f8f5be9cfe30b59a06..af03f0e5e5f430ca1bbefa70b91c941ee1038600 100644 (file)
@@ -6,12 +6,15 @@ LL | struct Value(u32);
    | |
    | doesn't satisfy `Value: Eq`
    | doesn't satisfy `Value: Hash`
+   | doesn't satisfy `Value: PartialEq`
 ...
 LL |     hs.insert(Value(0));
    |        ^^^^^^
    |
    = note: the following trait bounds were not satisfied:
            `Value: Eq`
+           `Value: PartialEq`
+           which is required by `Value: Eq`
            `Value: Hash`
 help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]`
    |
@@ -22,7 +25,10 @@ error[E0599]: the method `use_eq` exists for struct `Object<NoDerives>`, but its
   --> $DIR/issue-91550.rs:26:9
    |
 LL | pub struct NoDerives;
-   | -------------------- doesn't satisfy `NoDerives: Eq`
+   | --------------------
+   | |
+   | doesn't satisfy `NoDerives: Eq`
+   | doesn't satisfy `NoDerives: PartialEq`
 LL |
 LL | struct Object<T>(T);
    | ---------------- method `use_eq` not found for this struct
@@ -37,6 +43,9 @@ LL | impl<T: Eq> Object<T> {
    |         ^^  ---------
    |         |
    |         unsatisfied trait bound introduced here
+   = note: the following trait bounds were not satisfied:
+           `NoDerives: PartialEq`
+           which is required by `NoDerives: Eq`
 help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]`
    |
 LL | #[derive(Eq, PartialEq)]
@@ -46,7 +55,12 @@ error[E0599]: the method `use_ord` exists for struct `Object<NoDerives>`, but it
   --> $DIR/issue-91550.rs:27:9
    |
 LL | pub struct NoDerives;
-   | -------------------- doesn't satisfy `NoDerives: Ord`
+   | --------------------
+   | |
+   | doesn't satisfy `NoDerives: Eq`
+   | doesn't satisfy `NoDerives: Ord`
+   | doesn't satisfy `NoDerives: PartialEq`
+   | doesn't satisfy `NoDerives: PartialOrd`
 LL |
 LL | struct Object<T>(T);
    | ---------------- method `use_ord` not found for this struct
@@ -61,6 +75,13 @@ LL | impl<T: Ord> Object<T> {
    |         ^^^  ---------
    |         |
    |         unsatisfied trait bound introduced here
+   = note: the following trait bounds were not satisfied:
+           `NoDerives: PartialOrd`
+           which is required by `NoDerives: Ord`
+           `NoDerives: PartialEq`
+           which is required by `NoDerives: Ord`
+           `NoDerives: Eq`
+           which is required by `NoDerives: Ord`
 help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
    |
 LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
@@ -72,7 +93,9 @@ error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object<NoD
 LL | pub struct NoDerives;
    | --------------------
    | |
+   | doesn't satisfy `NoDerives: Eq`
    | doesn't satisfy `NoDerives: Ord`
+   | doesn't satisfy `NoDerives: PartialEq`
    | doesn't satisfy `NoDerives: PartialOrd`
 LL |
 LL | struct Object<T>(T);
@@ -91,6 +114,13 @@ LL | impl<T: Ord + PartialOrd> Object<T> {
    |         |     |
    |         |     unsatisfied trait bound introduced here
    |         unsatisfied trait bound introduced here
+   = note: the following trait bounds were not satisfied:
+           `NoDerives: PartialEq`
+           which is required by `NoDerives: Ord`
+           `NoDerives: Eq`
+           which is required by `NoDerives: Ord`
+           `NoDerives: PartialEq`
+           which is required by `NoDerives: PartialOrd`
 help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
    |
 LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
index 21f957ab549a3832f1769c824d27a21992ae9d88..55096e95df7e06cee280a39f5f477cf81a108c06 100644 (file)
@@ -61,25 +61,45 @@ error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:1:10
    |
 LL | type A = [u8; 4]::AssocTy;
-   |          ^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<[u8; 4] as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `[u8; 4]`, you could use the fully-qualified path
+   |
+LL | type A = <[u8; 4] as Example>::AssocTy;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:5:10
    |
 LL | type B = [u8]::AssocTy;
-   |          ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<[u8] as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `[u8]`, you could use the fully-qualified path
+   |
+LL | type B = <[u8] as Example>::AssocTy;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:9:10
    |
 LL | type C = (u8)::AssocTy;
-   |          ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path
+   |
+LL | type C = <u8 as Example>::AssocTy;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:13:10
    |
 LL | type D = (u8, u8)::AssocTy;
-   |          ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(u8, u8) as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `(u8, u8)`, you could use the fully-qualified path
+   |
+LL | type D = <(u8, u8) as Example>::AssocTy;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases
   --> $DIR/bad-assoc-ty.rs:17:10
@@ -91,13 +111,23 @@ error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:21:19
    |
 LL | type F = &'static (u8)::AssocTy;
-   |                   ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
+   |                   ^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path
+   |
+LL | type F = &'static <u8 as Example>::AssocTy;
+   |                   ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:27:10
    |
 LL | type G = dyn 'static + (Send)::AssocTy;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Send + 'static) as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `(dyn Send + 'static)`, you could use the fully-qualified path
+   |
+LL | type G = <(dyn Send + 'static) as Example>::AssocTy;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 warning: trait objects without an explicit `dyn` are deprecated
   --> $DIR/bad-assoc-ty.rs:33:10
@@ -117,24 +147,33 @@ error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:33:10
    |
 LL | type H = Fn(u8) -> (u8)::Output;
-   |          ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as Trait>::Output`
+   |          ^^^^^^^^^^^^^^^^^^^^^^ help: use the fully-qualified path: `<(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output`
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:39:19
    |
 LL |     ($ty: ty) => ($ty::AssocTy);
-   |                   ^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
+   |                   ^^^^^^^^^^^^
 ...
 LL | type J = ty!(u8);
    |          ------- in this macro invocation
    |
    = note: this error originates in the macro `ty` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path
+   |
+LL |     ($ty: ty) => (<u8 as Example>::AssocTy);
+   |                   ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:46:10
    |
 LL | type I = ty!()::AssocTy;
-   |          ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
+   |          ^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `AssocTy` implemented for `u8`, you could use the fully-qualified path
+   |
+LL | type I = <u8 as Example>::AssocTy;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/bad-assoc-ty.rs:51:13
index 6031b682d72a035c0310670fc662ede4bcd1fc88..2fe252de256650cf5b67b00bd1e0a28c7557572d 100644 (file)
@@ -1,4 +1,8 @@
 trait MyTrait { type X; }
+struct MyStruct;
+impl MyTrait for MyStruct {
+    type X = ();
+}
 
 fn main() {
     let foo: MyTrait::X;
index 726f39e11f1341384a03d7a618030d3e2c86bae0..42945e42f6ea1c682884a60c3e92c671964a0dcc 100644 (file)
@@ -1,8 +1,8 @@
 error[E0223]: ambiguous associated type
-  --> $DIR/E0223.rs:4:14
+  --> $DIR/E0223.rs:8:14
    |
 LL |     let foo: MyTrait::X;
-   |              ^^^^^^^^^^ help: use fully-qualified syntax: `<Type as MyTrait>::X`
+   |              ^^^^^^^^^^ help: use the fully-qualified path: `<MyStruct as MyTrait>::X`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/errors/auxiliary/remapped_dep.rs b/tests/ui/errors/auxiliary/remapped_dep.rs
new file mode 100644 (file)
index 0000000..ef26f1c
--- /dev/null
@@ -0,0 +1,3 @@
+// compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux
+
+pub struct SomeStruct {} // This line should be show as part of the error.
diff --git a/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr
new file mode 100644 (file)
index 0000000..2584e3e
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0423]: expected value, found struct `remapped_dep::SomeStruct`
+  --> $DIR/remap-path-prefix-reverse.rs:22:13
+   |
+LL |     let _ = remapped_dep::SomeStruct;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}`
+   |
+  ::: remapped-aux/remapped_dep.rs:3:1
+   |
+LL | pub struct SomeStruct {} // This line should be show as part of the error.
+   | --------------------- `remapped_dep::SomeStruct` defined here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0423`.
diff --git a/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr
new file mode 100644 (file)
index 0000000..e710183
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0423]: expected value, found struct `remapped_dep::SomeStruct`
+  --> remapped/errors/remap-path-prefix-reverse.rs:22:13
+   |
+LL |     let _ = remapped_dep::SomeStruct;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}`
+   |
+  ::: remapped-aux/remapped_dep.rs:3:1
+   |
+LL | pub struct SomeStruct {} // This line should be show as part of the error.
+   | --------------------- `remapped_dep::SomeStruct` defined here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0423`.
diff --git a/tests/ui/errors/remap-path-prefix-reverse.rs b/tests/ui/errors/remap-path-prefix-reverse.rs
new file mode 100644 (file)
index 0000000..635c416
--- /dev/null
@@ -0,0 +1,23 @@
+// aux-build:remapped_dep.rs
+// compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux
+
+// The remapped paths are not normalized by compiletest.
+// normalize-stderr-test: "\\(errors)" -> "/$1"
+
+// revisions: local-self remapped-self
+// [remapped-self]compile-flags: --remap-path-prefix={{src-base}}=remapped
+
+// The paths from `remapped-self` aren't recognized by compiletest, so we
+// cannot use line-specific patterns for the actual error.
+// error-pattern: E0423
+
+// Verify that the expected source code is shown.
+// error-pattern: pub struct SomeStruct {} // This line should be show
+
+extern crate remapped_dep;
+
+fn main() {
+    // The actual error is irrelevant. The important part it that is should show
+    // a snippet of the dependency's source.
+    let _ = remapped_dep::SomeStruct;
+}
diff --git a/tests/ui/errors/remap-path-prefix.rs b/tests/ui/errors/remap-path-prefix.rs
new file mode 100644 (file)
index 0000000..29b9c7b
--- /dev/null
@@ -0,0 +1,16 @@
+// compile-flags: --remap-path-prefix={{src-base}}=remapped
+
+// The remapped paths are not normalized by compiletest.
+// normalize-stderr-test: "\\(errors)" -> "/$1"
+
+// The remapped paths aren't recognized by compiletest, so we
+// cannot use line-specific patterns.
+// error-pattern: E0425
+
+fn main() {
+    // We cannot actually put an ERROR marker here because
+    // the file name in the error message is not what the
+    // test framework expects (since the filename gets remapped).
+    // We still test the expected error in the stderr file.
+    ferris
+}
diff --git a/tests/ui/errors/remap-path-prefix.stderr b/tests/ui/errors/remap-path-prefix.stderr
new file mode 100644 (file)
index 0000000..2f42128
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `ferris` in this scope
+  --> remapped/errors/remap-path-prefix.rs:15:5
+   |
+LL |     ferris
+   |     ^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
index 623adb1c2ad1ecb832616ad35bd3a91a19bacfa9..e5638d90ee8e7a90b7ece6292c4b5627bf1d9a7d 100644 (file)
@@ -17,6 +17,7 @@ LL |     type Copy<T>: Copy = Box<T>;
    |                          ^^^^^^ the trait `Clone` is not implemented for `T`
    |
    = note: required for `Box<T>` to implement `Clone`
+   = note: required for `<Self as UnsafeCopy>::Copy<T>` to implement `Copy`
 note: required by a bound in `UnsafeCopy::Copy`
   --> $DIR/issue-74824.rs:6:19
    |
index c913483a8747c15ef849f859570306d64a177578..9f669b9a5214b1694bb3c42331ca48480826526f 100644 (file)
@@ -23,6 +23,13 @@ LL |         A(self.0 + rhs.0)
    |
    = note: expected type parameter `B`
              found associated type `<B as Add>::Output`
+help: the type constructed contains `<B as Add>::Output` due to the type of the argument passed
+  --> $DIR/missing-bounds.rs:11:9
+   |
+LL |         A(self.0 + rhs.0)
+   |         ^^--------------^
+   |           |
+   |           this argument influences the type of `A`
 note: tuple struct defined here
   --> $DIR/missing-bounds.rs:5:8
    |
diff --git a/tests/ui/generics/issue-106694.rs b/tests/ui/generics/issue-106694.rs
new file mode 100644 (file)
index 0000000..c4b02ee
--- /dev/null
@@ -0,0 +1,24 @@
+trait Trait {}
+
+fn foo(_: impl &Trait) {}
+//~^ ERROR expected a trait, found type
+
+fn bar<T: &Trait>(_: T) {}
+//~^ ERROR expected a trait, found type
+
+fn partially_correct_impl(_: impl &*const &Trait + Copy) {}
+//~^ ERROR expected a trait, found type
+
+fn foo_bad(_: impl &BadTrait) {}
+//~^ ERROR expected a trait, found type
+//~^^ ERROR cannot find trait `BadTrait` in this scope
+
+fn bar_bad<T: &BadTrait>(_: T) {}
+//~^ ERROR expected a trait, found type
+//~^^ ERROR cannot find trait `BadTrait` in this scope
+
+fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {}
+//~^ ERROR expected a trait, found type
+//~^^ ERROR cannot find trait `BadTrait` in this scope
+
+fn main() {}
diff --git a/tests/ui/generics/issue-106694.stderr b/tests/ui/generics/issue-106694.stderr
new file mode 100644 (file)
index 0000000..235b898
--- /dev/null
@@ -0,0 +1,93 @@
+error: expected a trait, found type
+  --> $DIR/issue-106694.rs:3:16
+   |
+LL | fn foo(_: impl &Trait) {}
+   |                ^^^^^^
+   |
+help: consider removing the indirection
+   |
+LL - fn foo(_: impl &Trait) {}
+LL + fn foo(_: impl Trait) {}
+   |
+
+error: expected a trait, found type
+  --> $DIR/issue-106694.rs:6:11
+   |
+LL | fn bar<T: &Trait>(_: T) {}
+   |           ^^^^^^
+   |
+help: consider removing the indirection
+   |
+LL - fn bar<T: &Trait>(_: T) {}
+LL + fn bar<T: Trait>(_: T) {}
+   |
+
+error: expected a trait, found type
+  --> $DIR/issue-106694.rs:9:35
+   |
+LL | fn partially_correct_impl(_: impl &*const &Trait + Copy) {}
+   |                                   ^^^^^^^^^^^^^^
+   |
+help: consider removing the indirection
+   |
+LL - fn partially_correct_impl(_: impl &*const &Trait + Copy) {}
+LL + fn partially_correct_impl(_: impl Trait + Copy) {}
+   |
+
+error: expected a trait, found type
+  --> $DIR/issue-106694.rs:12:20
+   |
+LL | fn foo_bad(_: impl &BadTrait) {}
+   |                    ^^^^^^^^^
+   |
+help: consider removing the indirection
+   |
+LL - fn foo_bad(_: impl &BadTrait) {}
+LL + fn foo_bad(_: impl BadTrait) {}
+   |
+
+error: expected a trait, found type
+  --> $DIR/issue-106694.rs:16:15
+   |
+LL | fn bar_bad<T: &BadTrait>(_: T) {}
+   |               ^^^^^^^^^
+   |
+help: consider removing the indirection
+   |
+LL - fn bar_bad<T: &BadTrait>(_: T) {}
+LL + fn bar_bad<T: BadTrait>(_: T) {}
+   |
+
+error: expected a trait, found type
+  --> $DIR/issue-106694.rs:20:39
+   |
+LL | fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {}
+   |                                       ^^^^^^^^^^^^^^^^^
+   |
+help: consider removing the indirection
+   |
+LL - fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {}
+LL + fn partially_correct_impl_bad(_: impl BadTrait + Copy) {}
+   |
+
+error[E0405]: cannot find trait `BadTrait` in this scope
+  --> $DIR/issue-106694.rs:12:21
+   |
+LL | fn foo_bad(_: impl &BadTrait) {}
+   |                     ^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `BadTrait` in this scope
+  --> $DIR/issue-106694.rs:16:16
+   |
+LL | fn bar_bad<T: &BadTrait>(_: T) {}
+   |                ^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `BadTrait` in this scope
+  --> $DIR/issue-106694.rs:20:48
+   |
+LL | fn partially_correct_impl_bad(_: impl &*const &BadTrait + Copy) {}
+   |                                                ^^^^^^^^ not found in this scope
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0405`.
diff --git a/tests/ui/higher-rank-trait-bounds/issue-42114.rs b/tests/ui/higher-rank-trait-bounds/issue-42114.rs
new file mode 100644 (file)
index 0000000..01515fd
--- /dev/null
@@ -0,0 +1,20 @@
+// check-pass
+
+fn lifetime<'a>()
+where
+    &'a (): 'a,
+{
+    /* do nothing */
+}
+
+fn doesnt_work()
+where
+    for<'a> &'a (): 'a,
+{
+    /* do nothing */
+}
+
+fn main() {
+    lifetime();
+    doesnt_work();
+}
index fd0986d7c0a9dd9a525f9c142ec85f88c82d009c..b3ff2ce5a7bfada2b3b20cdadd9dd86f013a2729 100644 (file)
@@ -11,7 +11,7 @@ fn path_parametrized_type_is_allowed() -> option::Option<impl Debug> {
 
 fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
 //~^ ERROR `impl Trait` is not allowed in path parameters
-//~^^ ERROR ambiguous associated type
+//~| ERROR `impl Trait` is not allowed in path parameters
     x.next().unwrap()
 }
 
index 82d2422c40779a49c89569243328a8cd29c42f92..4deb24731bc030b12c8ca24dc088ee11b3c13297 100644 (file)
@@ -22,13 +22,12 @@ error[E0667]: `impl Trait` is not allowed in path parameters
 LL |     -> <dyn Iterator<Item = impl Debug> as Iterator>::Item
    |                             ^^^^^^^^^^
 
-error[E0223]: ambiguous associated type
-  --> $DIR/impl_trait_projections.rs:12:50
+error[E0667]: `impl Trait` is not allowed in path parameters
+  --> $DIR/impl_trait_projections.rs:12:51
    |
 LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
-   |                                                  ^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<impl Iterator as Trait>::Item`
+   |                                                   ^^^^^^^^^^^^^
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0223, E0667.
-For more information about an error, try `rustc --explain E0223`.
+For more information about this error, try `rustc --explain E0667`.
index 0ac31c642eb12ecc27853ad4ffd1041c8618b27b..ebe07027d2fa1ba036fd2a950a02b388863f6699 100644 (file)
@@ -1,8 +1,8 @@
 error: impl method assumes more implied bounds than the corresponding trait method
-  --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:5
+  --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31
    |
 LL |     fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `()`
    |
    = 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 #105572 <https://github.com/rust-lang/rust/issues/105572>
@@ -14,3 +14,18 @@ LL | #![deny(implied_bounds_entailment)]
 
 error: aborting due to previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: impl method assumes more implied bounds than the corresponding trait method
+  --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31
+   |
+LL |     fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `()`
+   |
+   = 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 #105572 <https://github.com/rust-lang/rust/issues/105572>
+note: the lint level is defined here
+  --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:1:9
+   |
+LL | #![deny(implied_bounds_entailment)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
index 0dfa8167a99661d792c30da429d7d18a7c8d83fb..43d3e058ffeb3f10adc89c2b7a1968f9b781aff1 100644 (file)
@@ -1,8 +1,8 @@
 error: impl method assumes more implied bounds than the corresponding trait method
-  --> $DIR/impl-implied-bounds-compatibility.rs:14:5
+  --> $DIR/impl-implied-bounds-compatibility.rs:14:35
    |
 LL |     fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `&'b MessageListeners<'b>`
    |
    = 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 #105572 <https://github.com/rust-lang/rust/issues/105572>
@@ -14,3 +14,18 @@ LL | #![deny(implied_bounds_entailment)]
 
 error: aborting due to previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: impl method assumes more implied bounds than the corresponding trait method
+  --> $DIR/impl-implied-bounds-compatibility.rs:14:35
+   |
+LL |     fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `&'b MessageListeners<'b>`
+   |
+   = 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 #105572 <https://github.com/rust-lang/rust/issues/105572>
+note: the lint level is defined here
+  --> $DIR/impl-implied-bounds-compatibility.rs:1:9
+   |
+LL | #![deny(implied_bounds_entailment)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
index 2a56aaa44fef23b3ae435b47451aa9e7986f4769..888c321bc479b8269d1c87b8a22fa8ca7a6be61f 100644 (file)
@@ -1,8 +1,6 @@
 error[E0282]: type annotations needed
   --> $DIR/cannot-infer-partial-try-return.rs:20:9
    |
-LL |         infallible()?;
-   |         ------------- type must be known at this point
 LL |         Ok(())
    |         ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
    |
index 9b822714f828a71a446fb169782482e6a0deb58c..a9cb7e5257c83d1db6c8fa8df7e3a1fed7811586 100644 (file)
@@ -1,8 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/question-mark-type-infer.rs:10:30
+  --> $DIR/question-mark-type-infer.rs:10:21
    |
 LL |     l.iter().map(f).collect()?
-   |                              ^ cannot infer type
+   |                     ^^^^^^^ cannot infer type of the type parameter `B` declared on the associated function `collect`
+   |
+help: consider specifying the generic argument
+   |
+LL |     l.iter().map(f).collect::<Vec<_>>()?
+   |                            ++++++++++
 
 error: aborting due to previous error
 
index 3a10a1ab11ac5d5addac61f5f67bc4305fc8703a..3a9f49ef167d692d6fe7feed84623e5c1b3a8f9e 100644 (file)
@@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type
   --> $DIR/issue-23073.rs:6:17
    |
 LL |     type FooT = <<Self as Bar>::Foo>::T;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<Self as Bar>::Foo as Trait>::T`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `T` implemented for `<Self as Bar>::Foo`, you could use the fully-qualified path
+   |
+LL |     type FooT = <<Self as Bar>::Foo as Example>::T;
+   |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
index 9d11cf19ea77c41a2f65c2c1f18e5aea41ed7f66..fc343bb54aace29f40aa5fd3cd5e87a2497de3e3 100644 (file)
@@ -1,14 +1,16 @@
-error[E0282]: type annotations needed
-  --> $DIR/issue-69455.rs:29:20
+error[E0284]: type annotations needed
+  --> $DIR/issue-69455.rs:29:41
    |
 LL |     println!("{}", 23u64.test(xs.iter().sum()));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `new_display`
+   |                          ----           ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
+   |                          |
+   |                          type must be known at this point
    |
-   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: cannot satisfy `<u64 as Test<_>>::Output == _`
 help: consider specifying the generic argument
    |
-LL |     println!("{}", 23u64.test(xs.iter().sum())::<T>);
-   |                                               +++++
+LL |     println!("{}", 23u64.test(xs.iter().sum::<S>()));
+   |                                            +++++
 
 error[E0283]: type annotations needed
   --> $DIR/issue-69455.rs:29:41
@@ -33,5 +35,5 @@ LL |     println!("{}", 23u64.test(xs.iter().sum::<S>()));
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0282, E0283.
-For more information about an error, try `rustc --explain E0282`.
+Some errors have detailed explanations: E0283, E0284.
+For more information about an error, try `rustc --explain E0283`.
index f7d44f21d3becb7e600b88d45d82a529a1dc47da..70daf8a2f1a6475b2ed53dbaf7fba87283829b8d 100644 (file)
@@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type
   --> $DIR/issue-78622.rs:5:5
    |
 LL |     S::A::<f> {}
-   |     ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+   |     ^^^^
+   |
+help: if there were a trait named `Example` with associated type `A` implemented for `S`, you could use the fully-qualified path
+   |
+LL |     <S as Example>::A::<f> {}
+   |     ~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
index 8ed303ca6069c108049f12d0407d4ca87e6c3c54..a19f4963c239bc6ef90f601ee534cf35ed31ef8b 100644 (file)
@@ -16,7 +16,7 @@ error[E0223]: ambiguous associated type
   --> $DIR/bare-trait-objects-path.rs:23:12
    |
 LL |     let _: Dyn::Ty;
-   |            ^^^^^^^ help: use fully-qualified syntax: `<dyn Dyn as Trait>::Ty`
+   |            ^^^^^^^ help: use the fully-qualified path: `<dyn Dyn as Assoc>::Ty`
 
 warning: trait objects without an explicit `dyn` are deprecated
   --> $DIR/bare-trait-objects-path.rs:14:5
index 1a88d985dd86a6438bf0b6847895a8255c24d5fa..e691fb37e6c43e51341367474a4fe12ac274edd0 100644 (file)
@@ -50,4 +50,8 @@ fn main() {
     if { return } {
 
     }
+
+    // regression test for https://github.com/rust-lang/rust/issues/106899
+    return println!("!");
+    //~^ WARN unnecessary braces
 }
index 5ca4811fc32d8342f523d5af85ea902dcf852510..0d260d2cbc93f5d82dcc96f0c1fee67871bbf273 100644 (file)
@@ -50,4 +50,8 @@ fn main() {
     if { return } {
 
     }
+
+    // regression test for https://github.com/rust-lang/rust/issues/106899
+    return { println!("!") };
+    //~^ WARN unnecessary braces
 }
index 7773f44ea2d38c0860855afe26fd1cc50f0643a8..0b4a1c321805ddea51a8b4261d5794fd89b38efc 100644 (file)
@@ -68,5 +68,17 @@ LL -     consume({ 7 });
 LL +     consume(7);
    |
 
-warning: 5 warnings emitted
+warning: unnecessary braces around `return` value
+  --> $DIR/unused_braces.rs:55:12
+   |
+LL |     return { println!("!") };
+   |            ^^             ^^
+   |
+help: remove these braces
+   |
+LL -     return { println!("!") };
+LL +     return println!("!");
+   |
+
+warning: 6 warnings emitted
 
index 680aff1726f9f905e056c800fad7a27206bfa5f5..de4e067fead4cce20007ef8415535eb42c1dba5d 100644 (file)
@@ -11,6 +11,13 @@ LL |         Some(true)
    |
    = note: expected type parameter `bool` (type parameter `bool`)
                         found type `bool` (`bool`)
+help: the type constructed contains `bool` due to the type of the argument passed
+  --> $DIR/issue-35030.rs:9:9
+   |
+LL |         Some(true)
+   |         ^^^^^----^
+   |              |
+   |              this argument influences the type of `Some`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
index a2201b946a6f0d5352c8db71b2e1e8f9972f7b62..05d3de80d8449b4b8e7da07684b29174989854a5 100644 (file)
@@ -6,6 +6,8 @@ LL |     this.is_subset(other)
    |
    = note: the following trait bounds were not satisfied:
            `T: Eq`
+           `T: PartialEq`
+           which is required by `T: Eq`
            `T: Hash`
 help: consider restricting the type parameters to satisfy the trait bounds
    |
index 8a16d7f955129811997464d47c4e10238db77340..0e8b0a5da220569b607fe3512ae59ee94e3fcf1b 100644 (file)
Binary files a/tests/ui/parser/issues/issue-66473.stderr and b/tests/ui/parser/issues/issue-66473.stderr differ
index b2c7dddc8011c21e1f3d21185bc48a97dbadf79c..43a903e6c4698e59840cdf18f73ed830c8b50c32 100644 (file)
Binary files a/tests/ui/parser/issues/issue-68629.stderr and b/tests/ui/parser/issues/issue-68629.stderr differ
index 6585a19d954efd39c15e3d7bd77ecb26e9796ae8..5bca5bbebeacb44984c8679e4d2c4757be4ee742 100644 (file)
Binary files a/tests/ui/parser/issues/issue-68730.stderr and b/tests/ui/parser/issues/issue-68730.stderr differ
index 89ae85ec990279bf489b4ab36471737e178e7972..f0122561f463d9b70375d696ae3cae8178e848bb 100644 (file)
@@ -2,4 +2,8 @@ fn main() {
     let y = 0;
     //~^ ERROR unknown start of token: \u{37e}
     //~^^ HELP Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), but it is not
+        let x = 0;
+    //~^ ERROR unknown start of token: \u{a0}
+    //~^^ NOTE character appears 3 more times
+    //~^^^ HELP Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not
 }
index 0cfe9240e8514e65fb7ec186ff97069965c87581..b1d4a0af7115493e4cb1d28e5cdc6b732dac4beb 100644 (file)
@@ -9,5 +9,17 @@ help: Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), b
 LL |     let y = 0;
    |              ~
 
-error: aborting due to previous error
+error: unknown start of token: \u{a0}
+  --> $DIR/unicode-chars.rs:5:5
+   |
+LL |         let x = 0;
+   |     ^^^^
+   |
+   = note: character appears 3 more times
+help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not
+   |
+LL |         let x = 0;
+   |     ++++
+
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/pattern/issue-106552.rs b/tests/ui/pattern/issue-106552.rs
new file mode 100644 (file)
index 0000000..aa2c141
--- /dev/null
@@ -0,0 +1,7 @@
+fn main() {
+    let 5 = 6;
+    //~^ error refutable pattern in local binding [E0005]
+
+    let x @ 5 = 6;
+    //~^ error refutable pattern in local binding [E0005]
+}
diff --git a/tests/ui/pattern/issue-106552.stderr b/tests/ui/pattern/issue-106552.stderr
new file mode 100644 (file)
index 0000000..ed5d40c
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0005]: refutable pattern in local binding
+  --> $DIR/issue-106552.rs:2:9
+   |
+LL |     let 5 = 6;
+   |         ^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+   = note: the matched value is of type `i32`
+help: you might want to use `if let` to ignore the variants that aren't matched
+   |
+LL |     if let 5 = 6 { todo!() }
+   |     ++           ~~~~~~~~~~~
+help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+   |
+LL |     let _5 = 6;
+   |         +
+
+error[E0005]: refutable pattern in local binding
+  --> $DIR/issue-106552.rs:5:9
+   |
+LL |     let x @ 5 = 6;
+   |         ^^^^^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+   = note: the matched value is of type `i32`
+help: you might want to use `let else` to handle the variants that aren't matched
+   |
+LL |     let x @ 5 = 6 else { todo!() };
+   |                   ++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0005`.
diff --git a/tests/ui/proc-macro/panic-abort.rs b/tests/ui/proc-macro/panic-abort.rs
new file mode 100644 (file)
index 0000000..ad312a8
--- /dev/null
@@ -0,0 +1,4 @@
+// error-pattern: building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
+// compile-flags: --crate-type proc-macro -Cpanic=abort
+// force-host
+// check-pass
diff --git a/tests/ui/proc-macro/panic-abort.stderr b/tests/ui/proc-macro/panic-abort.stderr
new file mode 100644 (file)
index 0000000..a6e1861
--- /dev/null
@@ -0,0 +1,4 @@
+warning: building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/proc-macro/pretty-print-hack-show.local.stderr b/tests/ui/proc-macro/pretty-print-hack-show.local.stderr
new file mode 100644 (file)
index 0000000..8730549
--- /dev/null
@@ -0,0 +1,179 @@
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: aborting due to 8 previous errors
+
+Future incompatibility report: Future breakage diagnostic:
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
diff --git a/tests/ui/proc-macro/pretty-print-hack-show.local.stdout b/tests/ui/proc-macro/pretty-print-hack-show.local.stdout
new file mode 100644 (file)
index 0000000..3d793d2
--- /dev/null
@@ -0,0 +1,44 @@
+PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, }
+PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "enum",
+        span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:1: 4:5 (#0),
+    },
+    Ident {
+        ident: "ProceduralMasqueradeDummyType",
+        span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6: 4:35 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Ident {
+                ident: "Input",
+                span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:13:5: 13:10 (#0),
+            },
+        ],
+        span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:36: 14:2 (#0),
+    },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, }
+PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "enum",
+        span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:1: 4:5 (#0),
+    },
+    Ident {
+        ident: "ProceduralMasqueradeDummyType",
+        span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6: 4:35 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Ident {
+                ident: "Input",
+                span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:13:5: 13:10 (#0),
+            },
+        ],
+        span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:36: 14:2 (#0),
+    },
+]
diff --git a/tests/ui/proc-macro/pretty-print-hack-show.remapped.stderr b/tests/ui/proc-macro/pretty-print-hack-show.remapped.stderr
new file mode 100644 (file)
index 0000000..ab50138
--- /dev/null
@@ -0,0 +1,179 @@
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+
+error: aborting due to 8 previous errors
+
+Future incompatibility report: Future breakage diagnostic:
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
+Future breakage diagnostic:
+error: using an old version of `rental`
+  --> remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
+   = note: `#[deny(proc_macro_back_compat)]` on by default
+
diff --git a/tests/ui/proc-macro/pretty-print-hack-show.remapped.stdout b/tests/ui/proc-macro/pretty-print-hack-show.remapped.stdout
new file mode 100644 (file)
index 0000000..61ca53b
--- /dev/null
@@ -0,0 +1,44 @@
+PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, }
+PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "enum",
+        span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:1: 4:5 (#0),
+    },
+    Ident {
+        ident: "ProceduralMasqueradeDummyType",
+        span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6: 4:35 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Ident {
+                ident: "Input",
+                span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:13:5: 13:10 (#0),
+            },
+        ],
+        span: remapped/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:36: 14:2 (#0),
+    },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, }
+PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "enum",
+        span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:1: 4:5 (#0),
+    },
+    Ident {
+        ident: "ProceduralMasqueradeDummyType",
+        span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6: 4:35 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Ident {
+                ident: "Input",
+                span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:13:5: 13:10 (#0),
+            },
+        ],
+        span: remapped/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs:4:36: 14:2 (#0),
+    },
+]
index 9b1899e49220e16818f800e0f48008ed9872d3bf..e9ff66ba45a08194678ad1ddb7f8135952dd4cfa 100644 (file)
@@ -1,5 +1,11 @@
 // aux-build:test-macros.rs
 // compile-flags: -Z span-debug
+// revisions: local remapped
+// [remapped]compile-flags: --remap-path-prefix={{src-base}}=remapped
+
+// The remapped paths are not normalized by compiletest.
+// normalize-stdout-test: "\\(proc-macro|pretty-print-hack)" -> "/$1"
+// normalize-stderr-test: "\\(proc-macro|pretty-print-hack)" -> "/$1"
 
 #![no_std] // Don't load unnecessary hygiene information from std
 extern crate std;
diff --git a/tests/ui/proc-macro/pretty-print-hack-show.stderr b/tests/ui/proc-macro/pretty-print-hack-show.stderr
deleted file mode 100644 (file)
index 8730549..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-   = note: `#[deny(proc_macro_back_compat)]` on by default
-
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-
-error: aborting due to 8 previous errors
-
-Future incompatibility report: Future breakage diagnostic:
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-   = note: `#[deny(proc_macro_back_compat)]` on by default
-
-Future breakage diagnostic:
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-   = note: `#[deny(proc_macro_back_compat)]` on by default
-
-Future breakage diagnostic:
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-   = note: `#[deny(proc_macro_back_compat)]` on by default
-
-Future breakage diagnostic:
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-   = note: `#[deny(proc_macro_back_compat)]` on by default
-
-Future breakage diagnostic:
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-   = note: `#[deny(proc_macro_back_compat)]` on by default
-
-Future breakage diagnostic:
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-   = note: `#[deny(proc_macro_back_compat)]` on by default
-
-Future breakage diagnostic:
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-   = note: `#[deny(proc_macro_back_compat)]` on by default
-
-Future breakage diagnostic:
-error: using an old version of `rental`
-  --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6
-   |
-LL | enum ProceduralMasqueradeDummyType {
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
-   = note: `#[deny(proc_macro_back_compat)]` on by default
-
diff --git a/tests/ui/proc-macro/pretty-print-hack-show.stdout b/tests/ui/proc-macro/pretty-print-hack-show.stdout
deleted file mode 100644 (file)
index 3d793d2..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, }
-PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input }
-PRINT-DERIVE INPUT (DEBUG): TokenStream [
-    Ident {
-        ident: "enum",
-        span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:1: 4:5 (#0),
-    },
-    Ident {
-        ident: "ProceduralMasqueradeDummyType",
-        span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6: 4:35 (#0),
-    },
-    Group {
-        delimiter: Brace,
-        stream: TokenStream [
-            Ident {
-                ident: "Input",
-                span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:13:5: 13:10 (#0),
-            },
-        ],
-        span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:36: 14:2 (#0),
-    },
-]
-PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, }
-PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input }
-PRINT-DERIVE INPUT (DEBUG): TokenStream [
-    Ident {
-        ident: "enum",
-        span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:1: 4:5 (#0),
-    },
-    Ident {
-        ident: "ProceduralMasqueradeDummyType",
-        span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6: 4:35 (#0),
-    },
-    Group {
-        delimiter: Brace,
-        stream: TokenStream [
-            Ident {
-                ident: "Input",
-                span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:13:5: 13:10 (#0),
-            },
-        ],
-        span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:36: 14:2 (#0),
-    },
-]
index 948f21fce4bdba4c1176ce55983232e2a5c0e42c..b6cf19b8286cca19fd31427caa3ca5e6ce691a52 100644 (file)
@@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type
   --> $DIR/qualified-path-params-2.rs:18:10
    |
 LL | type A = <S as Tr>::A::f<u8>;
-   |          ^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<S as Tr>::A as Trait>::f`
+   |          ^^^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `f` implemented for `<S as Tr>::A`, you could use the fully-qualified path
+   |
+LL | type A = <<S as Tr>::A as Example>::f;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/tests/ui/remap-path-prefix.rs b/tests/ui/remap-path-prefix.rs
deleted file mode 100644 (file)
index 2eef970..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-// compile-flags: --remap-path-prefix={{src-base}}=remapped
-
-fn main() {
-    // We cannot actually put an ERROR marker here because
-    // the file name in the error message is not what the
-    // test framework expects (since the filename gets remapped).
-    // We still test the expected error in the stderr file.
-    ferris
-}
diff --git a/tests/ui/remap-path-prefix.stderr b/tests/ui/remap-path-prefix.stderr
deleted file mode 100644 (file)
index ad6a35d..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0425]: cannot find value `ferris` in this scope
-  --> remapped/remap-path-prefix.rs:8:5
-   |
-LL |     ferris
-   |     ^^^^^^ not found in this scope
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0425`.
index 880389371ef701633073dee31e2ed2484c3f376c..d4d141fb06f39e600e0a8417d694d7ec2931323f 100644 (file)
@@ -2,7 +2,12 @@ error[E0223]: ambiguous associated type
   --> $DIR/issue-103202.rs:4:17
    |
 LL |     fn f(self: &S::x) {}
-   |                 ^^^^ help: use fully-qualified syntax: `<S as Trait>::x`
+   |                 ^^^^
+   |
+help: if there were a trait named `Example` with associated type `x` implemented for `S`, you could use the fully-qualified path
+   |
+LL |     fn f(self: &<S as Example>::x) {}
+   |                 ~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
index fb47f27e022f59d1313f89b985505622a7f97506..36372b644d6e171a18f033f6a74b0bc2d96fa247 100644 (file)
@@ -2,13 +2,13 @@ error[E0223]: ambiguous associated type
   --> $DIR/self-impl.rs:23:16
    |
 LL |         let _: <Self>::Baz = true;
-   |                ^^^^^^^^^^^ help: use fully-qualified syntax: `<Bar as Trait>::Baz`
+   |                ^^^^^^^^^^^ help: use the fully-qualified path: `<Bar as Foo>::Baz`
 
 error[E0223]: ambiguous associated type
   --> $DIR/self-impl.rs:25:16
    |
 LL |         let _: Self::Baz = true;
-   |                ^^^^^^^^^ help: use fully-qualified syntax: `<Bar as Trait>::Baz`
+   |                ^^^^^^^^^ help: use the fully-qualified path: `<Bar as Foo>::Baz`
 
 error: aborting due to 2 previous errors
 
index abb445214f362f2d9515cc92195c0ed49870e472..ca5f0b7e21e7d4fb37c3e31d17f748305b63a0d2 100644 (file)
@@ -48,19 +48,19 @@ error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:32:13
    |
 LL |     let s = S::A {};
-   |             ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+   |             ^^^^ help: use the fully-qualified path: `<S as Tr>::A`
 
 error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:33:13
    |
 LL |     let z = S::A::<u8> {};
-   |             ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+   |             ^^^^ help: use the fully-qualified path: `<S as Tr>::A`
 
 error[E0223]: ambiguous associated type
   --> $DIR/struct-path-associated-type.rs:35:9
    |
 LL |         S::A {} => {}
-   |         ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+   |         ^^^^ help: use the fully-qualified path: `<S as Tr>::A`
 
 error: aborting due to 8 previous errors
 
index 44a39efdf25425015543ec99292f7e9c78ad7ed3..bc097bf6eb4515f76396ffff7b467a1721cbf5e5 100644 (file)
@@ -11,6 +11,13 @@ LL |     let _: Option<(i32, bool)> = Some(1, 2);
    |                                       ^
    = note: expected tuple `(i32, bool)`
                found type `{integer}`
+help: the type constructed contains `{integer}` due to the type of the argument passed
+  --> $DIR/args-instead-of-tuple-errors.rs:6:34
+   |
+LL |     let _: Option<(i32, bool)> = Some(1, 2);
+   |                                  ^^^^^-^^^^
+   |                                       |
+   |                                       this argument influences the type of `Some`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 help: remove the extra argument
@@ -64,6 +71,13 @@ LL |     let _: Option<(i32,)> = Some(5_usize);
    |
    = note: expected tuple `(i32,)`
                found type `usize`
+help: the type constructed contains `usize` due to the type of the argument passed
+  --> $DIR/args-instead-of-tuple-errors.rs:14:29
+   |
+LL |     let _: Option<(i32,)> = Some(5_usize);
+   |                             ^^^^^-------^
+   |                                  |
+   |                                  this argument influences the type of `Some`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
@@ -77,6 +91,13 @@ LL |     let _: Option<(i32,)> = Some((5_usize));
    |
    = note: expected tuple `(i32,)`
                found type `usize`
+help: the type constructed contains `usize` due to the type of the argument passed
+  --> $DIR/args-instead-of-tuple-errors.rs:17:29
+   |
+LL |     let _: Option<(i32,)> = Some((5_usize));
+   |                             ^^^^^---------^
+   |                                  |
+   |                                  this argument influences the type of `Some`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
diff --git a/tests/ui/suggestions/call-on-unimplemented-with-autoderef.rs b/tests/ui/suggestions/call-on-unimplemented-with-autoderef.rs
new file mode 100644 (file)
index 0000000..9021dd7
--- /dev/null
@@ -0,0 +1,13 @@
+trait Foo {}
+
+impl Foo for i32 {}
+
+fn needs_foo(_: impl Foo) {}
+
+fn test(x: &Box<dyn Fn() -> i32>) {
+    needs_foo(x);
+    //~^ ERROR the trait bound
+    //~| HELP use parentheses to call this trait object
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/call-on-unimplemented-with-autoderef.stderr b/tests/ui/suggestions/call-on-unimplemented-with-autoderef.stderr
new file mode 100644 (file)
index 0000000..90f44cc
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `&Box<dyn Fn() -> i32>: Foo` is not satisfied
+  --> $DIR/call-on-unimplemented-with-autoderef.rs:8:15
+   |
+LL |     needs_foo(x);
+   |     --------- ^ the trait `Foo` is not implemented for `&Box<dyn Fn() -> i32>`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `needs_foo`
+  --> $DIR/call-on-unimplemented-with-autoderef.rs:5:22
+   |
+LL | fn needs_foo(_: impl Foo) {}
+   |                      ^^^ required by this bound in `needs_foo`
+help: use parentheses to call this trait object
+   |
+LL |     needs_foo(x());
+   |                ++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 477eb2786799a5d9320e5ed5b210dfef659c3af8..2af7c2f6971484e925eafdc4d402dbf0de7be0c6 100644 (file)
@@ -24,16 +24,7 @@ error[E0425]: cannot find value `F` in this scope
   --> $DIR/constrain-suggest-ice.rs:6:9
    |
 LL |         F
-   |         ^
-   |
-help: a local variable with a similar name exists
-   |
-LL |         x
-   |         ~
-help: you might be missing a type parameter
-   |
-LL | struct Bug<S, F>{
-   |             +++
+   |         ^ help: a local variable with a similar name exists: `x`
 
 error: generic `Self` types are currently not permitted in anonymous constants
   --> $DIR/constrain-suggest-ice.rs:3:21
diff --git a/tests/ui/suggestions/issue-105761-suggest-self-for-closure.fixed b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.fixed
new file mode 100644 (file)
index 0000000..78e4836
--- /dev/null
@@ -0,0 +1,28 @@
+//run-rustfix
+#![allow(unused)]
+
+struct S;
+impl S {
+    fn foo(&mut self) {
+        let x = |this: &Self, v: i32| {
+            this.bar();
+            this.hel();
+        };
+        self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
+        x(self, 1);
+        x(self, 3);
+    }
+    fn bar(&self) {}
+    fn hel(&self) {}
+    fn qux(&mut self) {}
+
+    fn hello(&mut self) {
+        let y = |this: &Self| {
+            this.bar();
+        };
+        self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
+        y(self);
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/issue-105761-suggest-self-for-closure.rs b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.rs
new file mode 100644 (file)
index 0000000..6d8a9ff
--- /dev/null
@@ -0,0 +1,28 @@
+//run-rustfix
+#![allow(unused)]
+
+struct S;
+impl S {
+    fn foo(&mut self) {
+        let x = |v: i32| {
+            self.bar();
+            self.hel();
+        };
+        self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
+        x(1);
+        x(3);
+    }
+    fn bar(&self) {}
+    fn hel(&self) {}
+    fn qux(&mut self) {}
+
+    fn hello(&mut self) {
+        let y = || {
+            self.bar();
+        };
+        self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
+        y();
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/issue-105761-suggest-self-for-closure.stderr b/tests/ui/suggestions/issue-105761-suggest-self-for-closure.stderr
new file mode 100644 (file)
index 0000000..bc97d32
--- /dev/null
@@ -0,0 +1,49 @@
+error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
+  --> $DIR/issue-105761-suggest-self-for-closure.rs:11:9
+   |
+LL |         let x = |v: i32| {
+   |                 -------- immutable borrow occurs here
+LL |             self.bar();
+   |             ---- first borrow occurs due to use of `self` in closure
+...
+LL |         self.qux();
+   |         ^^^^^^^^^^ mutable borrow occurs here
+LL |         x(1);
+   |         - immutable borrow later used here
+   |
+help: try explicitly pass `&Self` into the Closure as an argument
+   |
+LL ~         let x = |this: &Self, v: i32| {
+LL ~             this.bar();
+LL ~             this.hel();
+LL |         };
+LL |         self.qux();
+LL ~         x(self, 1);
+LL ~         x(self, 3);
+   |
+
+error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
+  --> $DIR/issue-105761-suggest-self-for-closure.rs:23:9
+   |
+LL |         let y = || {
+   |                 -- immutable borrow occurs here
+LL |             self.bar();
+   |             ---- first borrow occurs due to use of `self` in closure
+LL |         };
+LL |         self.qux();
+   |         ^^^^^^^^^^ mutable borrow occurs here
+LL |         y();
+   |         - immutable borrow later used here
+   |
+help: try explicitly pass `&Self` into the Closure as an argument
+   |
+LL ~         let y = |this: &Self| {
+LL ~             this.bar();
+LL |         };
+LL |         self.qux();
+LL ~         y(self);
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
index 2bf072ef52175eb46a2b95de658956ccbe54ee52..b90ae051fb77675f1847cb8063b674661f8965fc 100644 (file)
@@ -21,7 +21,12 @@ error[E0223]: ambiguous associated type
   --> $DIR/let-binding-init-expr-as-ty.rs:2:14
    |
 LL |     let foo: i32::from_be(num);
-   |              ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<i32 as Trait>::from_be`
+   |              ^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `from_be` implemented for `i32`, you could use the fully-qualified path
+   |
+LL |     let foo: <i32 as Example>::from_be;
+   |              ~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 3 previous errors
 
index 5f59d0f541c99433e116610108335abbe02e9a0c..7f05832bcd7281e77c2b53d06549e36d9636a612 100644 (file)
@@ -8,6 +8,13 @@ LL |     let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
    |
    = note: expected reference `&str`
                 found closure `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]`
+help: the return type of this call is `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]` due to the type of the argument passed
+  --> $DIR/sugg-else-for-closure.rs:6:14
+   |
+LL |     let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
+   |              ^^^^^^^^^^^^-------------------------------^
+   |                          |
+   |                          this argument influences the return type of `unwrap_or`
 note: associated function defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 help: try calling `unwrap_or_else` instead
diff --git a/tests/ui/suggestions/type-mismatch-byte-literal.rs b/tests/ui/suggestions/type-mismatch-byte-literal.rs
new file mode 100644 (file)
index 0000000..34199f8
--- /dev/null
@@ -0,0 +1,18 @@
+// Tests that a suggestion is issued for type mismatch errors when a
+// u8 is expected and a char literal which is ASCII is supplied.
+
+fn foo(_t: u8) {}
+
+fn main() {
+    let _x: u8 = 'X';
+    //~^ ERROR: mismatched types [E0308]
+    //~| HELP: if you meant to write a byte literal, prefix with `b`
+
+    foo('#');
+    //~^ ERROR: mismatched types [E0308]
+    //~| HELP: if you meant to write a byte literal, prefix with `b`
+
+    // Do not issue the suggestion if the char literal isn't ASCII
+    let _t: u8 = '€';
+    //~^ ERROR: mismatched types [E0308]
+}
diff --git a/tests/ui/suggestions/type-mismatch-byte-literal.stderr b/tests/ui/suggestions/type-mismatch-byte-literal.stderr
new file mode 100644 (file)
index 0000000..c9c2e74
--- /dev/null
@@ -0,0 +1,42 @@
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch-byte-literal.rs:7:18
+   |
+LL |     let _x: u8 = 'X';
+   |             --   ^^^ expected `u8`, found `char`
+   |             |
+   |             expected due to this
+   |
+help: if you meant to write a byte literal, prefix with `b`
+   |
+LL |     let _x: u8 = b'X';
+   |                  ~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch-byte-literal.rs:11:9
+   |
+LL |     foo('#');
+   |     --- ^^^ expected `u8`, found `char`
+   |     |
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/type-mismatch-byte-literal.rs:4:4
+   |
+LL | fn foo(_t: u8) {}
+   |    ^^^ ------
+help: if you meant to write a byte literal, prefix with `b`
+   |
+LL |     foo(b'#');
+   |         ~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch-byte-literal.rs:16:18
+   |
+LL |     let _t: u8 = '€';
+   |             --   ^^^ expected `u8`, found `char`
+   |             |
+   |             expected due to this
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/fn-trait-cast-diagnostic.rs b/tests/ui/traits/fn-trait-cast-diagnostic.rs
new file mode 100644 (file)
index 0000000..e20aa21
--- /dev/null
@@ -0,0 +1,26 @@
+// There are two different instances to check that even if
+// the trait is implemented for the output of a function,
+// it will still be displayed if the function itself implements a trait.
+trait Foo {}
+
+impl Foo for fn() -> bool {}
+impl Foo for bool {}
+
+fn example() -> bool {
+    true
+}
+
+trait NoOtherFoo {}
+
+impl NoOtherFoo for fn() -> bool {}
+
+fn do_on_foo(v: impl Foo) {}
+fn do_on_single_foo(v: impl NoOtherFoo) {}
+
+fn main() {
+    do_on_foo(example);
+    //~^ ERROR the trait bound
+
+    do_on_single_foo(example);
+    //~^ ERROR the trait bound
+}
diff --git a/tests/ui/traits/fn-trait-cast-diagnostic.stderr b/tests/ui/traits/fn-trait-cast-diagnostic.stderr
new file mode 100644 (file)
index 0000000..6851dcd
--- /dev/null
@@ -0,0 +1,43 @@
+error[E0277]: the trait bound `fn() -> bool {example}: Foo` is not satisfied
+  --> $DIR/fn-trait-cast-diagnostic.rs:21:15
+   |
+LL |     do_on_foo(example);
+   |     --------- ^^^^^^^ the trait `Foo` is not implemented for fn item `fn() -> bool {example}`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `do_on_foo`
+  --> $DIR/fn-trait-cast-diagnostic.rs:17:22
+   |
+LL | fn do_on_foo(v: impl Foo) {}
+   |                      ^^^ required by this bound in `do_on_foo`
+help: use parentheses to call this function
+   |
+LL |     do_on_foo(example());
+   |                      ++
+help: the trait `Foo` is implemented for fn pointer `fn() -> bool`, try casting using `as`
+   |
+LL |     do_on_foo(example as fn() -> bool);
+   |                       +++++++++++++++
+
+error[E0277]: the trait bound `fn() -> bool {example}: NoOtherFoo` is not satisfied
+  --> $DIR/fn-trait-cast-diagnostic.rs:24:22
+   |
+LL |     do_on_single_foo(example);
+   |     ---------------- ^^^^^^^ the trait `NoOtherFoo` is not implemented for fn item `fn() -> bool {example}`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `do_on_single_foo`
+  --> $DIR/fn-trait-cast-diagnostic.rs:18:29
+   |
+LL | fn do_on_single_foo(v: impl NoOtherFoo) {}
+   |                             ^^^^^^^^^^ required by this bound in `do_on_single_foo`
+help: the trait `NoOtherFoo` is implemented for fn pointer `fn() -> bool`, try casting using `as`
+   |
+LL |     do_on_single_foo(example as fn() -> bool);
+   |                              +++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/issue-106072.rs b/tests/ui/traits/issue-106072.rs
new file mode 100644 (file)
index 0000000..7064a39
--- /dev/null
@@ -0,0 +1,5 @@
+#[derive(Clone)] //~  trait objects must include the `dyn` keyword
+                 //~| trait objects must include the `dyn` keyword
+struct Foo;
+trait Foo {} //~ the name `Foo` is defined multiple times
+fn main() {}
diff --git a/tests/ui/traits/issue-106072.stderr b/tests/ui/traits/issue-106072.stderr
new file mode 100644 (file)
index 0000000..f9b7b81
--- /dev/null
@@ -0,0 +1,30 @@
+error[E0428]: the name `Foo` is defined multiple times
+  --> $DIR/issue-106072.rs:4:1
+   |
+LL | struct Foo;
+   | ----------- previous definition of the type `Foo` here
+LL | trait Foo {}
+   | ^^^^^^^^^ `Foo` redefined here
+   |
+   = note: `Foo` must be defined only once in the type namespace of this module
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/issue-106072.rs:1:10
+   |
+LL | #[derive(Clone)]
+   |          ^^^^^
+   |
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/issue-106072.rs:1:10
+   |
+LL | #[derive(Clone)]
+   |          ^^^^^
+   |
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0428, E0782.
+For more information about an error, try `rustc --explain E0428`.
index 4fe12731475b493d8e9426b04cae17c35f95410e..6b5b721384cbbebb622b4cdaaee0b356c35e5e45 100644 (file)
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
 LL | impl<T> Complete for T {}
    |                      ^ the trait `Copy` is not implemented for `T`
    |
+note: required for `T` to implement `Partial`
+  --> $DIR/issue-43784-supertrait.rs:1:11
+   |
+LL | pub trait Partial: Copy {
+   |           ^^^^^^^
 note: required by a bound in `Complete`
   --> $DIR/issue-43784-supertrait.rs:4:21
    |
index 7924d3db06f36efb7ce39b5e0740200fc312099e..a11867c03a689259dde89dd3adddef9e0822414f 100644 (file)
@@ -11,6 +11,13 @@ LL |         builder.push(output);
    |
    = note: expected type parameter `F`
                       found struct `Class<P>`
+help: the return type of this call is `Class<P>` due to the type of the argument passed
+  --> $DIR/issue-52893.rs:53:9
+   |
+LL |         builder.push(output);
+   |         ^^^^^^^^^^^^^------^
+   |                      |
+   |                      this argument influences the return type of `push`
 note: associated function defined here
   --> $DIR/issue-52893.rs:11:8
    |
index 3ff8f12f1b8ce8688378ef9ab7699d54a24edc24..fb6eebbd254a2034206d4829c6b1f44bc7f28c6b 100644 (file)
@@ -6,12 +6,15 @@ LL |     takes(function);
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
 note: required by a bound in `takes`
   --> $DIR/issue-99875.rs:9:18
    |
 LL | fn takes(_: impl Trait) {}
    |                  ^^^^^ required by this bound in `takes`
+help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`, try casting using `as`
+   |
+LL |     takes(function as fn(Argument) -> Return);
+   |                    +++++++++++++++++++++++++
 
 error[E0277]: the trait bound `[closure@$DIR/issue-99875.rs:14:11: 14:34]: Trait` is not satisfied
   --> $DIR/issue-99875.rs:14:11
index f137a298a7f41a533b69b22a9eddbd08853d73f7..293cfbda86c4925b680463596a809cb5226438cc 100644 (file)
@@ -148,19 +148,24 @@ error[E0223]: ambiguous associated type
   --> $DIR/item-privacy.rs:115:12
    |
 LL |     let _: S::A;
-   |            ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
+   |            ^^^^
+   |
+help: if there were a trait named `Example` with associated type `A` implemented for `S`, you could use the fully-qualified path
+   |
+LL |     let _: <S as Example>::A;
+   |            ~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/item-privacy.rs:116:12
    |
 LL |     let _: S::B;
-   |            ^^^^ help: use fully-qualified syntax: `<S as Trait>::B`
+   |            ^^^^ help: use the fully-qualified path: `<S as assoc_ty::B>::B`
 
 error[E0223]: ambiguous associated type
   --> $DIR/item-privacy.rs:117:12
    |
 LL |     let _: S::C;
-   |            ^^^^ help: use fully-qualified syntax: `<S as Trait>::C`
+   |            ^^^^ help: use the fully-qualified path: `<S as assoc_ty::C>::C`
 
 error[E0624]: associated type `A` is private
   --> $DIR/item-privacy.rs:119:12
diff --git a/tests/ui/traits/track-obligations.rs b/tests/ui/traits/track-obligations.rs
new file mode 100644 (file)
index 0000000..77e753c
--- /dev/null
@@ -0,0 +1,88 @@
+// These are simplifications of the tower traits by the same name:
+
+pub trait Service<Request> {
+    type Response;
+}
+
+pub trait Layer<C> {
+    type Service;
+}
+
+// Any type will do here:
+
+pub struct Req;
+pub struct Res;
+
+// This is encoding a trait alias.
+
+pub trait ParticularService:
+    Service<Req, Response = Res> {
+}
+
+impl<T> ParticularService for T
+where
+    T: Service<Req, Response = Res>,
+{
+}
+
+// This is also a trait alias.
+// The weird = <Self as ...> bound is there so that users of the trait do not
+// need to repeat the bounds. See https://github.com/rust-lang/rust/issues/20671
+// for context, and in particular the workaround in:
+// https://github.com/rust-lang/rust/issues/20671#issuecomment-529752828
+
+pub trait ParticularServiceLayer<C>:
+    Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
+{
+    type Service: ParticularService;
+}
+
+impl<T, C> ParticularServiceLayer<C> for T
+where
+    T: Layer<C>,
+    T::Service: ParticularService,
+{
+    type Service = T::Service;
+}
+
+// These are types that implement the traits that the trait aliases refer to.
+// They should also implement the alias traits due to the blanket impls.
+
+struct ALayer<C>(C);
+impl<C> Layer<C> for ALayer<C> {
+    type Service = AService;
+}
+
+struct AService;
+impl Service<Req> for AService {
+    // However, AService does _not_ meet the blanket implementation,
+    // since its Response type is bool, not Res as it should be.
+    type Response = bool;
+}
+
+// This is a wrapper type around ALayer that uses the trait alias
+// as a way to communicate the requirements of the provided types.
+struct Client<C>(C);
+
+// The method and the free-standing function below both have the same bounds.
+
+impl<C> Client<C>
+where
+    ALayer<C>: ParticularServiceLayer<C>,
+{
+    fn check(&self) {}
+}
+
+fn check<C>(_: C) where ALayer<C>: ParticularServiceLayer<C> {}
+
+// But, they give very different error messages.
+
+fn main() {
+    // This gives a very poor error message that does nothing to point the user
+    // at the underlying cause of why the types involved do not meet the bounds.
+    Client(()).check(); //~ ERROR E0599
+
+    // This gives a good(ish) error message that points the user at _why_ the
+    // bound isn't met, and thus how they might fix it.
+    check(()); //~ ERROR E0271
+}
diff --git a/tests/ui/traits/track-obligations.stderr b/tests/ui/traits/track-obligations.stderr
new file mode 100644 (file)
index 0000000..8947747
--- /dev/null
@@ -0,0 +1,76 @@
+error[E0599]: the method `check` exists for struct `Client<()>`, but its trait bounds were not satisfied
+  --> $DIR/track-obligations.rs:83:16
+   |
+LL | struct ALayer<C>(C);
+   | ----------------
+   | |
+   | doesn't satisfy `<_ as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service`
+   | doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>`
+...
+LL | struct Client<C>(C);
+   | ---------------- method `check` not found for this struct
+...
+LL |     Client(()).check();
+   |                ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds
+   |
+note: trait bound `<ALayer<()> as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service` was not satisfied
+  --> $DIR/track-obligations.rs:35:14
+   |
+LL | pub trait ParticularServiceLayer<C>:
+   |           ----------------------
+LL |     Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
+note: trait bound `ALayer<()>: ParticularServiceLayer<()>` was not satisfied
+  --> $DIR/track-obligations.rs:71:16
+   |
+LL | impl<C> Client<C>
+   |         ---------
+LL | where
+LL |     ALayer<C>: ParticularServiceLayer<C>,
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
+note: the trait `ParticularServiceLayer` must be implemented
+  --> $DIR/track-obligations.rs:34:1
+   |
+LL | / pub trait ParticularServiceLayer<C>:
+LL | |     Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
+   | |____________________________________________________________________^
+
+error[E0271]: type mismatch resolving `<AService as Service<Req>>::Response == Res`
+  --> $DIR/track-obligations.rs:87:11
+   |
+LL |     check(());
+   |     ----- ^^ type mismatch resolving `<AService as Service<Req>>::Response == Res`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: expected this to be `Res`
+  --> $DIR/track-obligations.rs:60:21
+   |
+LL |     type Response = bool;
+   |                     ^^^^
+note: required for `AService` to implement `ParticularService`
+  --> $DIR/track-obligations.rs:22:9
+   |
+LL | impl<T> ParticularService for T
+   |         ^^^^^^^^^^^^^^^^^     ^
+LL | where
+LL |     T: Service<Req, Response = Res>,
+   |                     -------------- unsatisfied trait bound introduced here
+note: required for `ALayer<_>` to implement `ParticularServiceLayer<_>`
+  --> $DIR/track-obligations.rs:40:12
+   |
+LL | impl<T, C> ParticularServiceLayer<C> for T
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^     ^
+...
+LL |     T::Service: ParticularService,
+   |                 ----------------- unsatisfied trait bound introduced here
+note: required by a bound in `check`
+  --> $DIR/track-obligations.rs:76:36
+   |
+LL | fn check<C>(_: C) where ALayer<C>: ParticularServiceLayer<C> {}
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0271, E0599.
+For more information about an error, try `rustc --explain E0271`.
index 4d2890b5de583c48bc63a8e6d727e4d3516f03f1..0bcc9e002ca0449040b54f47cade01bcc9e0b259 100644 (file)
@@ -14,5 +14,5 @@ impl<W> Trait<W> for () {}
 
 fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
     ()
-    //~^ ERROR non-defining opaque type use
+    //~^ ERROR expected generic type parameter, found `<T as TraitWithAssoc>::Assoc`
 }
index c405b1f6af2057428a78bf0dc88993d954d99ad7..3c259bd9e97cc08c2d3e04eaf57ac048d94924d9 100644 (file)
@@ -1,14 +1,12 @@
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic type parameter, found `<T as TraitWithAssoc>::Assoc`
   --> $DIR/bound_reduction2.rs:16:5
    |
+LL | type Foo<V> = impl Trait<V>;
+   |          - this generic parameter must be used with a generic type parameter
+...
 LL |     ()
    |     ^^
-   |
-note: used non-generic type `<T as TraitWithAssoc>::Assoc` for generic parameter
-  --> $DIR/bound_reduction2.rs:9:10
-   |
-LL | type Foo<V> = impl Trait<V>;
-   |          ^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0792`.
index f39741a6a625cc2d693309227e45982ad3515156..f5045d382aac4ed63c4be46e727c657ea6444a1c 100644 (file)
@@ -10,12 +10,11 @@ fn main() {}
 
 type OneConst<const X: usize> = impl Debug;
 
-
 // Not defining uses, because they doesn't define *all* possible generics.
 
 fn concrete_ty() -> OneTy<u32> {
     5u32
-    //~^ ERROR non-defining opaque type use in defining scope
+    //~^ ERROR expected generic type parameter, found `u32`
 }
 
 fn concrete_lifetime() -> OneLifetime<'static> {
@@ -25,5 +24,5 @@ fn concrete_lifetime() -> OneLifetime<'static> {
 
 fn concrete_const() -> OneConst<{ 123 }> {
     7u32
-    //~^ ERROR non-defining opaque type use in defining scope
+    //~^ ERROR expected generic constant parameter, found `123`
 }
index e7565525ad3387396ac5c7f9d2efd85ae366943f..564648630b16122127ce6a1c026785740f68c118 100644 (file)
@@ -1,17 +1,14 @@
-error: non-defining opaque type use in defining scope
-  --> $DIR/generic_nondefining_use.rs:17:5
+error[E0792]: expected generic type parameter, found `u32`
+  --> $DIR/generic_nondefining_use.rs:16:5
    |
+LL | type OneTy<T> = impl Debug;
+   |            - this generic parameter must be used with a generic type parameter
+...
 LL |     5u32
    |     ^^^^
-   |
-note: used non-generic type `u32` for generic parameter
-  --> $DIR/generic_nondefining_use.rs:7:12
-   |
-LL | type OneTy<T> = impl Debug;
-   |            ^
 
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_nondefining_use.rs:22:5
+  --> $DIR/generic_nondefining_use.rs:21:5
    |
 LL | type OneLifetime<'a> = impl Debug;
    |                  -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
@@ -19,17 +16,15 @@ LL | type OneLifetime<'a> = impl Debug;
 LL |     6u32
    |     ^^^^
 
-error: non-defining opaque type use in defining scope
-  --> $DIR/generic_nondefining_use.rs:27:5
+error[E0792]: expected generic constant parameter, found `123`
+  --> $DIR/generic_nondefining_use.rs:26:5
    |
+LL | type OneConst<const X: usize> = impl Debug;
+   |               -------------- this generic parameter must be used with a generic constant parameter
+...
 LL |     7u32
    |     ^^^^
-   |
-note: used non-generic constant `123` for generic parameter
-  --> $DIR/generic_nondefining_use.rs:11:15
-   |
-LL | type OneConst<const X: usize> = impl Debug;
-   |               ^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0792`.
index cb90776472b5dc543fd395548d0cbe41082ca61f..d3e169a70d3f7f30471d26e9186092e2a83ad880 100644 (file)
@@ -4,7 +4,7 @@ fn main() {
     let y = 42;
     let x = wrong_generic(&y);
     let z: i32 = x;
-    //~^ ERROR non-defining opaque type use
+    //~^ ERROR expected generic type parameter, found `&'static i32
 }
 
 type WrongGeneric<T> = impl 'static;
index ba583241a696b57dc23c5ac20908c54d29abfb29..19115fd28662be97e91c77088a4f7b2cb5c299a4 100644 (file)
@@ -4,17 +4,14 @@ error: at least one trait must be specified
 LL | type WrongGeneric<T> = impl 'static;
    |                        ^^^^^^^^^^^^
 
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic type parameter, found `&'static i32`
   --> $DIR/generic_type_does_not_live_long_enough.rs:6:18
    |
 LL |     let z: i32 = x;
    |                  ^
-   |
-note: used non-generic type `&'static i32` for generic parameter
-  --> $DIR/generic_type_does_not_live_long_enough.rs:10:19
-   |
+...
 LL | type WrongGeneric<T> = impl 'static;
-   |                   ^
+   |                   - this generic parameter must be used with a generic type parameter
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/generic_type_does_not_live_long_enough.rs:14:5
@@ -29,4 +26,5 @@ LL | fn wrong_generic<T: 'static>(t: T) -> WrongGeneric<T> {
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0310`.
+Some errors have detailed explanations: E0310, E0792.
+For more information about an error, try `rustc --explain E0310`.
index 4fc7679311a2e55b031dd0cf0c460c979476212b..c2f4c37080746f3ef2437046074e3434ecbc38e4 100644 (file)
@@ -18,7 +18,7 @@ impl<T: Copy, E> IterBits for T
     type BitsIter = IterBitsIter<T, E, u8>;
     fn iter_bits(self, n: u8) -> Self::BitsIter {
         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
-        //~^ ERROR non-defining opaque type use in defining scope
+        //~^ ERROR expected generic type parameter, found `u8`
     }
 }
 
index bbc93657be32f27501c851460adbfb0554ee0826..f8fdb004d098996e1af34800fe48011c533c341f 100644 (file)
@@ -1,14 +1,12 @@
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic type parameter, found `u8`
   --> $DIR/issue-60564.rs:20:9
    |
+LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
+   |                         - this generic parameter must be used with a generic type parameter
+...
 LL |         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: used non-generic type `u8` for generic parameter
-  --> $DIR/issue-60564.rs:8:25
-   |
-LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
-   |                         ^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0792`.
index 5223fb1c702d6753c92e6f6ac2e9938732faf792..5e0a82a72868ab88337ba20251768de6c23193b3 100644 (file)
@@ -7,7 +7,7 @@ trait Trait<T> {}
 type Alias<'a, U> = impl Trait<U>;
 
 fn f<'a>() -> Alias<'a, ()> {}
-//~^ ERROR non-defining opaque type use in defining scope
+//~^ ERROR expected generic type parameter, found `()`
 
 fn main() {}
 
index 7fb9a0c410e83c8c976a78979f913279f462b84e..271743a4010c8faa841a82027d8520e96a019546 100644 (file)
@@ -1,14 +1,12 @@
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic type parameter, found `()`
   --> $DIR/issue-68368-non-defining-use-2.rs:9:29
    |
+LL | type Alias<'a, U> = impl Trait<U>;
+   |                - this generic parameter must be used with a generic type parameter
+LL |
 LL | fn f<'a>() -> Alias<'a, ()> {}
    |                             ^^
-   |
-note: used non-generic type `()` for generic parameter
-  --> $DIR/issue-68368-non-defining-use-2.rs:7:16
-   |
-LL | type Alias<'a, U> = impl Trait<U>;
-   |                ^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0792`.
index b50462bf237bb9509f9d090097ef9675af48b8b8..3b32260c96fe14b9a84821de686d21de5aec353c 100644 (file)
@@ -7,7 +7,7 @@ trait Trait<T> {}
 type Alias<'a, U> = impl Trait<U>;
 
 fn f<'a>() -> Alias<'a, ()> {}
-//~^ ERROR non-defining opaque type use in defining scope
+//~^ ERROR expected generic type parameter, found `()`
 
 fn main() {}
 
index 8059621b61a096bc84ed17714d7130d44e864d72..4d9a8d6eef9156bbda6c22542093104cd88c504f 100644 (file)
@@ -1,14 +1,12 @@
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic type parameter, found `()`
   --> $DIR/issue-68368-non-defining-use.rs:9:29
    |
+LL | type Alias<'a, U> = impl Trait<U>;
+   |                - this generic parameter must be used with a generic type parameter
+LL |
 LL | fn f<'a>() -> Alias<'a, ()> {}
    |                             ^^
-   |
-note: used non-generic type `()` for generic parameter
-  --> $DIR/issue-68368-non-defining-use.rs:7:16
-   |
-LL | type Alias<'a, U> = impl Trait<U>;
-   |                ^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0792`.
index 428454bc04844d836b75c3a7fbde6796a1e84b53..7657fe2fb1aee34c86e37a4aa96905f7bb3c3a80 100644 (file)
@@ -18,6 +18,6 @@ impl<T> WithAssoc<T> for () {
 //~^ ERROR use of undeclared lifetime name `'a`
 
 fn my_fun() -> Return<()> {}
-//~^ ERROR non-defining opaque type use in defining scope
+//~^ ERROR expected generic type parameter, found `()`
 
 fn main() {}
index 7b50c8af26e5fe98d74a704b12ff57060e2f612b..d1250786d938c367c5cb2be6ab0ad6a5b693ee45 100644 (file)
@@ -14,18 +14,16 @@ help: consider introducing lifetime `'a` here
 LL | type Return<'a, A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
    |             +++
 
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic type parameter, found `()`
   --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27
    |
+LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
+   |             - this generic parameter must be used with a generic type parameter
+...
 LL | fn my_fun() -> Return<()> {}
    |                           ^^
-   |
-note: used non-generic type `()` for generic parameter
-  --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13
-   |
-LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
-   |             ^
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0261`.
+Some errors have detailed explanations: E0261, E0792.
+For more information about an error, try `rustc --explain E0261`.
index be60cda68b9f0fb0ce1951d6d84934f929f10a1d..e544b369515489ba17258e2eac2ea7eb50575cb5 100644 (file)
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `(Vec<T>,)`
   --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:9
    |
 LL |     let (x, ) = (vec![], );
-   |         ^^^^^
+   |         ^^^^^   ---------- type must be known at this point
    |
 help: consider giving this pattern a type, where the type for type parameter `T` is specified
    |
diff --git a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs
new file mode 100644 (file)
index 0000000..ba5b9f5
--- /dev/null
@@ -0,0 +1,28 @@
+fn function<T>(x: T, y: bool) -> T {
+    x
+}
+
+struct S {}
+impl S {
+    fn method<T>(&self, x: T) -> T {
+        x
+    }
+}
+
+fn wrong_arg_type(x: u32) -> u32 {
+    x
+}
+
+fn main() {
+    // Should not trigger.
+    let x = wrong_arg_type(0u16); //~ ERROR mismatched types
+    let x: u16 = function(0, 0u8); //~ ERROR mismatched types
+
+    // Should trigger exactly once for the first argument.
+    let x: u16 = function(0u32, 0u8); //~ ERROR arguments to this function are incorrect
+
+    // Should trigger.
+    let x: u16 = function(0u32, true); //~ ERROR mismatched types
+    let x: u16 = (S {}).method(0u32); //~ ERROR mismatched types
+    function(0u32, 8u8) //~ ERROR arguments to this function are incorrect
+}
diff --git a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr
new file mode 100644 (file)
index 0000000..4d012cb
--- /dev/null
@@ -0,0 +1,131 @@
+error[E0308]: mismatched types
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:18:28
+   |
+LL |     let x = wrong_arg_type(0u16);
+   |             -------------- ^^^^ expected `u32`, found `u16`
+   |             |
+   |             arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:12:4
+   |
+LL | fn wrong_arg_type(x: u32) -> u32 {
+   |    ^^^^^^^^^^^^^^ ------
+help: change the type of the numeric literal from `u16` to `u32`
+   |
+LL |     let x = wrong_arg_type(0u32);
+   |                             ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:19:30
+   |
+LL |     let x: u16 = function(0, 0u8);
+   |                  --------    ^^^ expected `bool`, found `u8`
+   |                  |
+   |                  arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+   |
+LL | fn function<T>(x: T, y: bool) -> T {
+   |    ^^^^^^^^          -------
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:22:18
+   |
+LL |     let x: u16 = function(0u32, 0u8);
+   |                  ^^^^^^^^ ----  --- expected `bool`, found `u8`
+   |                           |
+   |                           expected `u16`, found `u32`
+   |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:22:18
+   |
+LL |     let x: u16 = function(0u32, 0u8);
+   |                  ^^^^^^^^^----^^^^^^
+   |                           |
+   |                           this argument influences the return type of `function`
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+   |
+LL | fn function<T>(x: T, y: bool) -> T {
+   |    ^^^^^^^^    ----  -------
+help: change the type of the numeric literal from `u32` to `u16`
+   |
+LL |     let x: u16 = function(0u16, 0u8);
+   |                            ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:25:27
+   |
+LL |     let x: u16 = function(0u32, true);
+   |                  -------- ^^^^ expected `u16`, found `u32`
+   |                  |
+   |                  arguments to this function are incorrect
+   |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:25:18
+   |
+LL |     let x: u16 = function(0u32, true);
+   |                  ^^^^^^^^^----^^^^^^^
+   |                           |
+   |                           this argument influences the return type of `function`
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+   |
+LL | fn function<T>(x: T, y: bool) -> T {
+   |    ^^^^^^^^    ----
+help: change the type of the numeric literal from `u32` to `u16`
+   |
+LL |     let x: u16 = function(0u16, true);
+   |                            ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:26:32
+   |
+LL |     let x: u16 = (S {}).method(0u32);
+   |                         ------ ^^^^ expected `u16`, found `u32`
+   |                         |
+   |                         arguments to this method are incorrect
+   |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:26:18
+   |
+LL |     let x: u16 = (S {}).method(0u32);
+   |                  ^^^^^^^^^^^^^^----^
+   |                                |
+   |                                this argument influences the return type of `method`
+note: associated function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:7:8
+   |
+LL |     fn method<T>(&self, x: T) -> T {
+   |        ^^^^^^           ----
+help: change the type of the numeric literal from `u32` to `u16`
+   |
+LL |     let x: u16 = (S {}).method(0u16);
+   |                                 ~~~
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5
+   |
+LL |     function(0u32, 8u8)
+   |     ^^^^^^^^ ----  --- expected `bool`, found `u8`
+   |              |
+   |              expected `()`, found `u32`
+   |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5
+   |
+LL |     function(0u32, 8u8)
+   |     ^^^^^^^^^----^^^^^^
+   |              |
+   |              this argument influences the return type of `function`
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+   |
+LL | fn function<T>(x: T, y: bool) -> T {
+   |    ^^^^^^^^    ----  -------
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 5561673f3c6728e6bba507c3fd1305e82d85b498..42cfe38aed888e0b8dd69e61f44a5f03c670c1ce 100644 (file)
@@ -3,11 +3,6 @@ error[E0405]: cannot find trait `Oops` in this scope
    |
 LL |     let _: S<impl Oops> = S;
    |                   ^^^^ not found in this scope
-   |
-help: you might be missing a type parameter
-   |
-LL | fn f<Oops>() {
-   |     ++++++
 
 error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
   --> $DIR/issue-104513-ice.rs:3:14
index f488463ae3ce9faedbd67b008ae8cac5468b11bd..8f5ff51fbe1007cb7e77aa405625b059df75ed5f 100644 (file)
@@ -8,6 +8,13 @@ LL | fn main() { test(Ok(())); }
    |
    = note:   expected enum `Option<()>`
            found unit type `()`
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-46112.rs:9:18
+   |
+LL | fn main() { test(Ok(())); }
+   |                  ^^^--^
+   |                     |
+   |                     this argument influences the type of `Ok`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
 help: try wrapping the expression in `Some`
index 00d23389720b9d636cd2272e0686d5361dd2bdbe..09f3aee2d9ec56a51a33b9639863e6950adba45e 100644 (file)
@@ -14,6 +14,13 @@ LL |     <F as FnOnce(&mut u8)>::call_once(f, 1)
    |
    = note: expected tuple `(&mut u8,)`
                found type `{integer}`
+help: the return type of this call is `{integer}` due to the type of the argument passed
+  --> $DIR/issue-84768.rs:7:5
+   |
+LL |     <F as FnOnce(&mut u8)>::call_once(f, 1)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^
+   |                                          |
+   |                                          this argument influences the return type of `FnOnce`
 note: associated function defined here
   --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
index 5f7f6aa9f6ec62697ef4ae895994f184dd6686de..72fccea8ae399f1b763a23756c0169210cdad7ed 100644 (file)
@@ -205,7 +205,12 @@ error[E0223]: ambiguous associated type
   --> $DIR/ufcs-partially-resolved.rs:36:12
    |
 LL |     let _: <u8 as Tr>::Y::NN;
-   |            ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<u8 as Tr>::Y as Trait>::NN`
+   |            ^^^^^^^^^^^^^^^^^
+   |
+help: if there were a trait named `Example` with associated type `NN` implemented for `<u8 as Tr>::Y`, you could use the fully-qualified path
+   |
+LL |     let _: <<u8 as Tr>::Y as Example>::NN;
+   |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0599]: no associated item named `NN` found for type `u16` in the current scope
   --> $DIR/ufcs-partially-resolved.rs:38:20
index a2fe627868aeb36faef45712e678d61e0e83064f..e85144a31ca96c8ebc87ebd1a178f889dd5528b5 100644 (file)
@@ -21,6 +21,13 @@ LL |     <i32 as Add<i32>>::add(1u32, 2);
    |     |
    |     arguments to this function are incorrect
    |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/ufcs-qpath-self-mismatch.rs:7:5
+   |
+LL |     <i32 as Add<i32>>::add(1u32, 2);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^----^^^^
+   |                            |
+   |                            this argument influences the return type of `Add`
 note: associated function defined here
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 help: change the type of the numeric literal from `u32` to `i32`
@@ -36,6 +43,13 @@ LL |     <i32 as Add<i32>>::add(1, 2u32);
    |     |
    |     arguments to this function are incorrect
    |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/ufcs-qpath-self-mismatch.rs:9:5
+   |
+LL |     <i32 as Add<i32>>::add(1, 2u32);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^----^
+   |                               |
+   |                               this argument influences the return type of `Add`
 note: associated function defined here
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 help: change the type of the numeric literal from `u32` to `i32`
index 914b52cf041dbdf5be1802a1cadc6561fad571a5..14bade6472fa63b500ca6f0f6202a3ad01e4436d 100644 (file)
@@ -251,7 +251,7 @@ new_pr = true
 
 [autolabel."WG-trait-system-refactor"]
 trigger_files = [
-    "compiler/rustc_trait_selection/solve"
+    "compiler/rustc_trait_selection/src/solve"
 ]
 
 [notify-zulip."I-prioritize"]