]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #106353 - lukas-code:reduce-red-lines-in-my-ide, r=wesleywiser
authorMichael Goulet <michael@errs.io>
Wed, 4 Jan 2023 01:19:27 +0000 (17:19 -0800)
committerGitHub <noreply@github.com>
Wed, 4 Jan 2023 01:19:27 +0000 (17:19 -0800)
Reduce spans for `unsafe impl` errors

Because huge spans aren't great for IDEs.

Prior art: https://github.com/rust-lang/rust/pull/103749

281 files changed:
Cargo.lock
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_borrowck/src/borrowck_errors.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_builtin_macros/src/format.rs
compiler/rustc_codegen_gcc/src/builder.rs
compiler/rustc_codegen_gcc/src/context.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_data_structures/src/sorted_map.rs
compiler/rustc_error_messages/locales/en-US/metadata.ftl
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_expand/src/expand.rs
compiler/rustc_expand/src/mbe/diagnostics.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/hir_id.rs
compiler/rustc_hir_analysis/src/coherence/orphan.rs
compiler/rustc_hir_typeck/src/expr.rs
compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
compiler/rustc_hir_typeck/src/lib.rs
compiler/rustc_hir_typeck/src/method/prelude2021.rs
compiler/rustc_hir_typeck/src/method/probe.rs
compiler/rustc_hir_typeck/src/method/suggest.rs
compiler/rustc_hir_typeck/src/op.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
compiler/rustc_interface/src/callbacks.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/early.rs
compiler/rustc_lint/src/late.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_macros/src/symbols/tests.rs
compiler/rustc_metadata/src/dependency_format.rs
compiler/rustc_metadata/src/errors.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/mir/visit.rs
compiler/rustc_mir_build/src/check_unsafety.rs
compiler/rustc_mir_transform/src/inline.rs
compiler/rustc_query_impl/src/lib.rs
compiler/rustc_query_impl/src/plumbing.rs
compiler/rustc_query_system/src/dep_graph/graph.rs
compiler/rustc_query_system/src/query/config.rs
compiler/rustc_query_system/src/query/mod.rs
compiler/rustc_query_system/src/query/plumbing.rs
compiler/rustc_resolve/src/ident.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/options.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/span_encoding.rs
compiler/rustc_trait_selection/src/solve/overflow.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_ty_utils/src/abi.rs
library/alloc/src/alloc.rs
library/alloc/src/lib.rs
library/core/src/lib.rs
library/core/src/panicking.rs
library/core/src/str/iter.rs
library/core/src/task/wake.rs
library/core/tests/task.rs
library/std/src/alloc.rs
library/std/src/io/mod.rs
library/std/src/path.rs
src/bootstrap/bootstrap.py
src/bootstrap/check.rs
src/bootstrap/compile.rs
src/bootstrap/dist.rs
src/bootstrap/download-ci-llvm-stamp
src/bootstrap/native.rs
src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
src/ci/run.sh
src/doc/book
src/doc/nomicon
src/doc/rust-by-example
src/doc/rustc-dev-guide
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/fold.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/json/conversions.rs
src/librustdoc/passes/stripper.rs
src/librustdoc/visit.rs
src/librustdoc/visit_ast.rs
src/rustdoc-json-types/lib.rs
src/test/codegen/function-arguments.rs
src/test/codegen/issue-103840.rs [new file with mode: 0644]
src/test/incremental/change_symbol_export_status.rs
src/test/incremental/hashes/call_expressions.rs
src/test/incremental/hashes/closure_expressions.rs
src/test/incremental/hashes/enum_constructors.rs
src/test/incremental/hashes/enum_defs.rs
src/test/incremental/hashes/exported_vs_not.rs
src/test/incremental/hashes/extern_mods.rs
src/test/incremental/hashes/for_loops.rs
src/test/incremental/hashes/function_interfaces.rs
src/test/incremental/hashes/if_expressions.rs
src/test/incremental/hashes/indexing_expressions.rs
src/test/incremental/hashes/inherent_impls.rs
src/test/incremental/hashes/inline_asm.rs
src/test/incremental/hashes/let_expressions.rs
src/test/incremental/hashes/loop_expressions.rs
src/test/incremental/hashes/match_expressions.rs
src/test/incremental/hashes/statics.rs
src/test/incremental/hashes/struct_constructors.rs
src/test/incremental/hashes/struct_defs.rs
src/test/incremental/hashes/trait_defs.rs
src/test/incremental/hashes/trait_impls.rs
src/test/incremental/hashes/unary_and_binary_exprs.rs
src/test/incremental/hashes/while_let_loops.rs
src/test/incremental/hashes/while_loops.rs
src/test/incremental/spans_significant_w_debuginfo.rs
src/test/incremental/spans_significant_w_panic.rs
src/test/incremental/string_constant.rs
src/test/incremental/thinlto/cgu_keeps_identical_fn.rs
src/test/mir-opt/inline/cycle.g.Inline.diff
src/test/mir-opt/inline/cycle.main.Inline.diff
src/test/mir-opt/inline/exponential_runtime.main.Inline.diff
src/test/mir-opt/inline/inline_cycle.one.Inline.diff
src/test/mir-opt/inline/inline_cycle.two.Inline.diff
src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
src/test/mir-opt/inline/inline_diverging.h.Inline.diff
src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
src/test/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir [new file with mode: 0644]
src/test/mir-opt/simple_option_map_e2e.rs [new file with mode: 0644]
src/test/run-make-fulldeps/save-analysis/foo.rs
src/test/rustdoc-gui/docblock-table.goml
src/test/rustdoc-gui/source-code-page.goml
src/test/rustdoc-json/enums/discriminant/basic.rs
src/test/rustdoc-json/enums/discriminant/expr.rs
src/test/rustdoc-json/enums/discriminant/limits.rs
src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs
src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs
src/test/rustdoc-json/enums/discriminant/struct.rs [new file with mode: 0644]
src/test/rustdoc-json/enums/discriminant/tuple.rs [new file with mode: 0644]
src/test/rustdoc-json/enums/field_hidden.rs
src/test/rustdoc-json/enums/kind.rs
src/test/rustdoc-json/enums/struct_field_hidden.rs
src/test/rustdoc-json/enums/tuple_fields_hidden.rs
src/test/rustdoc-json/enums/variant_struct.rs
src/test/rustdoc-json/enums/variant_tuple_struct.rs
src/test/rustdoc-ui/issue-105334.rs [new file with mode: 0644]
src/test/rustdoc-ui/issue-105334.stderr [new file with mode: 0644]
src/test/rustdoc-ui/issue-105737.rs [new file with mode: 0644]
src/test/rustdoc-ui/issue-105737.stderr [new file with mode: 0644]
src/test/rustdoc-ui/issue-105742.rs [new file with mode: 0644]
src/test/rustdoc-ui/issue-105742.stderr [new file with mode: 0644]
src/test/rustdoc-ui/issue-106226.rs [new file with mode: 0644]
src/test/rustdoc-ui/issue-106226.stderr [new file with mode: 0644]
src/test/rustdoc-ui/issue-96287.rs [new file with mode: 0644]
src/test/rustdoc-ui/issue-96287.stderr [new file with mode: 0644]
src/test/ui-fulldeps/deriving-encodable-decodable-box.rs
src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs
src/test/ui-fulldeps/deriving-global.rs
src/test/ui-fulldeps/deriving-hygiene.rs
src/test/ui-fulldeps/dropck_tarena_sound_drop.rs
src/test/ui-fulldeps/empty-struct-braces-derive.rs
src/test/ui-fulldeps/issue-14021.rs
src/test/ui-fulldeps/missing-rustc-driver-error.rs [new file with mode: 0644]
src/test/ui-fulldeps/missing-rustc-driver-error.stderr [new file with mode: 0644]
src/test/ui-fulldeps/mod_dir_path_canonicalized.rs
src/test/ui-fulldeps/pprust-expr-roundtrip.rs
src/test/ui-fulldeps/regions-mock-tcx.rs
src/test/ui-fulldeps/rustc_encodable_hygiene.rs
src/test/ui/asm/aarch64/type-check-2-2.rs
src/test/ui/asm/aarch64/type-check-2-2.stderr
src/test/ui/asm/x86_64/type-check-5.rs
src/test/ui/asm/x86_64/type-check-5.stderr
src/test/ui/async-await/issue-61452.stderr
src/test/ui/async-await/issues/issue-61187.stderr
src/test/ui/augmented-assignments.rs
src/test/ui/augmented-assignments.stderr
src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr
src/test/ui/borrowck/borrowck-access-permissions.stderr
src/test/ui/borrowck/borrowck-argument.stderr
src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr
src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr
src/test/ui/borrowck/borrowck-borrow-from-stack-variable.stderr
src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr
src/test/ui/borrowck/borrowck-drop-from-guard.rs
src/test/ui/borrowck/borrowck-drop-from-guard.stderr
src/test/ui/borrowck/borrowck-mut-addr-of-imm-var.stderr
src/test/ui/borrowck/borrowck-mut-slice-of-imm-vec.stderr
src/test/ui/borrowck/borrowck-mutate-in-guard.rs
src/test/ui/borrowck/borrowck-mutate-in-guard.stderr
src/test/ui/borrowck/borrowck-overloaded-call.stderr
src/test/ui/borrowck/borrowck-ref-mut-of-imm.stderr
src/test/ui/borrowck/borrowck-unboxed-closures.stderr
src/test/ui/borrowck/immut-function-arguments.stderr
src/test/ui/borrowck/issue-31287-drop-in-guard.rs
src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr
src/test/ui/borrowck/many-mutable-borrows.rs [new file with mode: 0644]
src/test/ui/borrowck/many-mutable-borrows.stderr [new file with mode: 0644]
src/test/ui/borrowck/mut-borrow-of-mut-ref.rs
src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr
src/test/ui/borrowck/mutability-errors.rs
src/test/ui/borrowck/mutability-errors.stderr
src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr
src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr
src/test/ui/closures/issue-80313-mutable-borrow-in-closure.stderr
src/test/ui/closures/issue-80313-mutable-borrow-in-move-closure.stderr
src/test/ui/closures/issue-80313-mutation-in-closure.stderr
src/test/ui/closures/issue-80313-mutation-in-move-closure.stderr
src/test/ui/closures/issue-81700-mut-borrow.stderr
src/test/ui/closures/issue-82438-mut-without-upvar.stderr
src/test/ui/closures/issue-84044-drop-non-mut.stderr
src/test/ui/codemap_tests/huge_multispan_highlight.stderr
src/test/ui/did_you_mean/issue-35937.stderr
src/test/ui/did_you_mean/issue-39544.stderr
src/test/ui/dyn-star/align.normal.stderr
src/test/ui/dyn-star/align.over_aligned.stderr
src/test/ui/dyn-star/dispatch-on-pin-mut.stderr
src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr
src/test/ui/dyn-star/feature-gate-dyn_star.stderr
src/test/ui/dyn-star/no-explicit-dyn-star-cast.stderr
src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
src/test/ui/dyn-star/return.stderr
src/test/ui/dyn-star/upcast.stderr
src/test/ui/error-codes/E0596.stderr
src/test/ui/fmt/ifmt-bad-arg.stderr
src/test/ui/fmt/issue-89173.rs
src/test/ui/fmt/issue-89173.stderr
src/test/ui/issues/issue-29723.rs
src/test/ui/issues/issue-29723.stderr
src/test/ui/issues/issue-36400.stderr
src/test/ui/issues/issue-67535.rs [new file with mode: 0644]
src/test/ui/issues/issue-67535.stderr [new file with mode: 0644]
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.stderr
src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr
src/test/ui/macros/format-foreign.stderr
src/test/ui/macros/format-unused-lables.stderr
src/test/ui/macros/issue-92267.stderr
src/test/ui/macros/span-covering-argument-1.stderr
src/test/ui/mut/mut-suggestion.rs
src/test/ui/mut/mut-suggestion.stderr
src/test/ui/mut/mutable-class-fields.stderr
src/test/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs
src/test/ui/nll/issue-27282-move-match-input-into-guard.rs
src/test/ui/nll/issue-27282-move-match-input-into-guard.stderr
src/test/ui/nll/issue-27282-move-ref-mut-into-guard.rs
src/test/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
src/test/ui/nll/issue-27282-mutation-in-guard.rs
src/test/ui/nll/issue-27282-mutation-in-guard.stderr
src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs
src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr
src/test/ui/nll/issue-51191.stderr
src/test/ui/nll/match-cfg-fake-edges.rs
src/test/ui/nll/match-cfg-fake-edges.stderr
src/test/ui/nll/match-guards-always-borrow.rs
src/test/ui/nll/match-guards-always-borrow.stderr
src/test/ui/nll/match-guards-partially-borrow.rs
src/test/ui/nll/match-guards-partially-borrow.stderr
src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr
src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs
src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr
src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs
src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr
src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr
src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
src/test/ui/span/borrowck-object-mutability.stderr
src/test/ui/thir-tree.stdout
src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr
src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-missing-mut.stderr
src/test/ui/unboxed-closures/unboxed-closures-infer-fnmut-move-missing-mut.stderr
src/test/ui/unsafe/auxiliary/issue-106126.rs [new file with mode: 0644]
src/test/ui/unsafe/issue-106126-good-path-bug.rs [new file with mode: 0644]
src/test/ui/writing-to-immutable-vec.stderr
src/tools/jsondoclint/src/validator.rs
src/tools/miri/src/lib.rs
src/tools/rustfmt/src/lib.rs
src/tools/tidy/Cargo.toml
src/tools/tidy/src/lib.rs
src/tools/tidy/src/main.rs
src/tools/tidy/src/ui_tests.rs
src/tools/tidy/src/x_version.rs [new file with mode: 0644]
src/tools/x/src/main.rs

index f99e58e59b8e55d48bcb40f6153be3a1ed397531..4cb64882cb7e35f2c05a7a392621eb7965f55738 100644 (file)
@@ -4805,18 +4805,18 @@ checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af"
 
 [[package]]
 name = "semver"
-version = "1.0.12"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
+checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.147"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
 dependencies = [
  "serde_derive",
 ]
@@ -4833,9 +4833,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.147"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4853,9 +4853,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.85"
+version = "1.0.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
+checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
 dependencies = [
  "indexmap",
  "itoa",
@@ -5133,9 +5133,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.102"
+version = "1.0.107"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5309,6 +5309,7 @@ dependencies = [
  "lazy_static",
  "miropt-test-tools",
  "regex",
+ "semver",
  "termcolor",
  "walkdir",
 ]
index 9cc81f391672e8b8dc561068f536c427b04e6a1a..c1b26ca0925380293e9fca902bf60119b53d4dcf 100644 (file)
@@ -2743,8 +2743,19 @@ pub fn span_with_attributes(&self) -> Span {
 /// `extern` qualifier on a function item or function type.
 #[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub enum Extern {
+    /// No explicit extern keyword was used
+    ///
+    /// E.g. `fn foo() {}`
     None,
+    /// An explicit extern keyword was used, but with implicit ABI
+    ///
+    /// E.g. `extern fn foo() {}`
+    ///
+    /// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`)
     Implicit(Span),
+    /// An explicit extern keyword was used with an explicit ABI
+    ///
+    /// E.g. `extern "C" fn foo() {}`
     Explicit(StrLit, Span),
 }
 
@@ -2763,9 +2774,13 @@ pub fn from_abi(abi: Option<StrLit>, span: Span) -> Extern {
 /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
 #[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub struct FnHeader {
+    /// The `unsafe` keyword, if any
     pub unsafety: Unsafe,
+    /// The `async` keyword, if any
     pub asyncness: Async,
+    /// The `const` keyword, if any
     pub constness: Const,
+    /// The `extern` keyword and corresponding ABI string, if any
     pub ext: Extern,
 }
 
index c9d7477b5283670d3bd91caf8970383266b85e3b..83174afdb12ef907cc8cc81ed094612abe3f449e 100644 (file)
@@ -776,7 +776,7 @@ fn mark_span_with_reason(
     /// Intercept all spans entering HIR.
     /// Mark a span as relative to the current owning item.
     fn lower_span(&self, span: Span) -> Span {
-        if self.tcx.sess.opts.unstable_opts.incremental_relative_spans {
+        if self.tcx.sess.opts.incremental_relative_spans() {
             span.with_parent(Some(self.current_hir_id_owner.def_id))
         } else {
             // Do not make spans relative when not using incremental compilation.
index 01be379120dc7483c088daa4005b744bb386dfb8..e4942f9b666e0e837389503cd2d1099895b318da 100644 (file)
@@ -12,7 +12,7 @@ pub(crate) fn cannot_move_when_borrowed(
         place: &str,
         borrow_place: &str,
         value_place: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         self.infcx.tcx.sess.create_err(crate::session_diagnostics::MoveBorrow {
             place,
             span,
@@ -28,7 +28,7 @@ pub(crate) fn cannot_use_when_mutably_borrowed(
         desc: &str,
         borrow_span: Span,
         borrow_desc: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let mut err = struct_span_err!(
             self,
             span,
@@ -50,7 +50,7 @@ pub(crate) fn cannot_mutably_borrow_multiply(
         old_loan_span: Span,
         old_opt_via: &str,
         old_load_end_span: Option<Span>,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let via =
             |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) };
         let mut err = struct_span_err!(
@@ -98,7 +98,7 @@ pub(crate) fn cannot_uniquely_borrow_by_two_closures(
         desc: &str,
         old_loan_span: Span,
         old_load_end_span: Option<Span>,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let mut err = struct_span_err!(
             self,
             new_loan_span,
@@ -269,7 +269,7 @@ pub(crate) fn cannot_assign(
         &self,
         span: Span,
         desc: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         struct_span_err!(self, span, E0594, "cannot assign to {}", desc)
     }
 
@@ -348,7 +348,7 @@ pub(crate) fn cannot_borrow_path_as_mutable_because(
         span: Span,
         path: &str,
         reason: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,)
     }
 
@@ -359,7 +359,7 @@ pub(crate) fn cannot_mutate_in_immutable_section(
         immutable_place: &str,
         immutable_section: &str,
         action: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let mut err = struct_span_err!(
             self,
             mutate_span,
@@ -378,7 +378,7 @@ pub(crate) fn cannot_borrow_across_generator_yield(
         &self,
         span: Span,
         yield_span: Span,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let mut err = struct_span_err!(
             self,
             span,
@@ -392,7 +392,7 @@ pub(crate) fn cannot_borrow_across_generator_yield(
     pub(crate) fn cannot_borrow_across_destructor(
         &self,
         borrow_span: Span,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         struct_span_err!(
             self,
             borrow_span,
@@ -405,7 +405,7 @@ pub(crate) fn path_does_not_live_long_enough(
         &self,
         span: Span,
         path: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         struct_span_err!(self, span, E0597, "{} does not live long enough", path,)
     }
 
@@ -415,7 +415,7 @@ pub(crate) fn cannot_return_reference_to_local(
         return_kind: &str,
         reference_desc: &str,
         path_desc: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let mut err = struct_span_err!(
             self,
             span,
@@ -440,7 +440,7 @@ pub(crate) fn cannot_capture_in_long_lived_closure(
         closure_kind: &str,
         borrowed_path: &str,
         capture_span: Span,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let mut err = struct_span_err!(
             self,
             closure_span,
@@ -458,14 +458,14 @@ pub(crate) fn cannot_capture_in_long_lived_closure(
     pub(crate) fn thread_local_value_does_not_live_long_enough(
         &self,
         span: Span,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",)
     }
 
     pub(crate) fn temporary_value_borrowed_for_too_long(
         &self,
         span: Span,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",)
     }
 
index 3c3cb8c6b9c2ac4fa1eaeebdff4fc9f64dce5805..50cd13a2ccc8a462b28d35faddb94998e00efa93 100644 (file)
@@ -527,26 +527,21 @@ fn report_use_of_uninitialized(
             // that are *partially* initialized by assigning to a field of an uninitialized
             // binding. We differentiate between them for more accurate wording here.
             "isn't fully initialized"
-        } else if spans
-            .iter()
-            .filter(|i| {
-                // We filter these to avoid misleading wording in cases like the following,
-                // where `x` has an `init`, but it is in the same place we're looking at:
-                // ```
-                // let x;
-                // x += 1;
-                // ```
-                !i.contains(span)
-                    // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`
-                        && !visitor
-                            .errors
-                            .iter()
-                            .map(|(sp, _)| *sp)
-                            .any(|sp| span < sp && !sp.contains(span))
-            })
-            .count()
-            == 0
-        {
+        } else if !spans.iter().any(|i| {
+            // We filter these to avoid misleading wording in cases like the following,
+            // where `x` has an `init`, but it is in the same place we're looking at:
+            // ```
+            // let x;
+            // x += 1;
+            // ```
+            !i.contains(span)
+            // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`
+            && !visitor
+                .errors
+                .iter()
+                .map(|(sp, _)| *sp)
+                .any(|sp| span < sp && !sp.contains(span))
+        }) {
             show_assign_sugg = true;
             "isn't initialized"
         } else {
index 99ca4c637bd2e2c01e0407d1effa455e74292049..6f6d1b01bd4294a7f95195f858e0266a8a6f9c45 100644 (file)
@@ -180,6 +180,9 @@ pub(crate) fn report_mutability_error(
         // the verbs used in some diagnostic messages.
         let act;
         let acted_on;
+        let mut suggest = true;
+        let mut mut_error = None;
+        let mut count = 1;
 
         let span = match error_access {
             AccessKind::Mutate => {
@@ -194,15 +197,50 @@ pub(crate) fn report_mutability_error(
 
                 let borrow_spans = self.borrow_spans(span, location);
                 let borrow_span = borrow_spans.args_or_use();
-                err = self.cannot_borrow_path_as_mutable_because(borrow_span, &item_msg, &reason);
-                borrow_spans.var_span_label(
-                    &mut err,
-                    format!(
-                        "mutable borrow occurs due to use of {} in closure",
-                        self.describe_any_place(access_place.as_ref()),
-                    ),
-                    "mutable",
-                );
+                match the_place_err {
+                    PlaceRef { local, projection: [] }
+                        if self.body.local_decls[local].can_be_made_mutable() =>
+                    {
+                        let span = self.body.local_decls[local].source_info.span;
+                        mut_error = Some(span);
+                        if let Some((buffer, c)) = self.get_buffered_mut_error(span) {
+                            // We've encountered a second (or more) attempt to mutably borrow an
+                            // immutable binding, so the likely problem is with the binding
+                            // declaration, not the use. We collect these in a single diagnostic
+                            // and make the binding the primary span of the error.
+                            err = buffer;
+                            count = c + 1;
+                            if count == 2 {
+                                err.replace_span_with(span, false);
+                                err.span_label(span, "not mutable");
+                            }
+                            suggest = false;
+                        } else {
+                            err = self.cannot_borrow_path_as_mutable_because(
+                                borrow_span,
+                                &item_msg,
+                                &reason,
+                            );
+                        }
+                    }
+                    _ => {
+                        err = self.cannot_borrow_path_as_mutable_because(
+                            borrow_span,
+                            &item_msg,
+                            &reason,
+                        );
+                    }
+                }
+                if suggest {
+                    borrow_spans.var_span_label(
+                        &mut err,
+                        format!(
+                            "mutable borrow occurs due to use of {} in closure",
+                            self.describe_any_place(access_place.as_ref()),
+                        ),
+                        "mutable",
+                    );
+                }
                 borrow_span
             }
         };
@@ -276,7 +314,9 @@ pub(crate) fn report_mutability_error(
                                 pat_span: _,
                             },
                         )))) => {
-                            err.span_note(sp, "the binding is already a mutable borrow");
+                            if suggest {
+                                err.span_note(sp, "the binding is already a mutable borrow");
+                            }
                         }
                         _ => {
                             err.span_note(
@@ -333,16 +373,20 @@ pub(crate) fn report_mutability_error(
                 let local_decl = &self.body.local_decls[local];
                 assert_eq!(local_decl.mutability, Mutability::Not);
 
-                err.span_label(span, format!("cannot {act}"));
-                err.span_suggestion(
-                    local_decl.source_info.span,
-                    "consider changing this to be mutable",
-                    format!("mut {}", self.local_names[local].unwrap()),
-                    Applicability::MachineApplicable,
-                );
-                let tcx = self.infcx.tcx;
-                if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
-                    self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+                if count < 10 {
+                    err.span_label(span, format!("cannot {act}"));
+                }
+                if suggest {
+                    err.span_suggestion_verbose(
+                        local_decl.source_info.span.shrink_to_lo(),
+                        "consider changing this to be mutable",
+                        "mut ".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                    let tcx = self.infcx.tcx;
+                    if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
+                        self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+                    }
                 }
             }
 
@@ -615,7 +659,11 @@ pub(crate) fn report_mutability_error(
             }
         }
 
-        self.buffer_error(err);
+        if let Some(span) = mut_error {
+            self.buffer_mut_error(span, err, count);
+        } else {
+            self.buffer_error(err);
+        }
     }
 
     fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) {
index bcc8afbfd952d15763d32cd6239c5c129ee8f35b..567a9814fccbf3dd712e61d39df4d198de855453 100644 (file)
@@ -4,9 +4,9 @@
 
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
+use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{self as hir, Item, ItemKind, Node};
 use rustc_infer::infer::{
     error_reporting::nice_region_error::{
         self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
@@ -291,71 +291,6 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
         outlives_suggestion.add_suggestion(self);
     }
 
-    fn get_impl_ident_and_self_ty_from_trait(
-        &self,
-        def_id: DefId,
-        trait_objects: &FxIndexSet<DefId>,
-    ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
-        let tcx = self.infcx.tcx;
-        match tcx.hir().get_if_local(def_id) {
-            Some(Node::ImplItem(impl_item)) => {
-                match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
-                {
-                    Some(Node::Item(Item {
-                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
-                        ..
-                    })) => Some((impl_item.ident, self_ty)),
-                    _ => None,
-                }
-            }
-            Some(Node::TraitItem(trait_item)) => {
-                let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
-                match tcx.hir().find_by_def_id(trait_did.def_id) {
-                    Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
-                        // The method being called is defined in the `trait`, but the `'static`
-                        // obligation comes from the `impl`. Find that `impl` so that we can point
-                        // at it in the suggestion.
-                        let trait_did = trait_did.to_def_id();
-                        match tcx
-                            .hir()
-                            .trait_impls(trait_did)
-                            .iter()
-                            .filter_map(|&impl_did| {
-                                match tcx.hir().get_if_local(impl_did.to_def_id()) {
-                                    Some(Node::Item(Item {
-                                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
-                                        ..
-                                    })) if trait_objects.iter().all(|did| {
-                                        // FIXME: we should check `self_ty` against the receiver
-                                        // type in the `UnifyReceiver` context, but for now, use
-                                        // this imperfect proxy. This will fail if there are
-                                        // multiple `impl`s for the same trait like
-                                        // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
-                                        // In that case, only the first one will get suggestions.
-                                        let mut traits = vec![];
-                                        let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
-                                        hir_v.visit_ty(self_ty);
-                                        !traits.is_empty()
-                                    }) =>
-                                    {
-                                        Some(self_ty)
-                                    }
-                                    _ => None,
-                                }
-                            })
-                            .next()
-                        {
-                            Some(self_ty) => Some((trait_item.ident, self_ty)),
-                            _ => None,
-                        }
-                    }
-                    _ => None,
-                }
-            }
-            _ => None,
-        }
-    }
-
     /// Report an error because the universal region `fr` was required to outlive
     /// `outlived_fr` but it is not known to do so. For example:
     ///
@@ -850,7 +785,7 @@ fn maybe_suggest_constrain_dyn_trait_impl(
         visitor.visit_ty(param.param_ty);
 
         let Some((ident, self_ty)) =
-            self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &visitor.0) else {return};
+            NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &visitor.0) else { return; };
 
         self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
     }
index 168b798788b4c747c7fad8e4db5337b5f36fceaf..ae1bea008b6cede53a067e4a3dddf619752478ce 100644 (file)
@@ -2270,6 +2270,7 @@ pub struct BorrowckErrors<'tcx> {
         /// same primary span come out in a consistent order.
         buffered_move_errors:
             BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>)>,
+        buffered_mut_errors: FxHashMap<Span, (DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)>,
         /// Diagnostics to be reported buffer.
         buffered: Vec<Diagnostic>,
         /// Set to Some if we emit an error during borrowck
@@ -2281,6 +2282,7 @@ pub fn new(tcx: TyCtxt<'tcx>) -> Self {
             BorrowckErrors {
                 tcx,
                 buffered_move_errors: BTreeMap::new(),
+                buffered_mut_errors: Default::default(),
                 buffered: Default::default(),
                 tainted_by_errors: None,
             }
@@ -2331,12 +2333,34 @@ pub fn buffer_move_error(
             }
         }
 
+        pub fn get_buffered_mut_error(
+            &mut self,
+            span: Span,
+        ) -> Option<(DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)> {
+            self.errors.buffered_mut_errors.remove(&span)
+        }
+
+        pub fn buffer_mut_error(
+            &mut self,
+            span: Span,
+            t: DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+            count: usize,
+        ) {
+            self.errors.buffered_mut_errors.insert(span, (t, count));
+        }
+
         pub fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
             // Buffer any move errors that we collected and de-duplicated.
             for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
                 // We have already set tainted for this error, so just buffer it.
                 diag.buffer(&mut self.errors.buffered);
             }
+            for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
+                if count > 10 {
+                    diag.note(&format!("...and {} other attempted mutable borrows", count - 10));
+                }
+                diag.buffer(&mut self.errors.buffered);
+            }
 
             if !self.errors.buffered.is_empty() {
                 self.errors.buffered.sort_by_key(|diag| diag.sort_span);
index 63bc0d552c11e7e24e17bbb45ff095590fd1f18b..b2b7b9d75bd37163e9ac20a305ba9e19ac9366ef 100644 (file)
@@ -638,7 +638,7 @@ macro_rules! check_foreign {
                 if show_doc_note {
                     diag.note(concat!(
                         stringify!($kind),
-                        " formatting not supported; see the documentation for `std::fmt`",
+                        " formatting is not supported; see the documentation for `std::fmt`",
                     ));
                 }
                 if suggestions.len() > 0 {
index effb2de4827518c08360bed61995f5ffe3c86a58..a92242b2615c1f66b1cfb438c61a0bbf48ad0e97 100644 (file)
@@ -1244,7 +1244,7 @@ fn call(
     ) -> RValue<'gcc> {
         // FIXME(antoyo): remove when having a proper API.
         let gcc_func = unsafe { std::mem::transmute(func) };
-        let call = if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() {
+        let call = if self.functions.borrow().values().any(|value| *value == gcc_func) {
             self.function_call(func, args, funclet)
         }
         else {
index 837708aeb0ea9a42aa4a36aced6b7a19a40bddd3..4424b31c0542c65777d80571ebc85cafbdd1c925 100644 (file)
@@ -253,7 +253,7 @@ pub fn new(context: &'gcc Context<'gcc>, codegen_unit: &'tcx CodegenUnit<'tcx>,
 
     pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> {
         let function: Function<'gcc> = unsafe { std::mem::transmute(value) };
-        debug_assert!(self.functions.borrow().values().find(|value| **value == function).is_some(),
+        debug_assert!(self.functions.borrow().values().any(|value| *value == function),
             "{:?} ({:?}) is not a function", value, value.get_type());
         function
     }
index edde1537b81e19bcbde989104bf83592b4aff038..36f7e5954bf2ae30543932d264c1667c8fa65602 100644 (file)
@@ -2822,11 +2822,30 @@ fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
                     // Implement the "linker flavor" part of -Zgcc-ld
                     // by asking cc to use some kind of lld.
                     cmd.arg("-fuse-ld=lld");
+
                     if !flavor.is_gnu() {
                         // Tell clang to use a non-default LLD flavor.
                         // Gcc doesn't understand the target option, but we currently assume
                         // that gcc is not used for Apple and Wasm targets (#97402).
-                        cmd.arg(format!("--target={}", sess.target.llvm_target));
+                        //
+                        // Note that we don't want to do that by default on macOS: e.g. passing a
+                        // 10.7 target to LLVM works, but not to recent versions of clang/macOS, as
+                        // shown in issue #101653 and the discussion in PR #101792.
+                        //
+                        // It could be required in some cases of cross-compiling with
+                        // `-Zgcc-ld=lld`, but this is generally unspecified, and we don't know
+                        // which specific versions of clang, macOS SDK, host and target OS
+                        // combinations impact us here.
+                        //
+                        // So we do a simple first-approximation until we know more of what the
+                        // Apple targets require (and which would be handled prior to hitting this
+                        // `-Zgcc-ld=lld` codepath anyway), but the expectation is that until then
+                        // this should be manually passed if needed. We specify the target when
+                        // targeting a different linker flavor on macOS, and that's also always
+                        // the case when targeting WASM.
+                        if sess.target.linker_flavor != sess.host.linker_flavor {
+                            cmd.arg(format!("--target={}", sess.target.llvm_target));
+                        }
                     }
                 }
             }
index 05f059c89d5cd0fea01ea73e00e8d8419b4b3c9e..c63caa06818f26e2f3f263d778c140ae5fc588aa 100644 (file)
@@ -1,6 +1,7 @@
 use crate::stable_hasher::{HashStable, StableHasher, StableOrd};
 use std::borrow::Borrow;
 use std::cmp::Ordering;
+use std::fmt::Debug;
 use std::mem;
 use std::ops::{Bound, Index, IndexMut, RangeBounds};
 
@@ -16,7 +17,7 @@
 /// stores data in a more compact way. It also supports accessing contiguous
 /// ranges of elements as a slice, and slices of already sorted elements can be
 /// inserted efficiently.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
 pub struct SortedMap<K, V> {
     data: Vec<(K, V)>,
 }
@@ -314,5 +315,11 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
     }
 }
 
+impl<K: Debug, V: Debug> Debug for SortedMap<K, V> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_map().entries(self.data.iter().map(|(a, b)| (a, b))).finish()
+    }
+}
+
 #[cfg(test)]
 mod tests;
index b42b228bde9fa3329e04e6c2125049a22c598054..79b8b417257045a6b60f244acf4f4a0f7acc35d5 100644 (file)
@@ -4,6 +4,11 @@ metadata_rlib_required =
 metadata_lib_required =
     crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
 
+metadata_rustc_lib_required =
+    crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
+    .note = only .rmeta files are distributed for `rustc_private` crates other than `rustc_driver`
+    .help = try adding `extern crate rustc_driver;` at the top level of this crate
+
 metadata_crate_dep_multiple =
     cannot satisfy dependencies so `{$crate_name}` only shows up once
     .help = having upstream crates all available in one format will likely make this go away
index 585a54308c62e1c0bf07ab9c1478bd51ec0fca2c..e19a6fe0ee9bff2d5a0a5c28a7ace6c976c2fa9a 100644 (file)
@@ -365,12 +365,12 @@ pub fn span_labels(
         self
     }
 
-    pub fn replace_span_with(&mut self, after: Span) -> &mut Self {
+    pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
         let before = self.span.clone();
         self.set_span(after);
         for span_label in before.span_labels() {
             if let Some(label) = span_label.label {
-                if span_label.is_primary {
+                if span_label.is_primary && keep_label {
                     self.span.push_span_label(after, label);
                 } else {
                     self.span.push_span_label(span_label.span, label);
index 0455f0d7383ae67e9d50b7058b7853498c33b9bb..136c360201e61a925049b941997d039544c34e9f 100644 (file)
@@ -469,10 +469,12 @@ pub enum StashKey {
     CallAssocMethod,
 }
 
-fn default_track_diagnostic(_: &Diagnostic) {}
+fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
+    (*f)(d)
+}
 
-pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&Diagnostic)> =
-    AtomicRef::new(&(default_track_diagnostic as fn(&_)));
+pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&mut Diagnostic, &mut dyn FnMut(&mut Diagnostic))> =
+    AtomicRef::new(&(default_track_diagnostic as _));
 
 #[derive(Copy, Clone, Default)]
 pub struct HandlerFlags {
@@ -654,17 +656,19 @@ pub fn reset_err_count(&self) {
     /// Retrieve a stashed diagnostic with `steal_diagnostic`.
     pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
         let mut inner = self.inner.borrow_mut();
-        inner.stash((span, key), diag);
+        inner.stash((span.with_parent(None), key), diag);
     }
 
     /// Steal a previously stashed diagnostic with the given `Span` and [`StashKey`] as the key.
     pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> {
         let mut inner = self.inner.borrow_mut();
-        inner.steal((span, key)).map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
+        inner
+            .steal((span.with_parent(None), key))
+            .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
     }
 
     pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
-        self.inner.borrow().stashed_diagnostics.get(&(span, key)).is_some()
+        self.inner.borrow().stashed_diagnostics.get(&(span.with_parent(None), key)).is_some()
     }
 
     /// Emit all stashed diagnostics.
@@ -1293,67 +1297,69 @@ fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaran
             && !diagnostic.is_force_warn()
         {
             if diagnostic.has_future_breakage() {
-                (*TRACK_DIAGNOSTICS)(diagnostic);
+                (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
             }
             return None;
         }
 
-        (*TRACK_DIAGNOSTICS)(diagnostic);
-
         if matches!(diagnostic.level, Level::Expect(_) | Level::Allow) {
+            (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
             return None;
         }
 
-        if let Some(ref code) = diagnostic.code {
-            self.emitted_diagnostic_codes.insert(code.clone());
-        }
-
-        let already_emitted = |this: &mut Self| {
-            let mut hasher = StableHasher::new();
-            diagnostic.hash(&mut hasher);
-            let diagnostic_hash = hasher.finish();
-            !this.emitted_diagnostics.insert(diagnostic_hash)
-        };
+        let mut guaranteed = None;
+        (*TRACK_DIAGNOSTICS)(diagnostic, &mut |diagnostic| {
+            if let Some(ref code) = diagnostic.code {
+                self.emitted_diagnostic_codes.insert(code.clone());
+            }
 
-        // Only emit the diagnostic if we've been asked to deduplicate or
-        // haven't already emitted an equivalent diagnostic.
-        if !(self.flags.deduplicate_diagnostics && already_emitted(self)) {
-            debug!(?diagnostic);
-            debug!(?self.emitted_diagnostics);
-            let already_emitted_sub = |sub: &mut SubDiagnostic| {
-                debug!(?sub);
-                if sub.level != Level::OnceNote {
-                    return false;
-                }
+            let already_emitted = |this: &mut Self| {
                 let mut hasher = StableHasher::new();
-                sub.hash(&mut hasher);
+                diagnostic.hash(&mut hasher);
                 let diagnostic_hash = hasher.finish();
-                debug!(?diagnostic_hash);
-                !self.emitted_diagnostics.insert(diagnostic_hash)
+                !this.emitted_diagnostics.insert(diagnostic_hash)
             };
 
-            diagnostic.children.drain_filter(already_emitted_sub).for_each(|_| {});
-
-            self.emitter.emit_diagnostic(diagnostic);
-            if diagnostic.is_error() {
-                self.deduplicated_err_count += 1;
-            } else if let Warning(_) = diagnostic.level {
-                self.deduplicated_warn_count += 1;
+            // Only emit the diagnostic if we've been asked to deduplicate or
+            // haven't already emitted an equivalent diagnostic.
+            if !(self.flags.deduplicate_diagnostics && already_emitted(self)) {
+                debug!(?diagnostic);
+                debug!(?self.emitted_diagnostics);
+                let already_emitted_sub = |sub: &mut SubDiagnostic| {
+                    debug!(?sub);
+                    if sub.level != Level::OnceNote {
+                        return false;
+                    }
+                    let mut hasher = StableHasher::new();
+                    sub.hash(&mut hasher);
+                    let diagnostic_hash = hasher.finish();
+                    debug!(?diagnostic_hash);
+                    !self.emitted_diagnostics.insert(diagnostic_hash)
+                };
+
+                diagnostic.children.drain_filter(already_emitted_sub).for_each(|_| {});
+
+                self.emitter.emit_diagnostic(diagnostic);
+                if diagnostic.is_error() {
+                    self.deduplicated_err_count += 1;
+                } else if let Warning(_) = diagnostic.level {
+                    self.deduplicated_warn_count += 1;
+                }
             }
-        }
-        if diagnostic.is_error() {
-            if matches!(diagnostic.level, Level::Error { lint: true }) {
-                self.bump_lint_err_count();
+            if diagnostic.is_error() {
+                if matches!(diagnostic.level, Level::Error { lint: true }) {
+                    self.bump_lint_err_count();
+                } else {
+                    self.bump_err_count();
+                }
+
+                guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
             } else {
-                self.bump_err_count();
+                self.bump_warn_count();
             }
+        });
 
-            Some(ErrorGuaranteed::unchecked_claim_error_was_emitted())
-        } else {
-            self.bump_warn_count();
-
-            None
-        }
+        guaranteed
     }
 
     fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
index e26c16dcd7ee7784e4597cddbb6f073c9ea56657..5d47c1ed363fbf0463ddde0118bba718d9ca10ec 100644 (file)
@@ -587,7 +587,7 @@ fn collect_invocations(
                 .resolver
                 .visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment);
 
-            if self.cx.sess.opts.unstable_opts.incremental_relative_spans {
+            if self.cx.sess.opts.incremental_relative_spans() {
                 for (invoc, _) in invocations.iter_mut() {
                     let expn_id = invoc.expansion_data.id;
                     let parent_def = self.cx.resolver.invocation_parent(expn_id);
index 40aa64d9d40401719d595629467aaa9aa7544f44..3a38d7a966960bb8857ebe489d959a4cabdbe65f 100644 (file)
@@ -198,12 +198,12 @@ pub(super) fn emit_frag_parse_err(
         );
         if !e.span.is_dummy() {
             // early end of macro arm (#52866)
-            e.replace_span_with(parser.token.span.shrink_to_hi());
+            e.replace_span_with(parser.token.span.shrink_to_hi(), true);
         }
     }
     if e.span.is_dummy() {
         // Get around lack of span in error (#30128)
-        e.replace_span_with(site_span);
+        e.replace_span_with(site_span, true);
         if !parser.sess.source_map().is_imported(arm_span) {
             e.span_label(arm_span, "in this macro arm");
         }
index deb37bdebda638a77701537f008000a80452a4d6..beade4d44da84e6f4bb7610cf59e4c356fa51b85 100644 (file)
@@ -383,7 +383,7 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows `#[doc(masked)]`.
     (active, doc_masked, "1.21.0", Some(44027), None),
     /// Allows `dyn* Trait` objects.
-    (incomplete, dyn_star, "1.65.0", Some(91611), None),
+    (incomplete, dyn_star, "1.65.0", Some(102425), None),
     /// Allows `X..Y` patterns.
     (active, exclusive_range_pattern, "1.11.0", Some(37854), None),
     /// Allows exhaustive pattern matching on types that contain uninhabited types.
index e923ec26a488fda25f34d200c305d9cded23a676..034f06bb889b61f47022102f0fcfe8abe9d5d5cc 100644 (file)
@@ -854,7 +854,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 &self
                     .nodes
                     .iter_enumerated()
-                    .map(|(id, parented_node)| (id, parented_node.as_ref().map(|node| node.parent)))
+                    .map(|(id, parented_node)| {
+                        let parented_node = parented_node.as_ref().map(|node| node.parent);
+
+                        debug_fn(move |f| write!(f, "({id:?}, {parented_node:?})"))
+                    })
                     .collect::<Vec<_>>(),
             )
             .field("bodies", &self.bodies)
@@ -3615,3 +3619,13 @@ mod size_asserts {
     static_assert_size!(TyKind<'_>, 32);
     // tidy-alphabetical-end
 }
+
+fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Debug {
+    struct DebugFn<F>(F);
+    impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Debug for DebugFn<F> {
+        fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+            (self.0)(fmt)
+        }
+    }
+    DebugFn(f)
+}
index 03bcaa6946825baac7073958262ddd75f7bd3bf2..5d05adfb55654efb9184d872b62427aea6eefef3 100644 (file)
@@ -1,14 +1,21 @@
 use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_ID};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
 use rustc_span::{def_id::DefPathHash, HashStableContext};
-use std::fmt;
+use std::fmt::{self, Debug};
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[derive(Encodable, Decodable)]
 pub struct OwnerId {
     pub def_id: LocalDefId,
 }
 
+impl Debug for OwnerId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Example: DefId(0:1 ~ aa[7697]::{use#0})
+        Debug::fmt(&self.def_id, f)
+    }
+}
+
 impl From<OwnerId> for HirId {
     fn from(owner: OwnerId) -> HirId {
         HirId { owner, local_id: ItemLocalId::from_u32(0) }
@@ -60,7 +67,7 @@ fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
 /// the `local_id` part of the `HirId` changing, which is a very useful property in
 /// incremental compilation where we have to persist things through changes to
 /// the code base.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[derive(Encodable, Decodable, HashStable_Generic)]
 #[rustc_pass_by_value]
 pub struct HirId {
@@ -68,6 +75,14 @@ pub struct HirId {
     pub local_id: ItemLocalId,
 }
 
+impl Debug for HirId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Example: HirId(DefId(0:1 ~ aa[7697]::{use#0}).10)
+        // Don't use debug_tuple to always keep this on one line.
+        write!(f, "HirId({:?}.{:?})", self.owner, self.local_id)
+    }
+}
+
 impl HirId {
     /// Signal local id which should never be used.
     pub const INVALID: HirId =
index c6d4aeefc80e5e7883862065b6b6fe5fd63ba6d0..e8b3f139623ed56ce750a81dc1a6765f0fc2fd62 100644 (file)
@@ -53,7 +53,7 @@ fn do_orphan_check_impl<'tcx>(
             sp,
             item.span,
             tr.path.span,
-            trait_ref.self_ty(),
+            trait_ref,
             impl_.self_ty.span,
             &impl_.generics,
             err,
@@ -154,11 +154,12 @@ fn emit_orphan_check_error<'tcx>(
     sp: Span,
     full_impl_span: Span,
     trait_span: Span,
-    self_ty: Ty<'tcx>,
+    trait_ref: ty::TraitRef<'tcx>,
     self_ty_span: Span,
     generics: &hir::Generics<'tcx>,
     err: traits::OrphanCheckErr<'tcx>,
 ) -> Result<!, ErrorGuaranteed> {
+    let self_ty = trait_ref.self_ty();
     Err(match err {
         traits::OrphanCheckErr::NonLocalInputType(tys) => {
             let msg = match self_ty.kind() {
@@ -187,7 +188,14 @@ fn emit_orphan_check_error<'tcx>(
                 let msg = |ty: &str, postfix: &str| {
                     format!("{ty} is not defined in the current crate{postfix}")
                 };
-                let this = |name: &str| msg("this", &format!(" because {name} are always foreign"));
+
+                let this = |name: &str| {
+                    if !trait_ref.def_id.is_local() && !is_target_ty {
+                        msg("this", &format!(" because this is a foreign trait"))
+                    } else {
+                        msg("this", &format!(" because {name} are always foreign"))
+                    }
+                };
                 let msg = match &ty.kind() {
                     ty::Slice(_) => this("slices"),
                     ty::Array(..) => this("arrays"),
index ae641b26eeedbb48898bb1019e747c217b57833a..b8b4e873663100fbc3820820333ed3409ec67557 100644 (file)
@@ -395,7 +395,7 @@ fn check_expr_unary(
                             E0614,
                             "type `{oprnd_t}` cannot be dereferenced",
                         );
-                        let sp = tcx.sess.source_map().start_point(expr.span);
+                        let sp = tcx.sess.source_map().start_point(expr.span).with_parent(None);
                         if let Some(sp) =
                             tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
                         {
index e38d1bccc10657199fcc4ff2515c2136867a19d2..322e11c978f48cd3ef2026a07e30f6228678b97d 100644 (file)
@@ -974,7 +974,7 @@ pub(in super::super) fn suggest_missing_parentheses(
         err: &mut Diagnostic,
         expr: &hir::Expr<'_>,
     ) -> bool {
-        let sp = self.tcx.sess.source_map().start_point(expr.span);
+        let sp = self.tcx.sess.source_map().start_point(expr.span).with_parent(None);
         if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
             // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
             err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
index b06927f9662be7aeb09882ab6b7ec860a1a94061..cecf3d3f1e0644c2656924a4e4aa10cf13f9a7bc 100644 (file)
@@ -240,10 +240,8 @@ fn typeck_with_fallback<'tcx>(
                         }),
                         Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
                         | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
-                            let operand_ty = asm
-                                .operands
-                                .iter()
-                                .filter_map(|(op, _op_sp)| match op {
+                            let operand_ty =
+                                asm.operands.iter().find_map(|(op, _op_sp)| match op {
                                     hir::InlineAsmOperand::Const { anon_const }
                                         if anon_const.hir_id == id =>
                                     {
@@ -259,8 +257,7 @@ fn typeck_with_fallback<'tcx>(
                                         }))
                                     }
                                     _ => None,
-                                })
-                                .next();
+                                });
                             operand_ty.unwrap_or_else(fallback)
                         }
                         _ => fallback(),
index dea14dd93d6acd15e0ec4199ad0f677b5461ce6b..3d6c2119bea333e568dbd49f026bd343f1bdb32c 100644 (file)
@@ -341,8 +341,7 @@ fn trait_path(&self, span: Span, expr_hir_id: HirId, trait_def_id: DefId) -> Opt
         // Find an identifier with which this trait was imported (note that `_` doesn't count).
         let any_id = import_items
             .iter()
-            .filter_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None })
-            .next();
+            .find_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None });
         if let Some(any_id) = any_id {
             if any_id.name == Empty {
                 // Glob import, so just use its name.
index 1afaae0e0209dfa9c176b69259ba9e92bda286cc..2daf1979ee5e69d51642a7588f38aa29d6a12272 100644 (file)
@@ -1111,7 +1111,7 @@ fn pick_all_method(
                 // a raw pointer
                 !step.self_ty.references_error() && !step.from_unsafe_deref
             })
-            .flat_map(|step| {
+            .find_map(|step| {
                 let InferOk { value: self_ty, obligations: _ } = self
                     .fcx
                     .probe_instantiate_query_response(
@@ -1147,7 +1147,6 @@ fn pick_all_method(
                         })
                     })
             })
-            .next()
     }
 
     /// For each type `T` in the step list, this attempts to find a method where
index aa68929517842fca62c153aebf727486cb04b8a3..b04ef55a994ea61dbdcf7c36c98d48b55462f245 100644 (file)
@@ -102,7 +102,7 @@ fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
 
     pub fn report_method_error(
         &self,
-        mut span: Span,
+        span: Span,
         rcvr_ty: Ty<'tcx>,
         item_name: Ident,
         source: SelfSource<'tcx>,
@@ -114,144 +114,6 @@ pub fn report_method_error(
             return None;
         }
 
-        let report_candidates = |span: Span,
-                                 err: &mut Diagnostic,
-                                 sources: &mut Vec<CandidateSource>,
-                                 sugg_span: Option<Span>| {
-            sources.sort();
-            sources.dedup();
-            // Dynamic limit to avoid hiding just one candidate, which is silly.
-            let limit = if sources.len() == 5 { 5 } else { 4 };
-
-            for (idx, source) in sources.iter().take(limit).enumerate() {
-                match *source {
-                    CandidateSource::Impl(impl_did) => {
-                        // Provide the best span we can. Use the item, if local to crate, else
-                        // the impl, if local to crate (item may be defaulted), else nothing.
-                        let 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)
-                        }) else {
-                            continue;
-                        };
-
-                        let note_span = if item.def_id.is_local() {
-                            Some(self.tcx.def_span(item.def_id))
-                        } else if impl_did.is_local() {
-                            Some(self.tcx.def_span(impl_did))
-                        } else {
-                            None
-                        };
-
-                        let impl_ty = self.tcx.at(span).type_of(impl_did);
-
-                        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)
-                            ),
-                        };
-
-                        let (note_str, idx) = if sources.len() > 1 {
-                            (
-                                format!(
-                                    "candidate #{} is defined in an impl{} for the type `{}`",
-                                    idx + 1,
-                                    insertion,
-                                    impl_ty,
-                                ),
-                                Some(idx + 1),
-                            )
-                        } else {
-                            (
-                                format!(
-                                    "the candidate is defined in an impl{} for the type `{}`",
-                                    insertion, impl_ty,
-                                ),
-                                None,
-                            )
-                        };
-                        if let Some(note_span) = note_span {
-                            // We have a span pointing to the method. Show note with snippet.
-                            err.span_note(note_span, &note_str);
-                        } else {
-                            err.note(&note_str);
-                        }
-                        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 ty = match item.kind {
-                                ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
-                                ty::AssocKind::Fn => self
-                                    .tcx
-                                    .fn_sig(item.def_id)
-                                    .inputs()
-                                    .skip_binder()
-                                    .get(0)
-                                    .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
-                                    .copied()
-                                    .unwrap_or(rcvr_ty),
-                            };
-                            print_disambiguation_help(
-                                item_name,
-                                args,
-                                err,
-                                path,
-                                ty,
-                                item.kind,
-                                item.def_id,
-                                sugg_span,
-                                idx,
-                                self.tcx.sess.source_map(),
-                                item.fn_has_self_parameter,
-                            );
-                        }
-                    }
-                    CandidateSource::Trait(trait_did) => {
-                        let Some(item) = self.associated_value(trait_did, item_name) else { continue };
-                        let item_span = self.tcx.def_span(item.def_id);
-                        let idx = if sources.len() > 1 {
-                            let msg = &format!(
-                                "candidate #{} is defined in the trait `{}`",
-                                idx + 1,
-                                self.tcx.def_path_str(trait_did)
-                            );
-                            err.span_note(item_span, msg);
-                            Some(idx + 1)
-                        } else {
-                            let msg = &format!(
-                                "the candidate is defined in the trait `{}`",
-                                self.tcx.def_path_str(trait_did)
-                            );
-                            err.span_note(item_span, msg);
-                            None
-                        };
-                        if let Some(sugg_span) = sugg_span {
-                            let path = self.tcx.def_path_str(trait_did);
-                            print_disambiguation_help(
-                                item_name,
-                                args,
-                                err,
-                                path,
-                                rcvr_ty,
-                                item.kind,
-                                item.def_id,
-                                sugg_span,
-                                idx,
-                                self.tcx.sess.source_map(),
-                                item.fn_has_self_parameter,
-                            );
-                        }
-                    }
-                }
-            }
-            if sources.len() > limit {
-                err.note(&format!("and {} others", sources.len() - limit));
-            }
-        };
-
         let sugg_span = if let SelfSource::MethodCall(expr) = source {
             // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
             self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span
@@ -260,775 +122,16 @@ pub fn report_method_error(
         };
 
         match error {
-            MethodError::NoMatch(NoMatchData {
-                mut static_candidates,
-                unsatisfied_predicates,
-                out_of_scope_traits,
-                lev_candidate,
-                mode,
-            }) => {
-                let tcx = self.tcx;
-
-                let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
-                let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
-                let is_method = mode == Mode::MethodCall;
-                let item_kind = if is_method {
-                    "method"
-                } else if rcvr_ty.is_enum() {
-                    "variant or associated item"
-                } else {
-                    match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
-                        (Some(name), false) if name.is_lowercase() => "function or associated item",
-                        (Some(_), false) => "associated item",
-                        (Some(_), true) | (None, false) => "variant or associated item",
-                        (None, true) => "variant",
-                    }
-                };
-
-                if self.suggest_wrapping_range_with_parens(
-                    tcx, rcvr_ty, source, span, item_name, &ty_str,
-                ) || self.suggest_constraining_numerical_ty(
-                    tcx, rcvr_ty, source, span, item_kind, item_name, &ty_str,
-                ) {
-                    return None;
-                }
-                span = item_name.span;
-
-                // Don't show generic arguments when the method can't be found in any implementation (#81576).
-                let mut ty_str_reported = ty_str.clone();
-                if let ty::Adt(_, generics) = rcvr_ty.kind() {
-                    if generics.len() > 0 {
-                        let mut autoderef = self.autoderef(span, rcvr_ty);
-                        let candidate_found = autoderef.any(|(ty, _)| {
-                            if let ty::Adt(adt_def, _) = ty.kind() {
-                                self.tcx
-                                    .inherent_impls(adt_def.did())
-                                    .iter()
-                                    .filter_map(|def_id| self.associated_value(*def_id, item_name))
-                                    .count()
-                                    >= 1
-                            } else {
-                                false
-                            }
-                        });
-                        let has_deref = autoderef.step_count() > 0;
-                        if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
-                            if let Some((path_string, _)) = ty_str.split_once('<') {
-                                ty_str_reported = path_string.to_string();
-                            }
-                        }
-                    }
-                }
-
-                let mut err = struct_span_err!(
-                    tcx.sess,
+            MethodError::NoMatch(mut no_match_data) => {
+                return self.report_no_match_method_error(
                     span,
-                    E0599,
-                    "no {} named `{}` found for {} `{}` in the current scope",
-                    item_kind,
+                    rcvr_ty,
                     item_name,
-                    rcvr_ty.prefix_string(self.tcx),
-                    ty_str_reported,
+                    source,
+                    args,
+                    sugg_span,
+                    &mut no_match_data,
                 );
-                if rcvr_ty.references_error() {
-                    err.downgrade_to_delayed_bug();
-                }
-
-                if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
-                    self.suggest_await_before_method(
-                        &mut err, item_name, rcvr_ty, cal, span,
-                    );
-                }
-                if let Some(span) = tcx.resolutions(()).confused_type_with_std_module.get(&span) {
-                    err.span_suggestion(
-                        span.shrink_to_lo(),
-                        "you are looking for the module in `std`, not the primitive type",
-                        "std::",
-                        Applicability::MachineApplicable,
-                    );
-                }
-                if let ty::RawPtr(_) = &rcvr_ty.kind() {
-                    err.note(
-                        "try using `<*const T>::as_ref()` to get a reference to the \
-                         type behind the pointer: https://doc.rust-lang.org/std/\
-                         primitive.pointer.html#method.as_ref",
-                    );
-                    err.note(
-                        "using `<*const T>::as_ref()` on a pointer which is unaligned or points \
-                         to invalid or uninitialized memory is undefined behavior",
-                    );
-                }
-
-                let ty_span = match rcvr_ty.kind() {
-                    ty::Param(param_type) => Some(
-                        param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()),
-                    ),
-                    ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
-                    _ => None,
-                };
-                if let Some(span) = ty_span {
-                    err.span_label(
-                        span,
-                        format!(
-                            "{item_kind} `{item_name}` not found for this {}",
-                            rcvr_ty.prefix_string(self.tcx)
-                        ),
-                    );
-                }
-
-                if let SelfSource::MethodCall(rcvr_expr) = source {
-                    self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
-                        let call_expr = self
-                            .tcx
-                            .hir()
-                            .expect_expr(self.tcx.hir().get_parent_node(rcvr_expr.hir_id));
-                        let probe = self.lookup_probe(
-                            item_name,
-                            output_ty,
-                            call_expr,
-                            ProbeScope::AllTraits,
-                        );
-                        probe.is_ok()
-                    });
-                }
-
-                let mut custom_span_label = false;
-
-                if !static_candidates.is_empty() {
-                    err.note(
-                        "found the following associated functions; to be used as methods, \
-                         functions must have a `self` parameter",
-                    );
-                    err.span_label(span, "this is an associated function, not a method");
-                    custom_span_label = true;
-                }
-                if static_candidates.len() == 1 {
-                    self.suggest_associated_call_syntax(
-                        &mut err,
-                        &static_candidates,
-                        rcvr_ty,
-                        source,
-                        item_name,
-                        args,
-                        sugg_span,
-                    );
-
-                    report_candidates(span, &mut err, &mut static_candidates, None);
-                } else if static_candidates.len() > 1 {
-                    report_candidates(span, &mut err, &mut static_candidates, Some(sugg_span));
-                }
-
-                let mut bound_spans = vec![];
-                let mut restrict_type_params = false;
-                let mut unsatisfied_bounds = false;
-                if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
-                    let msg = "consider using `len` instead";
-                    if let SelfSource::MethodCall(_expr) = source {
-                        err.span_suggestion_short(
-                            span,
-                            msg,
-                            "len",
-                            Applicability::MachineApplicable,
-                        );
-                    } else {
-                        err.span_label(span, msg);
-                    }
-                    if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
-                        let iterator_trait = self.tcx.def_path_str(iterator_trait);
-                        err.note(&format!("`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"));
-                    }
-                } else if !unsatisfied_predicates.is_empty() {
-                    let mut type_params = FxHashMap::default();
-
-                    // Pick out the list of unimplemented traits on the receiver.
-                    // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
-                    let mut unimplemented_traits = FxHashMap::default();
-                    let mut unimplemented_traits_only = true;
-                    for (predicate, _parent_pred, cause) in &unsatisfied_predicates {
-                        if let (ty::PredicateKind::Clause(ty::Clause::Trait(p)), Some(cause)) =
-                            (predicate.kind().skip_binder(), cause.as_ref())
-                        {
-                            if p.trait_ref.self_ty() != rcvr_ty {
-                                // This is necessary, not just to keep the errors clean, but also
-                                // because our derived obligations can wind up with a trait ref that
-                                // requires a different param_env to be correctly compared.
-                                continue;
-                            }
-                            unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
-                                predicate.kind().rebind(p.trait_ref),
-                                Obligation {
-                                    cause: cause.clone(),
-                                    param_env: self.param_env,
-                                    predicate: *predicate,
-                                    recursion_depth: 0,
-                                },
-                            ));
-                        }
-                    }
-
-                    // Make sure that, if any traits other than the found ones were involved,
-                    // we don't don't report an unimplemented trait.
-                    // We don't want to say that `iter::Cloned` is not an iterator, just
-                    // because of some non-Clone item being iterated over.
-                    for (predicate, _parent_pred, _cause) in &unsatisfied_predicates {
-                        match predicate.kind().skip_binder() {
-                            ty::PredicateKind::Clause(ty::Clause::Trait(p))
-                                if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
-                            _ => {
-                                unimplemented_traits_only = false;
-                                break;
-                            }
-                        }
-                    }
-
-                    let mut collect_type_param_suggestions =
-                        |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
-                            // We don't care about regions here, so it's fine to skip the binder here.
-                            if let (ty::Param(_), ty::PredicateKind::Clause(ty::Clause::Trait(p))) =
-                                (self_ty.kind(), parent_pred.kind().skip_binder())
-                            {
-                                let hir = self.tcx.hir();
-                                let node = match p.trait_ref.self_ty().kind() {
-                                    ty::Param(_) => {
-                                        // Account for `fn` items like in `issue-35677.rs` to
-                                        // suggest restricting its type params.
-                                        let parent_body =
-                                            hir.body_owner(hir::BodyId { hir_id: self.body_id });
-                                        Some(hir.get(parent_body))
-                                    }
-                                    ty::Adt(def, _) => {
-                                        def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
-                                    }
-                                    _ => 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());
-                                    }
-                                }
-                            }
-                        };
-                    let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
-                        let msg = format!(
-                            "doesn't satisfy `{}`",
-                            if obligation.len() > 50 { quiet } else { obligation }
-                        );
-                        match &self_ty.kind() {
-                            // Point at the type that couldn't satisfy the bound.
-                            ty::Adt(def, _) => {
-                                bound_spans.push((self.tcx.def_span(def.did()), msg))
-                            }
-                            // Point at the trait object that couldn't satisfy the bound.
-                            ty::Dynamic(preds, _, _) => {
-                                for pred in preds.iter() {
-                                    match pred.skip_binder() {
-                                        ty::ExistentialPredicate::Trait(tr) => bound_spans
-                                            .push((self.tcx.def_span(tr.def_id), msg.clone())),
-                                        ty::ExistentialPredicate::Projection(_)
-                                        | ty::ExistentialPredicate::AutoTrait(_) => {}
-                                    }
-                                }
-                            }
-                            // Point at the closure that couldn't satisfy the bound.
-                            ty::Closure(def_id, _) => bound_spans.push((
-                                tcx.def_span(*def_id),
-                                format!("doesn't satisfy `{}`", quiet),
-                            )),
-                            _ => {}
-                        }
-                    };
-                    let mut format_pred = |pred: ty::Predicate<'tcx>| {
-                        let bound_predicate = pred.kind();
-                        match bound_predicate.skip_binder() {
-                            ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
-                                let pred = bound_predicate.rebind(pred);
-                                // `<Foo as Iterator>::Item = String`.
-                                let projection_ty = pred.skip_binder().projection_ty;
-
-                                let substs_with_infer_self = tcx.mk_substs(
-                                    iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
-                                        .chain(projection_ty.substs.iter().skip(1)),
-                                );
-
-                                let quiet_projection_ty =
-                                    tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
-
-                                let term = pred.skip_binder().term;
-
-                                let obligation = format!("{} = {}", projection_ty, term);
-                                let quiet = with_forced_trimmed_paths!(format!(
-                                    "{} = {}",
-                                    quiet_projection_ty, term
-                                ));
-
-                                bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
-                                Some((obligation, projection_ty.self_ty()))
-                            }
-                            ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
-                                let p = poly_trait_ref.trait_ref;
-                                let self_ty = p.self_ty();
-                                let path = p.print_only_trait_path();
-                                let obligation = format!("{}: {}", self_ty, path);
-                                let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
-                                bound_span_label(self_ty, &obligation, &quiet);
-                                Some((obligation, self_ty))
-                            }
-                            _ => None,
-                        }
-                    };
-
-                    // Find all the requirements that come from a local `impl` block.
-                    let mut skip_list: FxHashSet<_> = Default::default();
-                    let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
-                    for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates
-                        .iter()
-                        .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
-                        .filter_map(|(p, parent, c)| match c.code() {
-                            ObligationCauseCode::ImplDerivedObligation(data) => {
-                                Some((&data.derived, p, parent, data.impl_def_id, data))
-                            }
-                            _ => None,
-                        })
-                    {
-                        let parent_trait_ref = data.parent_trait_pred;
-                        let path = parent_trait_ref.print_modifiers_and_trait_path();
-                        let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
-                        let unsatisfied_msg = "unsatisfied trait bound introduced here";
-                        let derive_msg =
-                            "unsatisfied trait bound introduced in this `derive` macro";
-                        match self.tcx.hir().get_if_local(impl_def_id) {
-                            // Unmet obligation comes from a `derive` macro, point at it once to
-                            // avoid multiple span labels pointing at the same place.
-                            Some(Node::Item(hir::Item {
-                                kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
-                                ..
-                            })) if matches!(
-                                self_ty.span.ctxt().outer_expn_data().kind,
-                                ExpnKind::Macro(MacroKind::Derive, _)
-                            ) || matches!(
-                                of_trait.as_ref().map(|t| t
-                                    .path
-                                    .span
-                                    .ctxt()
-                                    .outer_expn_data()
-                                    .kind),
-                                Some(ExpnKind::Macro(MacroKind::Derive, _))
-                            ) =>
-                            {
-                                let span = self_ty.span.ctxt().outer_expn_data().call_site;
-                                let mut spans: MultiSpan = span.into();
-                                spans.push_span_label(span, derive_msg);
-                                let entry = spanned_predicates.entry(spans);
-                                entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
-                            }
-
-                            // Unmet obligation coming from an `impl`.
-                            Some(Node::Item(hir::Item {
-                                kind:
-                                    hir::ItemKind::Impl(hir::Impl {
-                                        of_trait, self_ty, generics, ..
-                                    }),
-                                span: item_span,
-                                ..
-                            })) => {
-                                let sized_pred =
-                                    unsatisfied_predicates.iter().any(|(pred, _, _)| {
-                                        match pred.kind().skip_binder() {
-                                            ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
-                                                Some(pred.def_id())
-                                                    == self.tcx.lang_items().sized_trait()
-                                                    && pred.polarity == ty::ImplPolarity::Positive
-                                            }
-                                            _ => false,
-                                        }
-                                    });
-                                for param in generics.params {
-                                    if param.span == cause.span && sized_pred {
-                                        let (sp, sugg) = match param.colon_span {
-                                            Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
-                                            None => (param.span.shrink_to_hi(), ": ?Sized"),
-                                        };
-                                        err.span_suggestion_verbose(
-                                            sp,
-                                            "consider relaxing the type parameter's implicit \
-                                             `Sized` bound",
-                                            sugg,
-                                            Applicability::MachineApplicable,
-                                        );
-                                    }
-                                }
-                                if let Some(pred) = parent_p {
-                                    // Done to add the "doesn't satisfy" `span_label`.
-                                    let _ = format_pred(*pred);
-                                }
-                                skip_list.insert(p);
-                                let mut spans = if cause.span != *item_span {
-                                    let mut spans: MultiSpan = cause.span.into();
-                                    spans.push_span_label(cause.span, unsatisfied_msg);
-                                    spans
-                                } else {
-                                    let mut spans = Vec::with_capacity(2);
-                                    if let Some(trait_ref) = of_trait {
-                                        spans.push(trait_ref.path.span);
-                                    }
-                                    spans.push(self_ty.span);
-                                    spans.into()
-                                };
-                                if let Some(trait_ref) = of_trait {
-                                    spans.push_span_label(trait_ref.path.span, "");
-                                }
-                                spans.push_span_label(self_ty.span, "");
-
-                                let entry = spanned_predicates.entry(spans);
-                                entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
-                            }
-                            Some(Node::Item(hir::Item {
-                                kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
-                                span: item_span,
-                                ..
-                            })) => {
-                                tcx.sess.delay_span_bug(
-                                        *item_span,
-                                        "auto trait is invoked with no method error, but no error reported?",
-                                    );
-                            }
-                            Some(_) => unreachable!(),
-                            None => (),
-                        }
-                    }
-                    let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
-                    spanned_predicates.sort_by_key(|(span, (_, _, _))| span.primary_span());
-                    for (span, (_path, _self_ty, preds)) in spanned_predicates {
-                        let mut preds: Vec<_> = preds
-                            .into_iter()
-                            .filter_map(|pred| format_pred(*pred))
-                            .map(|(p, _)| format!("`{}`", p))
-                            .collect();
-                        preds.sort();
-                        preds.dedup();
-                        let msg = if let [pred] = &preds[..] {
-                            format!("trait bound {} was not satisfied", pred)
-                        } else {
-                            format!(
-                                "the following trait bounds were not satisfied:\n{}",
-                                preds.join("\n"),
-                            )
-                        };
-                        err.span_note(span, &msg);
-                        unsatisfied_bounds = true;
-                    }
-
-                    // The requirements that didn't have an `impl` span to show.
-                    let mut bound_list = unsatisfied_predicates
-                        .iter()
-                        .filter_map(|(pred, parent_pred, _cause)| {
-                            format_pred(*pred).map(|(p, self_ty)| {
-                                collect_type_param_suggestions(self_ty, *pred, &p);
-                                (
-                                    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,
-                                                );
-                                                format!(
-                                                    "`{}`\nwhich is required by `{}`",
-                                                    p, parent_p
-                                                )
-                                            }
-                                        },
-                                    },
-                                    *pred,
-                                )
-                            })
-                        })
-                        .filter(|(_, pred)| !skip_list.contains(&pred))
-                        .map(|(t, _)| t)
-                        .enumerate()
-                        .collect::<Vec<(usize, String)>>();
-
-                    for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
-                        restrict_type_params = true;
-                        // #74886: Sort here so that the output is always the same.
-                        let mut obligations = obligations.into_iter().collect::<Vec<_>>();
-                        obligations.sort();
-                        err.span_suggestion_verbose(
-                            span,
-                            &format!(
-                                "consider restricting the type parameter{s} to satisfy the \
-                                 trait bound{s}",
-                                s = pluralize!(obligations.len())
-                            ),
-                            format!("{} {}", add_where_or_comma, obligations.join(", ")),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-
-                    bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
-                    bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
-                    bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
-
-                    if !bound_list.is_empty() || !skip_list.is_empty() {
-                        let bound_list = bound_list
-                            .into_iter()
-                            .map(|(_, path)| path)
-                            .collect::<Vec<_>>()
-                            .join("\n");
-                        let actual_prefix = rcvr_ty.prefix_string(self.tcx);
-                        info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
-                        let (primary_message, label) =
-                            if unimplemented_traits.len() == 1 && unimplemented_traits_only {
-                                unimplemented_traits
-                                    .into_iter()
-                                    .next()
-                                    .map(|(_, (trait_ref, obligation))| {
-                                        if trait_ref.self_ty().references_error()
-                                            || rcvr_ty.references_error()
-                                        {
-                                            // Avoid crashing.
-                                            return (None, None);
-                                        }
-                                        let OnUnimplementedNote { message, label, .. } = self
-                                            .err_ctxt()
-                                            .on_unimplemented_note(trait_ref, &obligation);
-                                        (message, label)
-                                    })
-                                    .unwrap()
-                            } else {
-                                (None, None)
-                            };
-                        let primary_message = primary_message.unwrap_or_else(|| format!(
-                            "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
-                             but its trait bounds were not satisfied"
-                        ));
-                        err.set_primary_message(&primary_message);
-                        if let Some(label) = label {
-                            custom_span_label = true;
-                            err.span_label(span, label);
-                        }
-                        if !bound_list.is_empty() {
-                            err.note(&format!(
-                                "the following trait bounds were not satisfied:\n{bound_list}"
-                            ));
-                        }
-                        self.suggest_derive(&mut err, &unsatisfied_predicates);
-
-                        unsatisfied_bounds = true;
-                    }
-                }
-
-                let label_span_not_found = |err: &mut Diagnostic| {
-                    if unsatisfied_predicates.is_empty() {
-                        err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
-                        let is_string_or_ref_str = match rcvr_ty.kind() {
-                            ty::Ref(_, ty, _) => {
-                                ty.is_str()
-                                    || matches!(
-                                        ty.kind(),
-                                        ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string()
-                                    )
-                            }
-                            ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(),
-                            _ => false,
-                        };
-                        if is_string_or_ref_str && item_name.name == sym::iter {
-                            err.span_suggestion_verbose(
-                                item_name.span,
-                                "because of the in-memory representation of `&str`, to obtain \
-                                 an `Iterator` over each of its codepoint use method `chars`",
-                                "chars",
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                        if let ty::Adt(adt, _) = rcvr_ty.kind() {
-                            let mut inherent_impls_candidate = self
-                                .tcx
-                                .inherent_impls(adt.did())
-                                .iter()
-                                .copied()
-                                .filter(|def_id| {
-                                    if let Some(assoc) = self.associated_value(*def_id, item_name) {
-                                        // Check for both mode is the same so we avoid suggesting
-                                        // incorrect associated item.
-                                        match (mode, assoc.fn_has_self_parameter, source) {
-                                            (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
-                                                // We check that the suggest type is actually
-                                                // different from the received one
-                                                // So we avoid suggestion method with Box<Self>
-                                                // for instance
-                                                self.tcx.at(span).type_of(*def_id) != rcvr_ty
-                                                    && self.tcx.at(span).type_of(*def_id) != rcvr_ty
-                                            }
-                                            (Mode::Path, false, _) => true,
-                                            _ => false,
-                                        }
-                                    } else {
-                                        false
-                                    }
-                                })
-                                .collect::<Vec<_>>();
-                            if !inherent_impls_candidate.is_empty() {
-                                inherent_impls_candidate.sort();
-                                inherent_impls_candidate.dedup();
-
-                                // number of type to shows at most.
-                                let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
-                                let type_candidates = inherent_impls_candidate
-                                    .iter()
-                                    .take(limit)
-                                    .map(|impl_item| {
-                                        format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
-                                    })
-                                    .collect::<Vec<_>>()
-                                    .join("\n");
-                                let additional_types = if inherent_impls_candidate.len() > limit {
-                                    format!(
-                                        "\nand {} more types",
-                                        inherent_impls_candidate.len() - limit
-                                    )
-                                } else {
-                                    "".to_string()
-                                };
-                                err.note(&format!(
-                                    "the {item_kind} was found for\n{}{}",
-                                    type_candidates, additional_types
-                                ));
-                            }
-                        }
-                    } else {
-                        let ty_str = if ty_str.len() > 50 {
-                            String::new()
-                        } else {
-                            format!("on `{ty_str}` ")
-                        };
-                        err.span_label(span, format!(
-                            "{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds"
-                        ));
-                    }
-                };
-
-                // If the method name is the name of a field with a function or closure type,
-                // give a helping note that it has to be called as `(x.f)(...)`.
-                if let SelfSource::MethodCall(expr) = source {
-                    if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
-                        && lev_candidate.is_none()
-                        && !custom_span_label
-                    {
-                        label_span_not_found(&mut err);
-                    }
-                } else if !custom_span_label {
-                    label_span_not_found(&mut err);
-                }
-
-                // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
-                // can't be called due to `typeof(expr): Clone` not holding.
-                if unsatisfied_predicates.is_empty() {
-                    self.suggest_calling_method_on_field(
-                        &mut err, source, span, rcvr_ty, item_name,
-                    );
-                }
-
-                self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
-
-                bound_spans.sort();
-                bound_spans.dedup();
-                for (span, msg) in bound_spans.into_iter() {
-                    err.span_label(span, &msg);
-                }
-
-                if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
-                } else {
-                    self.suggest_traits_to_import(
-                        &mut err,
-                        span,
-                        rcvr_ty,
-                        item_name,
-                        args.map(|(_, args)| args.len() + 1),
-                        source,
-                        out_of_scope_traits,
-                        &unsatisfied_predicates,
-                        &static_candidates,
-                        unsatisfied_bounds,
-                    );
-                }
-
-                // Don't emit a suggestion if we found an actual method
-                // that had unsatisfied trait bounds
-                if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
-                    let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
-                    if let Some(suggestion) = lev_distance::find_best_match_for_name(
-                        &adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
-                        item_name.name,
-                        None,
-                    ) {
-                        err.span_suggestion(
-                            span,
-                            "there is a variant with a similar name",
-                            suggestion,
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-
-                if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
-                    let msg = "remove this method call";
-                    let mut fallback_span = true;
-                    if let SelfSource::MethodCall(expr) = source {
-                        let call_expr =
-                            self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
-                        if let Some(span) = call_expr.span.trim_start(expr.span) {
-                            err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
-                            fallback_span = false;
-                        }
-                    }
-                    if fallback_span {
-                        err.span_label(span, msg);
-                    }
-                } else if let Some(lev_candidate) = lev_candidate {
-                    // Don't emit a suggestion if we found an actual method
-                    // that had unsatisfied trait bounds
-                    if unsatisfied_predicates.is_empty() {
-                        let def_kind = lev_candidate.kind.as_def_kind();
-                        // Methods are defined within the context of a struct and their first parameter is always self,
-                        // which represents the instance of the struct the method is being called on
-                        // Associated functions don’t take self as a parameter and
-                        // they are not methods because they don’t have an instance of the struct to work with.
-                        if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
-                            err.span_suggestion(
-                                span,
-                                "there is a method with a similar name",
-                                lev_candidate.name,
-                                Applicability::MaybeIncorrect,
-                            );
-                        } else {
-                            err.span_suggestion(
-                                span,
-                                &format!(
-                                    "there is {} {} with a similar name",
-                                    def_kind.article(),
-                                    def_kind.descr(lev_candidate.def_id),
-                                ),
-                                lev_candidate.name,
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                    }
-                }
-
-                self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
-
-                return Some(err);
             }
 
             MethodError::Ambiguity(mut sources) => {
@@ -1040,7 +143,15 @@ trait bound{s}",
                 );
                 err.span_label(item_name.span, format!("multiple `{}` found", item_name));
 
-                report_candidates(span, &mut err, &mut sources, Some(sugg_span));
+                self.note_candidates_on_method_error(
+                    rcvr_ty,
+                    item_name,
+                    args,
+                    span,
+                    &mut err,
+                    &mut sources,
+                    Some(sugg_span),
+                );
                 err.emit();
             }
 
@@ -1097,6 +208,900 @@ trait bound{s}",
         None
     }
 
+    pub fn report_no_match_method_error(
+        &self,
+        mut span: Span,
+        rcvr_ty: Ty<'tcx>,
+        item_name: Ident,
+        source: SelfSource<'tcx>,
+        args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+        sugg_span: Span,
+        no_match_data: &mut NoMatchData<'tcx>,
+    ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
+        let mode = no_match_data.mode;
+        let tcx = self.tcx;
+        let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
+        let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
+        let is_method = mode == Mode::MethodCall;
+        let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
+        let lev_candidate = no_match_data.lev_candidate;
+        let item_kind = if is_method {
+            "method"
+        } else if rcvr_ty.is_enum() {
+            "variant or associated item"
+        } else {
+            match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
+                (Some(name), false) if name.is_lowercase() => "function or associated item",
+                (Some(_), false) => "associated item",
+                (Some(_), true) | (None, false) => "variant or associated item",
+                (None, true) => "variant",
+            }
+        };
+
+        if self.suggest_wrapping_range_with_parens(tcx, rcvr_ty, source, span, item_name, &ty_str)
+            || self.suggest_constraining_numerical_ty(
+                tcx, rcvr_ty, source, span, item_kind, item_name, &ty_str,
+            )
+        {
+            return None;
+        }
+        span = item_name.span;
+
+        // Don't show generic arguments when the method can't be found in any implementation (#81576).
+        let mut ty_str_reported = ty_str.clone();
+        if let ty::Adt(_, generics) = rcvr_ty.kind() {
+            if generics.len() > 0 {
+                let mut autoderef = self.autoderef(span, rcvr_ty);
+                let candidate_found = autoderef.any(|(ty, _)| {
+                    if let ty::Adt(adt_def, _) = ty.kind() {
+                        self.tcx
+                            .inherent_impls(adt_def.did())
+                            .iter()
+                            .any(|def_id| self.associated_value(*def_id, item_name).is_some())
+                    } else {
+                        false
+                    }
+                });
+                let has_deref = autoderef.step_count() > 0;
+                if !candidate_found && !has_deref && unsatisfied_predicates.is_empty() {
+                    if let Some((path_string, _)) = ty_str.split_once('<') {
+                        ty_str_reported = path_string.to_string();
+                    }
+                }
+            }
+        }
+
+        let mut err = struct_span_err!(
+            tcx.sess,
+            span,
+            E0599,
+            "no {} named `{}` found for {} `{}` in the current scope",
+            item_kind,
+            item_name,
+            rcvr_ty.prefix_string(self.tcx),
+            ty_str_reported,
+        );
+        if rcvr_ty.references_error() {
+            err.downgrade_to_delayed_bug();
+        }
+
+        if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
+            self.suggest_await_before_method(
+                &mut err, item_name, rcvr_ty, cal, span,
+            );
+        }
+        if let Some(span) =
+            tcx.resolutions(()).confused_type_with_std_module.get(&span.with_parent(None))
+        {
+            err.span_suggestion(
+                span.shrink_to_lo(),
+                "you are looking for the module in `std`, not the primitive type",
+                "std::",
+                Applicability::MachineApplicable,
+            );
+        }
+        if let ty::RawPtr(_) = &rcvr_ty.kind() {
+            err.note(
+                "try using `<*const T>::as_ref()` to get a reference to the \
+                 type behind the pointer: https://doc.rust-lang.org/std/\
+                 primitive.pointer.html#method.as_ref",
+            );
+            err.note(
+                "using `<*const T>::as_ref()` on a pointer which is unaligned or points \
+                 to invalid or uninitialized memory is undefined behavior",
+            );
+        }
+
+        let ty_span = match rcvr_ty.kind() {
+            ty::Param(param_type) => {
+                Some(param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()))
+            }
+            ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
+            _ => None,
+        };
+        if let Some(span) = ty_span {
+            err.span_label(
+                span,
+                format!(
+                    "{item_kind} `{item_name}` not found for this {}",
+                    rcvr_ty.prefix_string(self.tcx)
+                ),
+            );
+        }
+
+        if let SelfSource::MethodCall(rcvr_expr) = source {
+            self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
+                let call_expr =
+                    self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(rcvr_expr.hir_id));
+                let probe =
+                    self.lookup_probe(item_name, output_ty, call_expr, ProbeScope::AllTraits);
+                probe.is_ok()
+            });
+        }
+
+        let mut custom_span_label = false;
+
+        let static_candidates = &mut no_match_data.static_candidates;
+        if !static_candidates.is_empty() {
+            err.note(
+                "found the following associated functions; to be used as methods, \
+                 functions must have a `self` parameter",
+            );
+            err.span_label(span, "this is an associated function, not a method");
+            custom_span_label = true;
+        }
+        if static_candidates.len() == 1 {
+            self.suggest_associated_call_syntax(
+                &mut err,
+                &static_candidates,
+                rcvr_ty,
+                source,
+                item_name,
+                args,
+                sugg_span,
+            );
+
+            self.note_candidates_on_method_error(
+                rcvr_ty,
+                item_name,
+                args,
+                span,
+                &mut err,
+                static_candidates,
+                None,
+            );
+        } else if static_candidates.len() > 1 {
+            self.note_candidates_on_method_error(
+                rcvr_ty,
+                item_name,
+                args,
+                span,
+                &mut err,
+                static_candidates,
+                Some(sugg_span),
+            );
+        }
+
+        let mut bound_spans = vec![];
+        let mut restrict_type_params = false;
+        let mut unsatisfied_bounds = false;
+        if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
+            let msg = "consider using `len` instead";
+            if let SelfSource::MethodCall(_expr) = source {
+                err.span_suggestion_short(span, msg, "len", Applicability::MachineApplicable);
+            } else {
+                err.span_label(span, msg);
+            }
+            if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
+                let iterator_trait = self.tcx.def_path_str(iterator_trait);
+                err.note(&format!(
+                    "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
+                ));
+            }
+        } else if !unsatisfied_predicates.is_empty() {
+            let mut type_params = FxHashMap::default();
+
+            // Pick out the list of unimplemented traits on the receiver.
+            // This is used for custom error messages with the `#[rustc_on_unimplemented]` attribute.
+            let mut unimplemented_traits = FxHashMap::default();
+            let mut unimplemented_traits_only = true;
+            for (predicate, _parent_pred, cause) in unsatisfied_predicates {
+                if let (ty::PredicateKind::Clause(ty::Clause::Trait(p)), Some(cause)) =
+                    (predicate.kind().skip_binder(), cause.as_ref())
+                {
+                    if p.trait_ref.self_ty() != rcvr_ty {
+                        // This is necessary, not just to keep the errors clean, but also
+                        // because our derived obligations can wind up with a trait ref that
+                        // requires a different param_env to be correctly compared.
+                        continue;
+                    }
+                    unimplemented_traits.entry(p.trait_ref.def_id).or_insert((
+                        predicate.kind().rebind(p.trait_ref),
+                        Obligation {
+                            cause: cause.clone(),
+                            param_env: self.param_env,
+                            predicate: *predicate,
+                            recursion_depth: 0,
+                        },
+                    ));
+                }
+            }
+
+            // Make sure that, if any traits other than the found ones were involved,
+            // we don't don't report an unimplemented trait.
+            // We don't want to say that `iter::Cloned` is not an iterator, just
+            // because of some non-Clone item being iterated over.
+            for (predicate, _parent_pred, _cause) in unsatisfied_predicates {
+                match predicate.kind().skip_binder() {
+                    ty::PredicateKind::Clause(ty::Clause::Trait(p))
+                        if unimplemented_traits.contains_key(&p.trait_ref.def_id) => {}
+                    _ => {
+                        unimplemented_traits_only = false;
+                        break;
+                    }
+                }
+            }
+
+            let mut collect_type_param_suggestions =
+                |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| {
+                    // We don't care about regions here, so it's fine to skip the binder here.
+                    if let (ty::Param(_), ty::PredicateKind::Clause(ty::Clause::Trait(p))) =
+                        (self_ty.kind(), parent_pred.kind().skip_binder())
+                    {
+                        let hir = self.tcx.hir();
+                        let node = match p.trait_ref.self_ty().kind() {
+                            ty::Param(_) => {
+                                // Account for `fn` items like in `issue-35677.rs` to
+                                // suggest restricting its type params.
+                                let parent_body =
+                                    hir.body_owner(hir::BodyId { hir_id: self.body_id });
+                                Some(hir.get(parent_body))
+                            }
+                            ty::Adt(def, _) => {
+                                def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
+                            }
+                            _ => 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());
+                            }
+                        }
+                    }
+                };
+            let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
+                let msg = format!(
+                    "doesn't satisfy `{}`",
+                    if obligation.len() > 50 { quiet } else { obligation }
+                );
+                match &self_ty.kind() {
+                    // Point at the type that couldn't satisfy the bound.
+                    ty::Adt(def, _) => bound_spans.push((self.tcx.def_span(def.did()), msg)),
+                    // Point at the trait object that couldn't satisfy the bound.
+                    ty::Dynamic(preds, _, _) => {
+                        for pred in preds.iter() {
+                            match pred.skip_binder() {
+                                ty::ExistentialPredicate::Trait(tr) => {
+                                    bound_spans.push((self.tcx.def_span(tr.def_id), msg.clone()))
+                                }
+                                ty::ExistentialPredicate::Projection(_)
+                                | ty::ExistentialPredicate::AutoTrait(_) => {}
+                            }
+                        }
+                    }
+                    // Point at the closure that couldn't satisfy the bound.
+                    ty::Closure(def_id, _) => bound_spans
+                        .push((tcx.def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
+                    _ => {}
+                }
+            };
+            let mut format_pred = |pred: ty::Predicate<'tcx>| {
+                let bound_predicate = pred.kind();
+                match bound_predicate.skip_binder() {
+                    ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
+                        let pred = bound_predicate.rebind(pred);
+                        // `<Foo as Iterator>::Item = String`.
+                        let projection_ty = pred.skip_binder().projection_ty;
+
+                        let substs_with_infer_self = tcx.mk_substs(
+                            iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
+                                .chain(projection_ty.substs.iter().skip(1)),
+                        );
+
+                        let quiet_projection_ty =
+                            tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
+
+                        let term = pred.skip_binder().term;
+
+                        let obligation = format!("{} = {}", projection_ty, term);
+                        let quiet = with_forced_trimmed_paths!(format!(
+                            "{} = {}",
+                            quiet_projection_ty, term
+                        ));
+
+                        bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
+                        Some((obligation, projection_ty.self_ty()))
+                    }
+                    ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
+                        let p = poly_trait_ref.trait_ref;
+                        let self_ty = p.self_ty();
+                        let path = p.print_only_trait_path();
+                        let obligation = format!("{}: {}", self_ty, path);
+                        let quiet = with_forced_trimmed_paths!(format!("_: {}", path));
+                        bound_span_label(self_ty, &obligation, &quiet);
+                        Some((obligation, self_ty))
+                    }
+                    _ => None,
+                }
+            };
+
+            // Find all the requirements that come from a local `impl` block.
+            let mut skip_list: FxHashSet<_> = Default::default();
+            let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
+            for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates
+                .iter()
+                .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
+                .filter_map(|(p, parent, c)| match c.code() {
+                    ObligationCauseCode::ImplDerivedObligation(data) => {
+                        Some((&data.derived, p, parent, data.impl_def_id, data))
+                    }
+                    _ => None,
+                })
+            {
+                let parent_trait_ref = data.parent_trait_pred;
+                let path = parent_trait_ref.print_modifiers_and_trait_path();
+                let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
+                let unsatisfied_msg = "unsatisfied trait bound introduced here";
+                let derive_msg = "unsatisfied trait bound introduced in this `derive` macro";
+                match self.tcx.hir().get_if_local(impl_def_id) {
+                    // Unmet obligation comes from a `derive` macro, point at it once to
+                    // avoid multiple span labels pointing at the same place.
+                    Some(Node::Item(hir::Item {
+                        kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
+                        ..
+                    })) if matches!(
+                        self_ty.span.ctxt().outer_expn_data().kind,
+                        ExpnKind::Macro(MacroKind::Derive, _)
+                    ) || matches!(
+                        of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind),
+                        Some(ExpnKind::Macro(MacroKind::Derive, _))
+                    ) =>
+                    {
+                        let span = self_ty.span.ctxt().outer_expn_data().call_site;
+                        let mut spans: MultiSpan = span.into();
+                        spans.push_span_label(span, derive_msg);
+                        let entry = spanned_predicates.entry(spans);
+                        entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
+                    }
+
+                    // Unmet obligation coming from an `impl`.
+                    Some(Node::Item(hir::Item {
+                        kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }),
+                        span: item_span,
+                        ..
+                    })) => {
+                        let sized_pred =
+                            unsatisfied_predicates.iter().any(|(pred, _, _)| {
+                                match pred.kind().skip_binder() {
+                                    ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
+                                        Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
+                                            && pred.polarity == ty::ImplPolarity::Positive
+                                    }
+                                    _ => false,
+                                }
+                            });
+                        for param in generics.params {
+                            if param.span == cause.span && sized_pred {
+                                let (sp, sugg) = match param.colon_span {
+                                    Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
+                                    None => (param.span.shrink_to_hi(), ": ?Sized"),
+                                };
+                                err.span_suggestion_verbose(
+                                    sp,
+                                    "consider relaxing the type parameter's implicit \
+                                     `Sized` bound",
+                                    sugg,
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                        }
+                        if let Some(pred) = parent_p {
+                            // Done to add the "doesn't satisfy" `span_label`.
+                            let _ = format_pred(*pred);
+                        }
+                        skip_list.insert(p);
+                        let mut spans = if cause.span != *item_span {
+                            let mut spans: MultiSpan = cause.span.into();
+                            spans.push_span_label(cause.span, unsatisfied_msg);
+                            spans
+                        } else {
+                            let mut spans = Vec::with_capacity(2);
+                            if let Some(trait_ref) = of_trait {
+                                spans.push(trait_ref.path.span);
+                            }
+                            spans.push(self_ty.span);
+                            spans.into()
+                        };
+                        if let Some(trait_ref) = of_trait {
+                            spans.push_span_label(trait_ref.path.span, "");
+                        }
+                        spans.push_span_label(self_ty.span, "");
+
+                        let entry = spanned_predicates.entry(spans);
+                        entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
+                    }
+                    Some(Node::Item(hir::Item {
+                        kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..),
+                        span: item_span,
+                        ..
+                    })) => {
+                        tcx.sess.delay_span_bug(
+                            *item_span,
+                            "auto trait is invoked with no method error, but no error reported?",
+                        );
+                    }
+                    Some(_) => unreachable!(),
+                    None => (),
+                }
+            }
+            let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
+            spanned_predicates.sort_by_key(|(span, (_, _, _))| span.primary_span());
+            for (span, (_path, _self_ty, preds)) in spanned_predicates {
+                let mut preds: Vec<_> = preds
+                    .into_iter()
+                    .filter_map(|pred| format_pred(*pred))
+                    .map(|(p, _)| format!("`{}`", p))
+                    .collect();
+                preds.sort();
+                preds.dedup();
+                let msg = if let [pred] = &preds[..] {
+                    format!("trait bound {} was not satisfied", pred)
+                } else {
+                    format!("the following trait bounds were not satisfied:\n{}", preds.join("\n"),)
+                };
+                err.span_note(span, &msg);
+                unsatisfied_bounds = true;
+            }
+
+            // The requirements that didn't have an `impl` span to show.
+            let mut bound_list = unsatisfied_predicates
+                .iter()
+                .filter_map(|(pred, parent_pred, _cause)| {
+                    format_pred(*pred).map(|(p, self_ty)| {
+                        collect_type_param_suggestions(self_ty, *pred, &p);
+                        (
+                            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);
+                                        format!("`{}`\nwhich is required by `{}`", p, parent_p)
+                                    }
+                                },
+                            },
+                            *pred,
+                        )
+                    })
+                })
+                .filter(|(_, pred)| !skip_list.contains(&pred))
+                .map(|(t, _)| t)
+                .enumerate()
+                .collect::<Vec<(usize, String)>>();
+
+            for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
+                restrict_type_params = true;
+                // #74886: Sort here so that the output is always the same.
+                let mut obligations = obligations.into_iter().collect::<Vec<_>>();
+                obligations.sort();
+                err.span_suggestion_verbose(
+                    span,
+                    &format!(
+                        "consider restricting the type parameter{s} to satisfy the \
+                         trait bound{s}",
+                        s = pluralize!(obligations.len())
+                    ),
+                    format!("{} {}", add_where_or_comma, obligations.join(", ")),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+
+            bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
+            bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
+            bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
+
+            if !bound_list.is_empty() || !skip_list.is_empty() {
+                let bound_list =
+                    bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n");
+                let actual_prefix = rcvr_ty.prefix_string(self.tcx);
+                info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
+                let (primary_message, label) = if unimplemented_traits.len() == 1
+                    && unimplemented_traits_only
+                {
+                    unimplemented_traits
+                        .into_iter()
+                        .next()
+                        .map(|(_, (trait_ref, obligation))| {
+                            if trait_ref.self_ty().references_error() || rcvr_ty.references_error()
+                            {
+                                // Avoid crashing.
+                                return (None, None);
+                            }
+                            let OnUnimplementedNote { message, label, .. } =
+                                self.err_ctxt().on_unimplemented_note(trait_ref, &obligation);
+                            (message, label)
+                        })
+                        .unwrap()
+                } else {
+                    (None, None)
+                };
+                let primary_message = primary_message.unwrap_or_else(|| {
+                    format!(
+                        "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, \
+                    but its trait bounds were not satisfied"
+                    )
+                });
+                err.set_primary_message(&primary_message);
+                if let Some(label) = label {
+                    custom_span_label = true;
+                    err.span_label(span, label);
+                }
+                if !bound_list.is_empty() {
+                    err.note(&format!(
+                        "the following trait bounds were not satisfied:\n{bound_list}"
+                    ));
+                }
+                self.suggest_derive(&mut err, &unsatisfied_predicates);
+
+                unsatisfied_bounds = true;
+            }
+        }
+
+        let label_span_not_found = |err: &mut Diagnostic| {
+            if unsatisfied_predicates.is_empty() {
+                err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+                let is_string_or_ref_str = match rcvr_ty.kind() {
+                    ty::Ref(_, ty, _) => {
+                        ty.is_str()
+                            || matches!(
+                                ty.kind(),
+                                ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string()
+                            )
+                    }
+                    ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(),
+                    _ => false,
+                };
+                if is_string_or_ref_str && item_name.name == sym::iter {
+                    err.span_suggestion_verbose(
+                        item_name.span,
+                        "because of the in-memory representation of `&str`, to obtain \
+                         an `Iterator` over each of its codepoint use method `chars`",
+                        "chars",
+                        Applicability::MachineApplicable,
+                    );
+                }
+                if let ty::Adt(adt, _) = rcvr_ty.kind() {
+                    let mut inherent_impls_candidate = self
+                        .tcx
+                        .inherent_impls(adt.did())
+                        .iter()
+                        .copied()
+                        .filter(|def_id| {
+                            if let Some(assoc) = self.associated_value(*def_id, item_name) {
+                                // Check for both mode is the same so we avoid suggesting
+                                // incorrect associated item.
+                                match (mode, assoc.fn_has_self_parameter, source) {
+                                    (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
+                                        // We check that the suggest type is actually
+                                        // different from the received one
+                                        // So we avoid suggestion method with Box<Self>
+                                        // for instance
+                                        self.tcx.at(span).type_of(*def_id) != rcvr_ty
+                                            && self.tcx.at(span).type_of(*def_id) != rcvr_ty
+                                    }
+                                    (Mode::Path, false, _) => true,
+                                    _ => false,
+                                }
+                            } else {
+                                false
+                            }
+                        })
+                        .collect::<Vec<_>>();
+                    if !inherent_impls_candidate.is_empty() {
+                        inherent_impls_candidate.sort();
+                        inherent_impls_candidate.dedup();
+
+                        // number of type to shows at most.
+                        let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
+                        let type_candidates = inherent_impls_candidate
+                            .iter()
+                            .take(limit)
+                            .map(|impl_item| {
+                                format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
+                            })
+                            .collect::<Vec<_>>()
+                            .join("\n");
+                        let additional_types = if inherent_impls_candidate.len() > limit {
+                            format!("\nand {} more types", inherent_impls_candidate.len() - limit)
+                        } else {
+                            "".to_string()
+                        };
+                        err.note(&format!(
+                            "the {item_kind} was found for\n{}{}",
+                            type_candidates, additional_types
+                        ));
+                    }
+                }
+            } else {
+                let ty_str =
+                    if ty_str.len() > 50 { String::new() } else { format!("on `{ty_str}` ") };
+                err.span_label(
+                    span,
+                    format!("{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds"),
+                );
+            }
+        };
+
+        // If the method name is the name of a field with a function or closure type,
+        // give a helping note that it has to be called as `(x.f)(...)`.
+        if let SelfSource::MethodCall(expr) = source {
+            if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
+                && lev_candidate.is_none()
+                && !custom_span_label
+            {
+                label_span_not_found(&mut err);
+            }
+        } else if !custom_span_label {
+            label_span_not_found(&mut err);
+        }
+
+        // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
+        // can't be called due to `typeof(expr): Clone` not holding.
+        if unsatisfied_predicates.is_empty() {
+            self.suggest_calling_method_on_field(&mut err, source, span, rcvr_ty, item_name);
+        }
+
+        self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
+
+        bound_spans.sort();
+        bound_spans.dedup();
+        for (span, msg) in bound_spans.into_iter() {
+            err.span_label(span, &msg);
+        }
+
+        if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
+        } else {
+            self.suggest_traits_to_import(
+                &mut err,
+                span,
+                rcvr_ty,
+                item_name,
+                args.map(|(_, args)| args.len() + 1),
+                source,
+                no_match_data.out_of_scope_traits.clone(),
+                &unsatisfied_predicates,
+                &static_candidates,
+                unsatisfied_bounds,
+            );
+        }
+
+        // Don't emit a suggestion if we found an actual method
+        // that had unsatisfied trait bounds
+        if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
+            let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
+            if let Some(suggestion) = lev_distance::find_best_match_for_name(
+                &adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
+                item_name.name,
+                None,
+            ) {
+                err.span_suggestion(
+                    span,
+                    "there is a variant with a similar name",
+                    suggestion,
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        }
+
+        if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
+            let msg = "remove this method call";
+            let mut fallback_span = true;
+            if let SelfSource::MethodCall(expr) = source {
+                let call_expr =
+                    self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
+                if let Some(span) = call_expr.span.trim_start(expr.span) {
+                    err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
+                    fallback_span = false;
+                }
+            }
+            if fallback_span {
+                err.span_label(span, msg);
+            }
+        } else if let Some(lev_candidate) = lev_candidate {
+            // Don't emit a suggestion if we found an actual method
+            // that had unsatisfied trait bounds
+            if unsatisfied_predicates.is_empty() {
+                let def_kind = lev_candidate.kind.as_def_kind();
+                // Methods are defined within the context of a struct and their first parameter is always self,
+                // which represents the instance of the struct the method is being called on
+                // Associated functions don’t take self as a parameter and
+                // they are not methods because they don’t have an instance of the struct to work with.
+                if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
+                    err.span_suggestion(
+                        span,
+                        "there is a method with a similar name",
+                        lev_candidate.name,
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    err.span_suggestion(
+                        span,
+                        &format!(
+                            "there is {} {} with a similar name",
+                            def_kind.article(),
+                            def_kind.descr(lev_candidate.def_id),
+                        ),
+                        lev_candidate.name,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+
+        self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
+        return Some(err);
+    }
+
+    fn note_candidates_on_method_error(
+        &self,
+        rcvr_ty: Ty<'tcx>,
+        item_name: Ident,
+        args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
+        span: Span,
+        err: &mut Diagnostic,
+        sources: &mut Vec<CandidateSource>,
+        sugg_span: Option<Span>,
+    ) {
+        sources.sort();
+        sources.dedup();
+        // Dynamic limit to avoid hiding just one candidate, which is silly.
+        let limit = if sources.len() == 5 { 5 } else { 4 };
+
+        for (idx, source) in sources.iter().take(limit).enumerate() {
+            match *source {
+                CandidateSource::Impl(impl_did) => {
+                    // Provide the best span we can. Use the item, if local to crate, else
+                    // the impl, if local to crate (item may be defaulted), else nothing.
+                    let 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)
+                    }) else {
+                        continue;
+                    };
+
+                    let note_span = if item.def_id.is_local() {
+                        Some(self.tcx.def_span(item.def_id))
+                    } else if impl_did.is_local() {
+                        Some(self.tcx.def_span(impl_did))
+                    } else {
+                        None
+                    };
+
+                    let impl_ty = self.tcx.at(span).type_of(impl_did);
+
+                    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))
+                        }
+                    };
+
+                    let (note_str, idx) = if sources.len() > 1 {
+                        (
+                            format!(
+                                "candidate #{} is defined in an impl{} for the type `{}`",
+                                idx + 1,
+                                insertion,
+                                impl_ty,
+                            ),
+                            Some(idx + 1),
+                        )
+                    } else {
+                        (
+                            format!(
+                                "the candidate is defined in an impl{} for the type `{}`",
+                                insertion, impl_ty,
+                            ),
+                            None,
+                        )
+                    };
+                    if let Some(note_span) = note_span {
+                        // We have a span pointing to the method. Show note with snippet.
+                        err.span_note(note_span, &note_str);
+                    } else {
+                        err.note(&note_str);
+                    }
+                    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 ty = match item.kind {
+                            ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty,
+                            ty::AssocKind::Fn => self
+                                .tcx
+                                .fn_sig(item.def_id)
+                                .inputs()
+                                .skip_binder()
+                                .get(0)
+                                .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
+                                .copied()
+                                .unwrap_or(rcvr_ty),
+                        };
+                        print_disambiguation_help(
+                            item_name,
+                            args,
+                            err,
+                            path,
+                            ty,
+                            item.kind,
+                            item.def_id,
+                            sugg_span,
+                            idx,
+                            self.tcx.sess.source_map(),
+                            item.fn_has_self_parameter,
+                        );
+                    }
+                }
+                CandidateSource::Trait(trait_did) => {
+                    let Some(item) = self.associated_value(trait_did, item_name) else { continue };
+                    let item_span = self.tcx.def_span(item.def_id);
+                    let idx = if sources.len() > 1 {
+                        let msg = &format!(
+                            "candidate #{} is defined in the trait `{}`",
+                            idx + 1,
+                            self.tcx.def_path_str(trait_did)
+                        );
+                        err.span_note(item_span, msg);
+                        Some(idx + 1)
+                    } else {
+                        let msg = &format!(
+                            "the candidate is defined in the trait `{}`",
+                            self.tcx.def_path_str(trait_did)
+                        );
+                        err.span_note(item_span, msg);
+                        None
+                    };
+                    if let Some(sugg_span) = sugg_span {
+                        let path = self.tcx.def_path_str(trait_did);
+                        print_disambiguation_help(
+                            item_name,
+                            args,
+                            err,
+                            path,
+                            rcvr_ty,
+                            item.kind,
+                            item.def_id,
+                            sugg_span,
+                            idx,
+                            self.tcx.sess.source_map(),
+                            item.fn_has_self_parameter,
+                        );
+                    }
+                }
+            }
+        }
+        if sources.len() > limit {
+            err.note(&format!("and {} others", sources.len() - limit));
+        }
+    }
+
     /// Suggest calling `Ty::method` if `.method()` isn't found because the method
     /// doesn't take a `self` receiver.
     fn suggest_associated_call_syntax(
index 34140f3e1fe3e535a0d4d82e5090e9e4e0511821..78cea1f4d8d3e199295d83834e2e33398b5d2851 100644 (file)
@@ -657,7 +657,7 @@ pub fn check_user_unop(
                         }
                     }
 
-                    let sp = self.tcx.sess.source_map().start_point(ex.span);
+                    let sp = self.tcx.sess.source_map().start_point(ex.span).with_parent(None);
                     if let Some(sp) =
                         self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
                     {
index 9bd2202d2601e6f54dcb7a7bac0a5c001e2eb325..d9cdfa9dd4fc9973151c55ecbf98837c65cfbe1e 100644 (file)
@@ -239,7 +239,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
             let mut v = TraitObjectVisitor(FxIndexSet::default());
             v.visit_ty(param.param_ty);
             if let Some((ident, self_ty)) =
-                self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0)
+                NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, item_def_id, &v.0)
                 && self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty)
             {
                 override_error_code = Some(ident.name);
@@ -309,19 +309,12 @@ pub fn suggest_new_region_bound(
                 let did = item_id.owner_id.to_def_id();
                 let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did));
 
-                if let Some(span) = opaque
-                    .bounds
-                    .iter()
-                    .filter_map(|arg| match arg {
-                        GenericBound::Outlives(Lifetime {
-                            res: LifetimeName::Static,
-                            ident,
-                            ..
-                        }) => Some(ident.span),
-                        _ => None,
-                    })
-                    .next()
-                {
+                if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg {
+                    GenericBound::Outlives(Lifetime {
+                        res: LifetimeName::Static, ident, ..
+                    }) => Some(ident.span),
+                    _ => None,
+                }) {
                     if let Some(explicit_static) = &explicit_static {
                         err.span_suggestion_verbose(
                             span,
@@ -338,20 +331,14 @@ pub fn suggest_new_region_bound(
                             Applicability::MaybeIncorrect,
                         );
                     }
-                } else if opaque
-                    .bounds
-                    .iter()
-                    .filter_map(|arg| match arg {
-                        GenericBound::Outlives(Lifetime { ident, .. })
-                            if ident.name.to_string() == lifetime_name =>
-                        {
-                            Some(ident.span)
-                        }
-                        _ => None,
-                    })
-                    .next()
-                    .is_some()
-                {
+                } else if opaque.bounds.iter().any(|arg| match arg {
+                    GenericBound::Outlives(Lifetime { ident, .. })
+                        if ident.name.to_string() == lifetime_name =>
+                    {
+                        true
+                    }
+                    _ => false,
+                }) {
                 } else {
                     err.span_suggestion_verbose(
                         fn_return.span.shrink_to_hi(),
@@ -403,66 +390,54 @@ pub fn suggest_new_region_bound(
 }
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
-    fn get_impl_ident_and_self_ty_from_trait(
-        &self,
+    pub fn get_impl_ident_and_self_ty_from_trait(
+        tcx: TyCtxt<'tcx>,
         def_id: DefId,
         trait_objects: &FxIndexSet<DefId>,
     ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
-        let tcx = self.tcx();
-        match tcx.hir().get_if_local(def_id) {
-            Some(Node::ImplItem(impl_item)) => {
-                match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
+        match tcx.hir().get_if_local(def_id)? {
+            Node::ImplItem(impl_item) => {
+                let impl_did = tcx.hir().get_parent_item(impl_item.hir_id());
+                if let hir::OwnerNode::Item(Item {
+                    kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+                    ..
+                }) = tcx.hir().owner(impl_did)
                 {
-                    Some(Node::Item(Item {
-                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
-                        ..
-                    })) => Some((impl_item.ident, self_ty)),
-                    _ => None,
+                    Some((impl_item.ident, self_ty))
+                } else {
+                    None
                 }
             }
-            Some(Node::TraitItem(trait_item)) => {
-                let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
-                match tcx.hir().find_by_def_id(trait_did.def_id) {
-                    Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
-                        // The method being called is defined in the `trait`, but the `'static`
-                        // obligation comes from the `impl`. Find that `impl` so that we can point
-                        // at it in the suggestion.
-                        let trait_did = trait_did.to_def_id();
-                        match tcx
-                            .hir()
-                            .trait_impls(trait_did)
-                            .iter()
-                            .filter_map(|&impl_did| {
-                                match tcx.hir().get_if_local(impl_did.to_def_id()) {
-                                    Some(Node::Item(Item {
-                                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
-                                        ..
-                                    })) if trait_objects.iter().all(|did| {
-                                        // FIXME: we should check `self_ty` against the receiver
-                                        // type in the `UnifyReceiver` context, but for now, use
-                                        // this imperfect proxy. This will fail if there are
-                                        // multiple `impl`s for the same trait like
-                                        // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
-                                        // In that case, only the first one will get suggestions.
-                                        let mut traits = vec![];
-                                        let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
-                                        hir_v.visit_ty(self_ty);
-                                        !traits.is_empty()
-                                    }) =>
-                                    {
-                                        Some(self_ty)
-                                    }
-                                    _ => None,
-                                }
-                            })
-                            .next()
-                        {
-                            Some(self_ty) => Some((trait_item.ident, self_ty)),
-                            _ => None,
-                        }
+            Node::TraitItem(trait_item) => {
+                let trait_id = tcx.hir().get_parent_item(trait_item.hir_id());
+                debug_assert_eq!(tcx.def_kind(trait_id.def_id), hir::def::DefKind::Trait);
+                // The method being called is defined in the `trait`, but the `'static`
+                // obligation comes from the `impl`. Find that `impl` so that we can point
+                // at it in the suggestion.
+                let trait_did = trait_id.to_def_id();
+                tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
+                    if let Node::Item(Item {
+                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+                        ..
+                    }) = tcx.hir().find_by_def_id(impl_did)?
+                        && trait_objects.iter().all(|did| {
+                            // FIXME: we should check `self_ty` against the receiver
+                            // type in the `UnifyReceiver` context, but for now, use
+                            // this imperfect proxy. This will fail if there are
+                            // multiple `impl`s for the same trait like
+                            // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
+                            // In that case, only the first one will get suggestions.
+                            let mut traits = vec![];
+                            let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
+                            hir_v.visit_ty(self_ty);
+                            !traits.is_empty()
+                        })
+                    {
+                        Some((trait_item.ident, *self_ty))
+                    } else {
+                        None
                     }
-                    _ => None,
-                }
+                })
             }
             _ => None,
         }
@@ -493,7 +468,7 @@ fn find_impl_on_dyn_trait(
 
         // Get the `Ident` of the method being called and the corresponding `impl` (to point at
         // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
-        let Some((ident, self_ty)) = self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0) else {
+        let Some((ident, self_ty)) = NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &v.0) else {
             return false;
         };
 
index 76442de69d35147d7d7634c14d25e2cbef4dcf1b..ee0552d77ceee8080eab5dd43ed6f63f115a2e9f 100644 (file)
@@ -10,6 +10,7 @@
 //! origin crate when the `TyCtxt` is not present in TLS.
 
 use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
+use rustc_middle::dep_graph::TaskDepsRef;
 use rustc_middle::ty::tls;
 use std::fmt;
 
@@ -26,14 +27,22 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
 /// This is a callback from `rustc_ast` as it cannot access the implicit state
 /// in `rustc_middle` otherwise. It is used when diagnostic messages are
 /// emitted and stores them in the current query, if there is one.
-fn track_diagnostic(diagnostic: &Diagnostic) {
+fn track_diagnostic(diagnostic: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
     tls::with_context_opt(|icx| {
         if let Some(icx) = icx {
             if let Some(diagnostics) = icx.diagnostics {
                 let mut diagnostics = diagnostics.lock();
                 diagnostics.extend(Some(diagnostic.clone()));
+                std::mem::drop(diagnostics);
             }
+
+            // Diagnostics are tracked, we can ignore the dependency.
+            let icx = tls::ImplicitCtxt { task_deps: TaskDepsRef::Ignore, ..icx.clone() };
+            return tls::enter_context(&icx, move |_| (*f)(diagnostic));
         }
+
+        // In any other case, invoke diagnostics anyway.
+        (*f)(diagnostic);
     })
 }
 
@@ -55,5 +64,5 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) ->
 pub fn setup_callbacks() {
     rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
     rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
-    TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_)));
+    TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _));
 }
index ff2196d58577c817557e23d497733fbbc7c00f2e..eb3baba999b9cc49b463ad782abf276b766f5cee 100644 (file)
@@ -652,7 +652,6 @@ macro_rules! untracked {
     untracked!(future_incompat_test, true);
     untracked!(hir_stats, true);
     untracked!(identify_regions, true);
-    untracked!(incremental_ignore_spans, true);
     untracked!(incremental_info, true);
     untracked!(incremental_verify_ich, true);
     untracked!(input_stats, true);
@@ -737,6 +736,7 @@ macro_rules! tracked {
     tracked!(fuel, Some(("abc".to_string(), 99)));
     tracked!(function_sections, Some(false));
     tracked!(human_readable_cgu_names, true);
+    tracked!(incremental_ignore_spans, true);
     tracked!(inline_in_all_cgus, Some(true));
     tracked!(inline_mir, Some(true));
     tracked!(inline_mir_hint_threshold, Some(123));
index cdb901b7f8603b65329e31ff6e14e7385db6c222..10d8db5393da94bb6cd64bb73a2f884c6194488d 100644 (file)
@@ -1392,7 +1392,7 @@ fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
     ///
     /// The attribute must be used in conjunction with the
     /// [`closure_track_caller` feature flag]. Otherwise, the `#[track_caller]`
-    /// annotation will function as as no-op.
+    /// annotation will function as a no-op.
     ///
     /// [`closure_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/closure-track-caller.html
     UNGATED_ASYNC_FN_TRACK_CALLER,
index 5f84d5c8b949575394d401a287bbe1b025563376..c18abaef8e2565e450bffb1959adfdf5dde7532b 100644 (file)
@@ -29,7 +29,7 @@ macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
     $cx.pass.$f(&$cx.context, $($args),*);
 }) }
 
-/// Implements the AST traversal for early lint passes. `T` provides the the
+/// Implements the AST traversal for early lint passes. `T` provides the
 /// `check_*` methods.
 pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
     context: EarlyContext<'a>,
index e2876938d70566477329cc94541c81478a3894f1..b2a2656746eec8b45849ec4faf9ce905ef15ec69 100644 (file)
@@ -40,7 +40,7 @@ macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
     $cx.pass.$f(&$cx.context, $($args),*);
 }) }
 
-/// Implements the AST traversal for late lint passes. `T` provides the the
+/// Implements the AST traversal for late lint passes. `T` provides the
 /// `check_*` methods.
 pub struct LateContextAndPass<'tcx, T: LateLintPass<'tcx>> {
     context: LateContext<'tcx>,
index a7a5234049fe63db04d6789e5a509238dd4346ae..525079681ca5cec4eee3f16787df9760519508df 100644 (file)
@@ -256,7 +256,7 @@ fn is_ty_must_use<'tcx>(
                         cx.tcx,
                         cx.tcx.explicit_item_bounds(def).iter().cloned(),
                     )
-                    .filter_map(|obligation| {
+                    .find_map(|obligation| {
                         // We only look at the `DefId`, so it is safe to skip the binder here.
                         if let ty::PredicateKind::Clause(ty::Clause::Trait(
                             ref poly_trait_predicate,
@@ -270,22 +270,17 @@ fn is_ty_must_use<'tcx>(
                         }
                     })
                     .map(|inner| MustUsePath::Opaque(Box::new(inner)))
-                    .next()
                 }
-                ty::Dynamic(binders, _, _) => binders
-                    .iter()
-                    .filter_map(|predicate| {
-                        if let ty::ExistentialPredicate::Trait(ref trait_ref) =
-                            predicate.skip_binder()
-                        {
-                            let def_id = trait_ref.def_id;
-                            is_def_must_use(cx, def_id, span)
-                        } else {
-                            None
-                        }
-                        .map(|inner| MustUsePath::TraitObject(Box::new(inner)))
-                    })
-                    .next(),
+                ty::Dynamic(binders, _, _) => binders.iter().find_map(|predicate| {
+                    if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
+                    {
+                        let def_id = trait_ref.def_id;
+                        is_def_must_use(cx, def_id, span)
+                            .map(|inner| MustUsePath::TraitObject(Box::new(inner)))
+                    } else {
+                        None
+                    }
+                }),
                 ty::Tuple(tys) => {
                     let elem_exprs = if let hir::ExprKind::Tup(elem_exprs) = expr.kind {
                         debug_assert_eq!(elem_exprs.len(), tys.len());
index 842d2a977189d53e6a7e0102ef8a9e7e9823cd57..bd0c08a53c4f20eb2ce5b6a15a561091ce83d0a6 100644 (file)
@@ -16,14 +16,13 @@ fn test_symbols() {
     let m: &syn::ItemMacro = file
         .items
         .iter()
-        .filter_map(|i| {
+        .find_map(|i| {
             if let syn::Item::Macro(m) = i {
                 if m.mac.path == symbols_path { Some(m) } else { None }
             } else {
                 None
             }
         })
-        .next()
         .expect("did not find `symbols!` macro invocation.");
 
     let body_tokens = m.mac.tokens.clone();
index 6112ec9e4e948b6b8d01068f57336c7f83d84067..cee4ba56a9d8f863180eefcb1c3bb4e7745ae23c 100644 (file)
@@ -54,7 +54,7 @@
 use crate::creader::CStore;
 use crate::errors::{
     BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired,
-    RequiredPanicStrategy, RlibRequired, TwoPanicRuntimes,
+    RequiredPanicStrategy, RlibRequired, RustcLibRequired, TwoPanicRuntimes,
 };
 
 use rustc_data_structures::fx::FxHashMap;
@@ -224,7 +224,12 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
                     Linkage::Static => "rlib",
                     _ => "dylib",
                 };
-                sess.emit_err(LibRequired { crate_name: tcx.crate_name(cnum), kind: kind });
+                let crate_name = tcx.crate_name(cnum);
+                if crate_name.as_str().starts_with("rustc_") {
+                    sess.emit_err(RustcLibRequired { crate_name, kind });
+                } else {
+                    sess.emit_err(LibRequired { crate_name, kind });
+                }
             }
         }
     }
index 1e08e95c01f844136f8ca0cee6e1312e133a73a6..02c03114eb67f637cf5b1236e0d25d1310239019 100644 (file)
@@ -24,6 +24,14 @@ pub struct LibRequired<'a> {
     pub kind: &'a str,
 }
 
+#[derive(Diagnostic)]
+#[diag(metadata_rustc_lib_required)]
+#[help]
+pub struct RustcLibRequired<'a> {
+    pub crate_name: Symbol,
+    pub kind: &'a str,
+}
+
 #[derive(Diagnostic)]
 #[diag(metadata_crate_dep_multiple)]
 #[help]
index 99e692ccb584a8ac30c9f60e0c6b224cfaa814c7..d799d3a5ad7799cb9f12656376b8185d448a39fa 100644 (file)
@@ -1160,7 +1160,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
         hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
         upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
         source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
-        if tcx.sess.opts.unstable_opts.incremental_relative_spans {
+        if tcx.sess.opts.incremental_relative_spans() {
             let definitions = tcx.definitions_untracked();
             let mut owner_spans: Vec<_> = krate
                 .owners
index 2ee3f551529f986c44525f9857994b4a29cbafba..1a264d2d5af9a0d6ab1d8eebc2aaba14b9bde5ed 100644 (file)
@@ -3,15 +3,15 @@
 //! ## Overview
 //!
 //! There are two visitors, one for immutable and one for mutable references,
-//! but both are generated by the following macro. The code is written according
-//! to the following conventions:
+//! but both are generated by the `make_mir_visitor` macro.
+//! The code is written according to the following conventions:
 //!
 //! - introduce a `visit_foo` and a `super_foo` method for every MIR type
 //! - `visit_foo`, by default, calls `super_foo`
 //! - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
 //!
-//! This allows you as a user to override `visit_foo` for types are
-//! interested in, and invoke (within that method) call
+//! This allows you to override `visit_foo` for types you are
+//! interested in, and invoke (within that method call)
 //! `self.super_foo` to get the default behavior. Just as in an OO
 //! language, you should never call `super` methods ordinarily except
 //! in that circumstance.
index 3c311729a52aa6dd0f29c912c7230d721ec97bef..03a7f2d70faebb1127bcf952ce28cab88b633923 100644 (file)
@@ -5,6 +5,7 @@
 use rustc_hir as hir;
 use rustc_middle::mir::BorrowKind;
 use rustc_middle::thir::*;
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
 use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
 use rustc_session::lint::Level;
@@ -524,17 +525,19 @@ pub fn emit_unsafe_op_in_unsafe_fn_lint(
         hir_id: hir::HirId,
         span: Span,
     ) {
+        // FIXME: ideally we would want to trim the def paths, but this is not
+        // feasible with the current lint emission API (see issue #106126).
         match self {
-            CallToUnsafeFunction(did) if did.is_some() => tcx.emit_spanned_lint(
+            CallToUnsafeFunction(Some(did)) => tcx.emit_spanned_lint(
                 UNSAFE_OP_IN_UNSAFE_FN,
                 hir_id,
                 span,
                 UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe {
                     span,
-                    function: &tcx.def_path_str(did.unwrap()),
+                    function: &with_no_trimmed_paths!(tcx.def_path_str(*did)),
                 },
             ),
-            CallToUnsafeFunction(..) => tcx.emit_spanned_lint(
+            CallToUnsafeFunction(None) => tcx.emit_spanned_lint(
                 UNSAFE_OP_IN_UNSAFE_FN,
                 hir_id,
                 span,
@@ -594,7 +597,7 @@ pub fn emit_unsafe_op_in_unsafe_fn_lint(
                 span,
                 UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
                     span,
-                    function: &tcx.def_path_str(*did),
+                    function: &with_no_trimmed_paths!(tcx.def_path_str(*did)),
                 },
             ),
         }
@@ -607,24 +610,24 @@ pub fn emit_requires_unsafe_err(
         unsafe_op_in_unsafe_fn_allowed: bool,
     ) {
         match self {
-            CallToUnsafeFunction(did) if did.is_some() && unsafe_op_in_unsafe_fn_allowed => {
+            CallToUnsafeFunction(Some(did)) if unsafe_op_in_unsafe_fn_allowed => {
                 tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
                     span,
-                    function: &tcx.def_path_str(did.unwrap()),
+                    function: &tcx.def_path_str(*did),
                 });
             }
-            CallToUnsafeFunction(did) if did.is_some() => {
+            CallToUnsafeFunction(Some(did)) => {
                 tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafe {
                     span,
-                    function: &tcx.def_path_str(did.unwrap()),
+                    function: &tcx.def_path_str(*did),
                 });
             }
-            CallToUnsafeFunction(..) if unsafe_op_in_unsafe_fn_allowed => {
+            CallToUnsafeFunction(None) if unsafe_op_in_unsafe_fn_allowed => {
                 tcx.sess.emit_err(
                     CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { span },
                 );
             }
-            CallToUnsafeFunction(..) => {
+            CallToUnsafeFunction(None) => {
                 tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless { span });
             }
             UseOfInlineAssembly if unsafe_op_in_unsafe_fn_allowed => {
index 8bdd965deb2098eb5b61e0b589ff6dd8e5ff7f0f..4219e6280ebbca481424a6b7ee3bbef6ed25d41c 100644 (file)
@@ -1,6 +1,7 @@
 //! Inlining pass for MIR functions
 use crate::deref_separator::deref_finder;
 use rustc_attr::InlineAttr;
+use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@@ -27,6 +28,8 @@
 
 const UNKNOWN_SIZE_COST: usize = 10;
 
+const TOP_DOWN_DEPTH_LIMIT: usize = 5;
+
 pub struct Inline;
 
 #[derive(Copy, Clone, Debug)]
@@ -86,8 +89,13 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
 
     let param_env = tcx.param_env_reveal_all_normalized(def_id);
 
-    let mut this =
-        Inliner { tcx, param_env, codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), changed: false };
+    let mut this = Inliner {
+        tcx,
+        param_env,
+        codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
+        history: Vec::new(),
+        changed: false,
+    };
     let blocks = BasicBlock::new(0)..body.basic_blocks.next_index();
     this.process_blocks(body, blocks);
     this.changed
@@ -98,12 +106,26 @@ struct Inliner<'tcx> {
     param_env: ParamEnv<'tcx>,
     /// Caller codegen attributes.
     codegen_fn_attrs: &'tcx CodegenFnAttrs,
+    /// Stack of inlined instances.
+    /// We only check the `DefId` and not the substs because we want to
+    /// avoid inlining cases of polymorphic recursion.
+    /// The number of `DefId`s is finite, so checking history is enough
+    /// to ensure that we do not loop endlessly while inlining.
+    history: Vec<DefId>,
     /// Indicates that the caller body has been modified.
     changed: bool,
 }
 
 impl<'tcx> Inliner<'tcx> {
     fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBlock>) {
+        // How many callsites in this body are we allowed to inline? We need to limit this in order
+        // to prevent super-linear growth in MIR size
+        let inline_limit = match self.history.len() {
+            0 => usize::MAX,
+            1..=TOP_DOWN_DEPTH_LIMIT => 1,
+            _ => return,
+        };
+        let mut inlined_count = 0;
         for bb in blocks {
             let bb_data = &caller_body[bb];
             if bb_data.is_cleanup {
@@ -122,12 +144,16 @@ fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBl
                     debug!("not-inlined {} [{}]", callsite.callee, reason);
                     continue;
                 }
-                Ok(_) => {
+                Ok(new_blocks) => {
                     debug!("inlined {}", callsite.callee);
                     self.changed = true;
-                    // We could process the blocks returned by `try_inlining` here. However, that
-                    // leads to exponential compile times due to the top-down nature of this kind
-                    // of inlining.
+                    inlined_count += 1;
+                    if inlined_count == inline_limit {
+                        return;
+                    }
+                    self.history.push(callsite.callee.def_id());
+                    self.process_blocks(caller_body, new_blocks);
+                    self.history.pop();
                 }
             }
         }
@@ -301,6 +327,10 @@ fn resolve_callsite(
                     return None;
                 }
 
+                if self.history.contains(&callee.def_id()) {
+                    return None;
+                }
+
                 let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs);
                 let source_info = SourceInfo { span: fn_span, ..terminator.source_info };
 
index d426a2b6b78a0655220e6785f4b390a87f0d4b05..2d243e13cc21249a6679d1e298be44dce69c7024 100644 (file)
@@ -34,7 +34,6 @@
 pub use rustc_query_system::query::{deadlock, QueryContext};
 
 pub use rustc_query_system::query::QueryConfig;
-pub(crate) use rustc_query_system::query::QueryVTable;
 
 mod on_disk_cache;
 pub use on_disk_cache::OnDiskCache;
index 9ffcc5672cc33676c2b37077603f21eeff3cb402..535445e70bc15c519afd3abd47164c09b010af63 100644 (file)
@@ -493,28 +493,32 @@ fn query_cache<'a>(tcx: QueryCtxt<'tcx>) -> &'a Self::Cache
                 &tcx.query_caches.$name
             }
 
+            fn execute_query(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Stored {
+                tcx.$name(key)
+            }
+
             #[inline]
-            fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
-                QueryVTable<QueryCtxt<'tcx>, Self::Key, Self::Value>
-            {
-                let compute = get_provider!([$($modifiers)*][tcx, $name, key]);
-                let cache_on_disk = Self::cache_on_disk(tcx.tcx, key);
-                QueryVTable {
-                    anon: is_anon!([$($modifiers)*]),
-                    eval_always: is_eval_always!([$($modifiers)*]),
-                    depth_limit: depth_limit!([$($modifiers)*]),
-                    feedable: feedable!([$($modifiers)*]),
-                    dep_kind: dep_graph::DepKind::$name,
-                    hash_result: hash_result!([$($modifiers)*]),
-                    handle_cycle_error: handle_cycle_error!([$($modifiers)*]),
-                    compute,
-                    try_load_from_disk: if cache_on_disk { should_ever_cache_on_disk!([$($modifiers)*]) } else { None },
-                }
+            // key is only sometimes used
+            #[allow(unused_variables)]
+            fn compute(qcx: QueryCtxt<'tcx>, key: &Self::Key) -> fn(TyCtxt<'tcx>, Self::Key) -> Self::Value {
+                get_provider!([$($modifiers)*][qcx, $name, key])
             }
 
-            fn execute_query(tcx: TyCtxt<'tcx>, k: Self::Key) -> Self::Stored {
-                tcx.$name(k)
+            #[inline]
+            fn try_load_from_disk(qcx: QueryCtxt<'tcx>, key: &Self::Key) -> rustc_query_system::query::TryLoadFromDisk<QueryCtxt<'tcx>, Self> {
+                let cache_on_disk = Self::cache_on_disk(qcx.tcx, key);
+                if cache_on_disk { should_ever_cache_on_disk!([$($modifiers)*]) } else { None }
             }
+
+            const ANON: bool = is_anon!([$($modifiers)*]);
+            const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
+            const DEPTH_LIMIT: bool = depth_limit!([$($modifiers)*]);
+            const FEEDABLE: bool = feedable!([$($modifiers)*]);
+
+            const DEP_KIND: rustc_middle::dep_graph::DepKind = dep_graph::DepKind::$name;
+            const HANDLE_CYCLE_ERROR: rustc_query_system::HandleCycleError = handle_cycle_error!([$($modifiers)*]);
+
+            const HASH_RESULT: rustc_query_system::query::HashResult<QueryCtxt<'tcx>, Self> = hash_result!([$($modifiers)*]);
         })*
 
         #[allow(nonstandard_style)]
index 52957ee0222387b62747d335e3429016184cf0bf..0b1ff5d709fe904e96dd3703ba79966817af37c0 100644 (file)
@@ -634,7 +634,7 @@ pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode<K>, debug_str_gen
         if dep_node_debug.borrow().contains_key(&dep_node) {
             return;
         }
-        let debug_str = debug_str_gen();
+        let debug_str = self.with_ignore(debug_str_gen);
         dep_node_debug.borrow_mut().insert(dep_node, debug_str);
     }
 
@@ -829,7 +829,9 @@ fn try_mark_previous_green<Qcx: QueryContext<DepKind = K>>(
         );
 
         if !side_effects.is_empty() {
-            self.emit_side_effects(qcx, data, dep_node_index, side_effects);
+            self.with_query_deserialization(|| {
+                self.emit_side_effects(qcx, data, dep_node_index, side_effects)
+            });
         }
 
         // ... and finally storing a "Green" entry in the color map.
index 24c960765df8a387b8a177d3a8b4741d13204f3f..8c0330e438de4724711816ed47742d1e5537aee1 100644 (file)
@@ -1,7 +1,6 @@
 //! Query configuration and description traits.
 
-use crate::dep_graph::DepNode;
-use crate::dep_graph::SerializedDepNodeIndex;
+use crate::dep_graph::{DepNode, DepNodeParams, SerializedDepNodeIndex};
 use crate::error::HandleCycleError;
 use crate::ich::StableHashingContext;
 use crate::query::caches::QueryCache;
 use std::fmt::Debug;
 use std::hash::Hash;
 
+pub type HashResult<Qcx, Q> =
+    Option<fn(&mut StableHashingContext<'_>, &<Q as QueryConfig<Qcx>>::Value) -> Fingerprint>;
+
+pub type TryLoadFromDisk<Qcx, Q> =
+    Option<fn(Qcx, SerializedDepNodeIndex) -> Option<<Q as QueryConfig<Qcx>>::Value>>;
+
 pub trait QueryConfig<Qcx: QueryContext> {
     const NAME: &'static str;
 
-    type Key: Eq + Hash + Clone + Debug;
+    type Key: DepNodeParams<Qcx::DepContext> + Eq + Hash + Clone + Debug;
     type Value: Debug;
     type Stored: Debug + Clone + std::borrow::Borrow<Self::Value>;
 
@@ -30,39 +35,27 @@ fn query_cache<'a>(tcx: Qcx) -> &'a Self::Cache
     where
         Qcx: 'a;
 
-    // Don't use this method to compute query results, instead use the methods on TyCtxt
-    fn make_vtable(tcx: Qcx, key: &Self::Key) -> QueryVTable<Qcx, Self::Key, Self::Value>;
-
     fn cache_on_disk(tcx: Qcx::DepContext, key: &Self::Key) -> bool;
 
     // Don't use this method to compute query results, instead use the methods on TyCtxt
     fn execute_query(tcx: Qcx::DepContext, k: Self::Key) -> Self::Stored;
-}
 
-#[derive(Copy, Clone)]
-pub struct QueryVTable<Qcx: QueryContext, K, V> {
-    pub anon: bool,
-    pub dep_kind: Qcx::DepKind,
-    pub eval_always: bool,
-    pub depth_limit: bool,
-    pub feedable: bool,
-
-    pub compute: fn(Qcx::DepContext, K) -> V,
-    pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
-    pub handle_cycle_error: HandleCycleError,
-    // NOTE: this is also `None` if `cache_on_disk()` returns false, not just if it's unsupported by the query
-    pub try_load_from_disk: Option<fn(Qcx, SerializedDepNodeIndex) -> Option<V>>,
-}
+    fn compute(tcx: Qcx, key: &Self::Key) -> fn(Qcx::DepContext, Self::Key) -> Self::Value;
 
-impl<Qcx: QueryContext, K, V> QueryVTable<Qcx, K, V> {
-    pub(crate) fn to_dep_node(&self, tcx: Qcx::DepContext, key: &K) -> DepNode<Qcx::DepKind>
-    where
-        K: crate::dep_graph::DepNodeParams<Qcx::DepContext>,
-    {
-        DepNode::construct(tcx, self.dep_kind, key)
-    }
+    fn try_load_from_disk(qcx: Qcx, idx: &Self::Key) -> TryLoadFromDisk<Qcx, Self>;
+
+    const ANON: bool;
+    const EVAL_ALWAYS: bool;
+    const DEPTH_LIMIT: bool;
+    const FEEDABLE: bool;
+
+    const DEP_KIND: Qcx::DepKind;
+    const HANDLE_CYCLE_ERROR: HandleCycleError;
+
+    const HASH_RESULT: HashResult<Qcx, Self>;
 
-    pub(crate) fn compute(&self, tcx: Qcx::DepContext, key: K) -> V {
-        (self.compute)(tcx, key)
+    // Just here for convernience and checking that the key matches the kind, don't override this.
+    fn construct_dep_node(tcx: Qcx::DepContext, key: &Self::Key) -> DepNode<Qcx::DepKind> {
+        DepNode::construct(tcx, Self::DEP_KIND, key)
     }
 }
index ce9179ea832e75e8fbc6e61ff2f00b108ae8f1f5..d308af192076051ef23b0098f3375e39791a879a 100644 (file)
@@ -12,7 +12,7 @@
 };
 
 mod config;
-pub use self::config::{QueryConfig, QueryVTable};
+pub use self::config::{HashResult, QueryConfig, TryLoadFromDisk};
 
 use crate::dep_graph::DepKind;
 use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
index 53844dab9db59490992e073f0b62bf742df3f223..da1ac6a5fb227dd48daf9c075a238a2ebbf4b773 100644 (file)
@@ -2,10 +2,9 @@
 //! generate the actual methods on tcx which find and execute the provider,
 //! manage the caches, and so forth.
 
-use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams};
+use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex};
 use crate::ich::StableHashingContext;
 use crate::query::caches::QueryCache;
-use crate::query::config::QueryVTable;
 use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo};
 use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
 use crate::values::Value;
@@ -361,36 +360,34 @@ pub fn try_get_cached<Tcx, C, R, OnHit>(
     })
 }
 
-fn try_execute_query<Qcx, C>(
+fn try_execute_query<Q, Qcx>(
     qcx: Qcx,
-    state: &QueryState<C::Key, Qcx::DepKind>,
-    cache: &C,
+    state: &QueryState<Q::Key, Qcx::DepKind>,
+    cache: &Q::Cache,
     span: Span,
-    key: C::Key,
+    key: Q::Key,
     dep_node: Option<DepNode<Qcx::DepKind>>,
-    query: &QueryVTable<Qcx, C::Key, C::Value>,
-) -> (C::Stored, Option<DepNodeIndex>)
+) -> (Q::Stored, Option<DepNodeIndex>)
 where
-    C: QueryCache,
-    C::Key: Clone + DepNodeParams<Qcx::DepContext>,
-    C::Value: Value<Qcx::DepContext, Qcx::DepKind>,
-    C::Stored: Debug + std::borrow::Borrow<C::Value>,
+    Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
 {
-    match JobOwner::<'_, C::Key, Qcx::DepKind>::try_start(&qcx, state, span, key.clone()) {
+    match JobOwner::<'_, Q::Key, Qcx::DepKind>::try_start(&qcx, state, span, key.clone()) {
         TryGetJob::NotYetStarted(job) => {
-            let (result, dep_node_index) = execute_job(qcx, key.clone(), dep_node, query, job.id);
-            if query.feedable {
+            let (result, dep_node_index) =
+                execute_job::<Q, Qcx>(qcx, key.clone(), dep_node, job.id);
+            if Q::FEEDABLE {
                 // We may have put a value inside the cache from inside the execution.
                 // Verify that it has the same hash as what we have now, to ensure consistency.
                 let _ = cache.lookup(&key, |cached_result, _| {
-                    let hasher = query.hash_result.expect("feedable forbids no_hash");
+                    let hasher = Q::HASH_RESULT.expect("feedable forbids no_hash");
+
                     let old_hash = qcx.dep_context().with_stable_hashing_context(|mut hcx| hasher(&mut hcx, cached_result.borrow()));
                     let new_hash = qcx.dep_context().with_stable_hashing_context(|mut hcx| hasher(&mut hcx, &result));
                     debug_assert_eq!(
                         old_hash, new_hash,
                         "Computed query value for {:?}({:?}) is inconsistent with fed value,\ncomputed={:#?}\nfed={:#?}",
-                        query.dep_kind, key, result, cached_result,
+                        Q::DEP_KIND, key, result, cached_result,
                     );
                 });
             }
@@ -398,7 +395,7 @@ fn try_execute_query<Qcx, C>(
             (result, Some(dep_node_index))
         }
         TryGetJob::Cycle(error) => {
-            let result = mk_cycle(qcx, error, query.handle_cycle_error, cache);
+            let result = mk_cycle(qcx, error, Q::HANDLE_CYCLE_ERROR, cache);
             (result, None)
         }
         #[cfg(parallel_compiler)]
@@ -417,16 +414,14 @@ fn try_execute_query<Qcx, C>(
     }
 }
 
-fn execute_job<Qcx, K, V>(
+fn execute_job<Q, Qcx>(
     qcx: Qcx,
-    key: K,
+    key: Q::Key,
     mut dep_node_opt: Option<DepNode<Qcx::DepKind>>,
-    query: &QueryVTable<Qcx, K, V>,
     job_id: QueryJobId,
-) -> (V, DepNodeIndex)
+) -> (Q::Value, DepNodeIndex)
 where
-    K: Clone + DepNodeParams<Qcx::DepContext>,
-    V: Debug,
+    Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
 {
     let dep_graph = qcx.dep_context().dep_graph();
@@ -434,23 +429,23 @@ fn execute_job<Qcx, K, V>(
     // Fast path for when incr. comp. is off.
     if !dep_graph.is_fully_enabled() {
         let prof_timer = qcx.dep_context().profiler().query_provider();
-        let result = qcx.start_query(job_id, query.depth_limit, None, || {
-            query.compute(*qcx.dep_context(), key)
+        let result = qcx.start_query(job_id, Q::DEPTH_LIMIT, None, || {
+            Q::compute(qcx, &key)(*qcx.dep_context(), key)
         });
         let dep_node_index = dep_graph.next_virtual_depnode_index();
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
         return (result, dep_node_index);
     }
 
-    if !query.anon && !query.eval_always {
+    if !Q::ANON && !Q::EVAL_ALWAYS {
         // `to_dep_node` is expensive for some `DepKind`s.
         let dep_node =
-            dep_node_opt.get_or_insert_with(|| query.to_dep_node(*qcx.dep_context(), &key));
+            dep_node_opt.get_or_insert_with(|| Q::construct_dep_node(*qcx.dep_context(), &key));
 
         // The diagnostics for this query will be promoted to the current session during
         // `try_mark_green()`, so we can ignore them here.
         if let Some(ret) = qcx.start_query(job_id, false, None, || {
-            try_load_from_disk_and_cache_in_memory(qcx, &key, &dep_node, query)
+            try_load_from_disk_and_cache_in_memory::<Q, Qcx>(qcx, &key, &dep_node)
         }) {
             return ret;
         }
@@ -460,18 +455,19 @@ fn execute_job<Qcx, K, V>(
     let diagnostics = Lock::new(ThinVec::new());
 
     let (result, dep_node_index) =
-        qcx.start_query(job_id, query.depth_limit, Some(&diagnostics), || {
-            if query.anon {
-                return dep_graph.with_anon_task(*qcx.dep_context(), query.dep_kind, || {
-                    query.compute(*qcx.dep_context(), key)
+        qcx.start_query(job_id, Q::DEPTH_LIMIT, Some(&diagnostics), || {
+            if Q::ANON {
+                return dep_graph.with_anon_task(*qcx.dep_context(), Q::DEP_KIND, || {
+                    Q::compute(qcx, &key)(*qcx.dep_context(), key)
                 });
             }
 
             // `to_dep_node` is expensive for some `DepKind`s.
             let dep_node =
-                dep_node_opt.unwrap_or_else(|| query.to_dep_node(*qcx.dep_context(), &key));
+                dep_node_opt.unwrap_or_else(|| Q::construct_dep_node(*qcx.dep_context(), &key));
 
-            dep_graph.with_task(dep_node, *qcx.dep_context(), key, query.compute, query.hash_result)
+            let task = Q::compute(qcx, &key);
+            dep_graph.with_task(dep_node, *qcx.dep_context(), key, task, Q::HASH_RESULT)
         });
 
     prof_timer.finish_with_query_invocation_id(dep_node_index.into());
@@ -480,7 +476,7 @@ fn execute_job<Qcx, K, V>(
     let side_effects = QuerySideEffects { diagnostics };
 
     if std::intrinsics::unlikely(!side_effects.is_empty()) {
-        if query.anon {
+        if Q::ANON {
             qcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
         } else {
             qcx.store_side_effects(dep_node_index, side_effects);
@@ -490,16 +486,14 @@ fn execute_job<Qcx, K, V>(
     (result, dep_node_index)
 }
 
-fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
+fn try_load_from_disk_and_cache_in_memory<Q, Qcx>(
     qcx: Qcx,
-    key: &K,
+    key: &Q::Key,
     dep_node: &DepNode<Qcx::DepKind>,
-    query: &QueryVTable<Qcx, K, V>,
-) -> Option<(V, DepNodeIndex)>
+) -> Option<(Q::Value, DepNodeIndex)>
 where
-    K: Clone,
+    Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
-    V: Debug,
 {
     // Note this function can be called concurrently from the same query
     // We must ensure that this is handled correctly.
@@ -511,7 +505,7 @@ fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
 
     // First we try to load the result from the on-disk cache.
     // Some things are never cached on disk.
-    if let Some(try_load_from_disk) = query.try_load_from_disk {
+    if let Some(try_load_from_disk) = Q::try_load_from_disk(qcx, &key) {
         let prof_timer = qcx.dep_context().profiler().incr_cache_loading();
 
         // The call to `with_query_deserialization` enforces that no new `DepNodes`
@@ -545,7 +539,7 @@ fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
             if std::intrinsics::unlikely(
                 try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich,
             ) {
-                incremental_verify_ich(*qcx.dep_context(), &result, dep_node, query.hash_result);
+                incremental_verify_ich(*qcx.dep_context(), &result, dep_node, Q::HASH_RESULT);
             }
 
             return Some((result, dep_node_index));
@@ -565,7 +559,7 @@ fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
     let prof_timer = qcx.dep_context().profiler().query_provider();
 
     // The dep-graph for this computation is already in-place.
-    let result = dep_graph.with_ignore(|| query.compute(*qcx.dep_context(), key.clone()));
+    let result = dep_graph.with_ignore(|| Q::compute(qcx, key)(*qcx.dep_context(), key.clone()));
 
     prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
@@ -578,7 +572,7 @@ fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
     //
     // See issue #82920 for an example of a miscompilation that would get turned into
     // an ICE by this check
-    incremental_verify_ich(*qcx.dep_context(), &result, dep_node, query.hash_result);
+    incremental_verify_ich(*qcx.dep_context(), &result, dep_node, Q::HASH_RESULT);
 
     Some((result, dep_node_index))
 }
@@ -699,23 +693,19 @@ fn incremental_verify_ich_failed(sess: &Session, dep_node: DebugArg<'_>, result:
 ///
 /// Note: The optimization is only available during incr. comp.
 #[inline(never)]
-fn ensure_must_run<Qcx, K, V>(
-    qcx: Qcx,
-    key: &K,
-    query: &QueryVTable<Qcx, K, V>,
-) -> (bool, Option<DepNode<Qcx::DepKind>>)
+fn ensure_must_run<Q, Qcx>(qcx: Qcx, key: &Q::Key) -> (bool, Option<DepNode<Qcx::DepKind>>)
 where
-    K: crate::dep_graph::DepNodeParams<Qcx::DepContext>,
+    Q: QueryConfig<Qcx>,
     Qcx: QueryContext,
 {
-    if query.eval_always {
+    if Q::EVAL_ALWAYS {
         return (true, None);
     }
 
     // Ensuring an anonymous query makes no sense
-    assert!(!query.anon);
+    assert!(!Q::ANON);
 
-    let dep_node = query.to_dep_node(*qcx.dep_context(), key);
+    let dep_node = Q::construct_dep_node(*qcx.dep_context(), key);
 
     let dep_graph = qcx.dep_context().dep_graph();
     match dep_graph.try_mark_green(qcx, &dep_node) {
@@ -746,13 +736,11 @@ pub fn get_query<Q, Qcx, D>(qcx: Qcx, span: Span, key: Q::Key, mode: QueryMode)
 where
     D: DepKind,
     Q: QueryConfig<Qcx>,
-    Q::Key: DepNodeParams<Qcx::DepContext>,
     Q::Value: Value<Qcx::DepContext, D>,
     Qcx: QueryContext,
 {
-    let query = Q::make_vtable(qcx, &key);
     let dep_node = if let QueryMode::Ensure = mode {
-        let (must_run, dep_node) = ensure_must_run(qcx, &key, &query);
+        let (must_run, dep_node) = ensure_must_run::<Q, _>(qcx, &key);
         if !must_run {
             return None;
         }
@@ -761,14 +749,13 @@ pub fn get_query<Q, Qcx, D>(qcx: Qcx, span: Span, key: Q::Key, mode: QueryMode)
         None
     };
 
-    let (result, dep_node_index) = try_execute_query(
+    let (result, dep_node_index) = try_execute_query::<Q, Qcx>(
         qcx,
         Q::query_state(qcx),
         Q::query_cache(qcx),
         span,
         key,
         dep_node,
-        &query,
     );
     if let Some(dep_node_index) = dep_node_index {
         qcx.dep_context().dep_graph().read_index(dep_node_index)
@@ -780,7 +767,6 @@ pub fn force_query<Q, Qcx, D>(qcx: Qcx, key: Q::Key, dep_node: DepNode<Qcx::DepK
 where
     D: DepKind,
     Q: QueryConfig<Qcx>,
-    Q::Key: DepNodeParams<Qcx::DepContext>,
     Q::Value: Value<Qcx::DepContext, D>,
     Qcx: QueryContext,
 {
@@ -798,9 +784,8 @@ pub fn force_query<Q, Qcx, D>(qcx: Qcx, key: Q::Key, dep_node: DepNode<Qcx::DepK
         Err(()) => {}
     }
 
-    let query = Q::make_vtable(qcx, &key);
     let state = Q::query_state(qcx);
-    debug_assert!(!query.anon);
+    debug_assert!(!Q::ANON);
 
-    try_execute_query(qcx, state, cache, DUMMY_SP, key, Some(dep_node), &query);
+    try_execute_query::<Q, _>(qcx, state, cache, DUMMY_SP, key, Some(dep_node));
 }
index 0c4b35b88335ad5e429b68d74e14db5555fb3451..e41fe325b811cb42cf118565782a00e1f75df0eb 100644 (file)
@@ -820,13 +820,12 @@ fn resolve_ident_in_module_unadjusted_ext(
             // binding if it exists. What we really want here is having two separate scopes in
             // a module - one for non-globs and one for globs, but until that's done use this
             // hack to avoid inconsistent resolution ICEs during import validation.
-            let binding = [resolution.binding, resolution.shadowed_glob]
-                .into_iter()
-                .filter_map(|binding| match (binding, ignore_binding) {
+            let binding = [resolution.binding, resolution.shadowed_glob].into_iter().find_map(
+                |binding| match (binding, ignore_binding) {
                     (Some(binding), Some(ignored)) if ptr::eq(binding, ignored) => None,
                     _ => binding,
-                })
-                .next();
+                },
+            );
             let Some(binding) = binding else {
                 return Err((Determined, Weak::No));
             };
index 3bafd3730bd79d2db4cb31d95bda50d7e756a492..02e3992a6a940d5b6a53c723fdba5c624f979c03 100644 (file)
@@ -787,6 +787,12 @@ pub fn share_generics(&self) -> bool {
     pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
         self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
     }
+
+    #[allow(rustc::bad_opt_access)]
+    pub fn incremental_relative_spans(&self) -> bool {
+        self.unstable_opts.incremental_relative_spans
+            || (self.unstable_features.is_nightly_build() && self.incremental.is_some())
+    }
 }
 
 impl UnstableOptions {
index ae01efebacc21e9f4ffc41ef8a25e6b07a93f871..9bf581ff73d23c01d918df44afa709605f93c28b 100644 (file)
@@ -1332,11 +1332,12 @@ pub(crate) fn parse_proc_macro_execution_strategy(
         "generate human-readable, predictable names for codegen units (default: no)"),
     identify_regions: bool = (false, parse_bool, [UNTRACKED],
         "display unnamed regions as `'<id>`, using a non-ident unique id (default: no)"),
-    incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
+    incremental_ignore_spans: bool = (false, parse_bool, [TRACKED],
         "ignore spans during ICH computation -- used for testing (default: no)"),
     incremental_info: bool = (false, parse_bool, [UNTRACKED],
         "print high-level information about incremental reuse (or the lack thereof) \
         (default: no)"),
+    #[rustc_lint_opt_deny_field_access("use `Session::incremental_relative_spans` instead of this field")]
     incremental_relative_spans: bool = (false, parse_bool, [TRACKED],
         "hash spans relative to their parent item for incr. comp. (default: no)"),
     incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
index 7d1443559fe53b503637cedbc156957a68c869a5..4e70dfb614782e015325fb216133bba7d8eeda82 100644 (file)
@@ -104,6 +104,10 @@ fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str)
         // `-Z incremental-ignore-spans` option. Normally, this option is disabled,
         // which will cause us to require that this method always be called with `Span` hashing
         // enabled.
+        //
+        // Span hashing can also be disabled without `-Z incremental-ignore-spans`.
+        // This is the case for instance when building a hash for name mangling.
+        // Such configuration must not be used for metadata.
         HashingControls { hash_spans }
             if hash_spans == !ctx.unstable_opts_incremental_ignore_spans() => {}
         other => panic!("Attempted hashing of {msg} with non-default HashingControls: {:?}", other),
index f0e91e5a6a917c3373fa399a2e496fe243ab805d..d48c4f7e5a8119f1c84f2a9b32d043dcab05e898 100644 (file)
@@ -4,7 +4,7 @@
 // The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
 // See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28
 
-use crate::def_id::LocalDefId;
+use crate::def_id::{DefIndex, LocalDefId};
 use crate::hygiene::SyntaxContext;
 use crate::SPAN_TRACK;
 use crate::{BytePos, SpanData};
@@ -13,8 +13,8 @@
 
 /// A compressed span.
 ///
-/// Whereas [`SpanData`] is 12 bytes, which is a bit too big to stick everywhere, `Span`
-/// is a form that only takes up 8 bytes, with less space for the length and
+/// Whereas [`SpanData`] is 16 bytes, which is a bit too big to stick everywhere, `Span`
+/// is a form that only takes up 8 bytes, with less space for the length, parent and
 /// context. The vast majority (99.9%+) of `SpanData` instances will fit within
 /// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are
 /// stored in a separate interner table, and the `Span` will index into that
@@ -25,7 +25,7 @@
 /// slower because only 80--90% of spans could be stored inline (even less in
 /// very large crates) and so the interner was used a lot more.
 ///
-/// Inline (compressed) format:
+/// Inline (compressed) format with no parent:
 /// - `span.base_or_index == span_data.lo`
 /// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
 /// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
 /// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
 /// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
 ///
+/// Inline (compressed) format with root context:
+/// - `span.base_or_index == span_data.lo`
+/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
+/// - `span.len_or_tag` has top bit (`PARENT_MASK`) set
+/// - `span.ctxt == span_data.parent` (must be `<= MAX_CTXT`)
+///
 /// Interned format:
 /// - `span.base_or_index == index` (indexes into the interner table)
 /// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
@@ -73,7 +79,8 @@ pub struct Span {
     ctxt_or_tag: u16,
 }
 
-const LEN_TAG: u16 = 0b1000_0000_0000_0000;
+const LEN_TAG: u16 = 0b1111_1111_1111_1111;
+const PARENT_MASK: u16 = 0b1000_0000_0000_0000;
 const MAX_LEN: u32 = 0b0111_1111_1111_1111;
 const CTXT_TAG: u32 = 0b1111_1111_1111_1111;
 const MAX_CTXT: u32 = CTXT_TAG - 1;
@@ -95,16 +102,32 @@ pub fn new(
 
         let (base, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32());
 
-        if len <= MAX_LEN && ctxt2 <= MAX_CTXT && parent.is_none() {
-            // Inline format.
-            Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_tag: ctxt2 as u16 }
-        } else {
-            // Interned format.
-            let index =
-                with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
-            let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
-            Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
+        if len <= MAX_LEN && ctxt2 <= MAX_CTXT {
+            let len_or_tag = len as u16;
+            debug_assert_eq!(len_or_tag & PARENT_MASK, 0);
+
+            if let Some(parent) = parent {
+                // Inline format with parent.
+                let len_or_tag = len_or_tag | PARENT_MASK;
+                let parent2 = parent.local_def_index.as_u32();
+                if ctxt2 == SyntaxContext::root().as_u32() && parent2 <= MAX_CTXT {
+                    return Span { base_or_index: base, len_or_tag, ctxt_or_tag: parent2 as u16 };
+                }
+            } else {
+                // Inline format with ctxt.
+                return Span {
+                    base_or_index: base,
+                    len_or_tag: len as u16,
+                    ctxt_or_tag: ctxt2 as u16,
+                };
+            }
         }
+
+        // Interned format.
+        let index =
+            with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
+        let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
+        Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
     }
 
     #[inline]
@@ -122,12 +145,25 @@ pub fn data(self) -> SpanData {
     pub fn data_untracked(self) -> SpanData {
         if self.len_or_tag != LEN_TAG {
             // Inline format.
-            debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
-            SpanData {
-                lo: BytePos(self.base_or_index),
-                hi: BytePos(self.base_or_index + self.len_or_tag as u32),
-                ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
-                parent: None,
+            if self.len_or_tag & PARENT_MASK == 0 {
+                debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
+                SpanData {
+                    lo: BytePos(self.base_or_index),
+                    hi: BytePos(self.base_or_index + self.len_or_tag as u32),
+                    ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
+                    parent: None,
+                }
+            } else {
+                let len = self.len_or_tag & !PARENT_MASK;
+                debug_assert!(len as u32 <= MAX_LEN);
+                let parent =
+                    LocalDefId { local_def_index: DefIndex::from_u32(self.ctxt_or_tag as u32) };
+                SpanData {
+                    lo: BytePos(self.base_or_index),
+                    hi: BytePos(self.base_or_index + len as u32),
+                    ctxt: SyntaxContext::root(),
+                    parent: Some(parent),
+                }
             }
         } else {
             // Interned format.
@@ -141,8 +177,14 @@ pub fn data_untracked(self) -> SpanData {
     pub fn ctxt(self) -> SyntaxContext {
         let ctxt_or_tag = self.ctxt_or_tag as u32;
         if ctxt_or_tag <= MAX_CTXT {
-            // Inline format or interned format with inline ctxt.
-            SyntaxContext::from_u32(ctxt_or_tag)
+            if self.len_or_tag == LEN_TAG || self.len_or_tag & PARENT_MASK == 0 {
+                // Inline format or interned format with inline ctxt.
+                SyntaxContext::from_u32(ctxt_or_tag)
+            } else {
+                // Inline format or interned format with inline parent.
+                // We know that the SyntaxContext is root.
+                SyntaxContext::root()
+            }
         } else {
             // Interned format.
             let index = self.base_or_index;
index 8d73a83aec96e119639b011ab134ff94176f964c..fdd6adb681be4cba1aa43187d323db65e864b3b4 100644 (file)
@@ -36,7 +36,7 @@ pub(super) fn did_overflow(&self) -> bool {
 
     #[inline]
     pub(super) fn has_overflow(&self, depth: usize) -> bool {
-        self.current_limit.value_within_limit(depth + self.additional_depth)
+        !self.current_limit.value_within_limit(depth + self.additional_depth)
     }
 
     /// Updating the current limit when hitting overflow.
index 06ab0e8d94470cdbbcd258be58665ba73bf597d0..7c21a1047bcbfc5c3a04de884663780a3b56f66f 100644 (file)
@@ -3237,7 +3237,7 @@ fn note_function_argument_obligation(
         })) = call_node
         {
             if Some(rcvr.span) == err.span.primary_span() {
-                err.replace_span_with(path.ident.span);
+                err.replace_span_with(path.ident.span, true);
             }
         }
         if let Some(Node::Expr(hir::Expr {
index d644cbccea11b2df6c5080a2191ad3c1c8b8f4f1..73d2d278f93f3bb0886c518448ba59ccd25c402c 100644 (file)
@@ -273,9 +273,11 @@ fn adjust_for_rust_scalar<'tcx>(
                 | PointerKind::UniqueBorrowed
                 | PointerKind::UniqueBorrowedPinned => false,
                 PointerKind::UniqueOwned => noalias_for_box,
-                PointerKind::Frozen => !is_return,
+                PointerKind::Frozen => true,
             };
-            if no_alias {
+            // We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics
+            // (see <https://github.com/rust-lang/unsafe-code-guidelines/issues/385#issuecomment-1368055745>).
+            if no_alias && !is_return {
                 attrs.set(ArgAttribute::NoAlias);
             }
 
index a2fdec6fbfe7b18b3c0ae48fc9956935c885c8d6..fe6de1cf879b2e2395173f1d4e5d3c80ea2a1fe9 100644 (file)
@@ -402,7 +402,20 @@ pub mod __alloc_error_handler {
     // `#[alloc_error_handler]`.
     #[rustc_std_internal_symbol]
     pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
-        panic!("memory allocation of {size} bytes failed")
+        extern "Rust" {
+            // This symbol is emitted by rustc next to __rust_alloc_error_handler.
+            // Its value depends on the -Zoom={panic,abort} compiler option.
+            static __rust_alloc_error_handler_should_panic: u8;
+        }
+
+        #[allow(unused_unsafe)]
+        if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
+            panic!("memory allocation of {size} bytes failed")
+        } else {
+            core::panicking::panic_nounwind_fmt(format_args!(
+                "memory allocation of {size} bytes failed"
+            ))
+        }
     }
 }
 
index 9857f0516baa217f84fc0e66223c4e53bf0da7a4..bb1a85eb2203bee7266dd89e51339106cca94299 100644 (file)
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_refs_to_cell)]
 #![feature(core_intrinsics)]
+#![feature(core_panic)]
 #![feature(const_eval_select)]
 #![feature(const_pin)]
 #![feature(const_waker)]
index 0e3fef4ead31aefd1703f83966fffe0ce6ecb6af..9e0d7cab63e5c1d3efc36e508955cc9b8eb3dd89 100644 (file)
 #![feature(const_unsafecell_get_mut)]
 #![feature(const_waker)]
 #![feature(core_panic)]
+#![feature(char_indices_offset)]
 #![feature(duration_consts_float)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(ptr_alignment_type)]
 #![feature(slice_ptr_get)]
 #![feature(slice_split_at_unchecked)]
 #![feature(str_internals)]
+#![feature(str_split_remainder)]
+#![feature(str_split_inclusive_remainder)]
 #![feature(strict_provenance)]
 #![feature(utf16_extra)]
 #![feature(utf16_extra_const)]
index 0146a3c2fbf7f02ddbc70f4c26343eb058faa5ba..48e90e6d794005e7b9bde41b4ac440a93ade37f5 100644 (file)
@@ -64,13 +64,17 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
     unsafe { panic_impl(&pi) }
 }
 
-/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize.
-/// (No `fmt` variant as a `fmt::Arguments` needs more space to be passed.)
+/// Like `panic_fmt`, but for non-unwinding panics.
+///
+/// Has to be a separate function so that it can carry the `rustc_nounwind` attribute.
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cfg_attr(not(bootstrap), lang = "panic_nounwind")] // needed by codegen for non-unwinding panics
+#[track_caller]
+// This attribute has the key side-effect that if the panic handler ignores `can_unwind`
+// and unwinds anyway, we will hit the "unwinding out of nounwind function" guard,
+// which causes a "panic in a function that cannot unwind".
 #[rustc_nounwind]
-pub fn panic_nounwind(msg: &'static str) -> ! {
+pub fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
         super::intrinsics::abort()
     }
@@ -83,8 +87,6 @@ pub fn panic_nounwind(msg: &'static str) -> ! {
     }
 
     // PanicInfo with the `can_unwind` flag set to false forces an abort.
-    let pieces = [msg];
-    let fmt = fmt::Arguments::new_v1(&pieces, &[]);
     let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);
 
     // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
@@ -112,6 +114,15 @@ pub const fn panic(expr: &'static str) -> ! {
     panic_fmt(fmt::Arguments::new_v1(&[expr], &[]));
 }
 
+/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize.
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(bootstrap), lang = "panic_nounwind")] // needed by codegen for non-unwinding panics
+#[rustc_nounwind]
+pub fn panic_nounwind(expr: &'static str) -> ! {
+    panic_nounwind_fmt(fmt::Arguments::new_v1(&[expr], &[]));
+}
+
 #[inline]
 #[track_caller]
 #[rustc_diagnostic_item = "panic_str"]
index 24083ee6af44f34f2362df3913445b5c906a0aae..d969475aa484fd5a740a2f2c6895f0a24c2b7e3d 100644 (file)
@@ -585,16 +585,17 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
     #[inline]
     fn get_end(&mut self) -> Option<&'a str> {
-        if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) {
+        if !self.finished {
             self.finished = true;
-            // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
-            unsafe {
-                let string = self.matcher.haystack().get_unchecked(self.start..self.end);
-                Some(string)
+
+            if self.allow_trailing_empty || self.end - self.start > 0 {
+                // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
+                let string = unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) };
+                return Some(string);
             }
-        } else {
-            None
         }
+
+        None
     }
 
     #[inline]
@@ -716,14 +717,14 @@ fn next_back_inclusive(&mut self) -> Option<&'a str>
     }
 
     #[inline]
-    fn as_str(&self) -> &'a str {
+    fn remainder(&self) -> Option<&'a str> {
         // `Self::get_end` doesn't change `self.start`
         if self.finished {
-            return "";
+            return None;
         }
 
         // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
-        unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) }
+        Some(unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) })
     }
 }
 
@@ -746,44 +747,48 @@ fn as_str(&self) -> &'a str {
 }
 
 impl<'a, P: Pattern<'a>> Split<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "Mary had a little lamb".split(' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
 impl<'a, P: Pattern<'a>> RSplit<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "Mary had a little lamb".rsplit(' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "Mary had a little");
+    /// assert_eq!(split.remainder(), Some("Mary had a little"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
@@ -806,44 +811,48 @@ pub fn as_str(&self) -> &'a str {
 }
 
 impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "A..B..".split_terminator('.');
-    /// assert_eq!(split.as_str(), "A..B..");
+    /// assert_eq!(split.remainder(), Some("A..B.."));
     /// split.next();
-    /// assert_eq!(split.as_str(), ".B..");
+    /// assert_eq!(split.remainder(), Some(".B.."));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
 impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "A..B..".rsplit_terminator('.');
-    /// assert_eq!(split.as_str(), "A..B..");
+    /// assert_eq!(split.remainder(), Some("A..B.."));
     /// split.next();
-    /// assert_eq!(split.as_str(), "A..B");
+    /// assert_eq!(split.remainder(), Some("A..B"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
@@ -905,8 +914,8 @@ fn next_back(&mut self) -> Option<&'a str>
     }
 
     #[inline]
-    fn as_str(&self) -> &'a str {
-        self.iter.as_str()
+    fn remainder(&self) -> Option<&'a str> {
+        self.iter.remainder()
     }
 }
 
@@ -929,44 +938,48 @@ fn as_str(&self) -> &'a str {
 }
 
 impl<'a, P: Pattern<'a>> SplitN<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "Mary had a little lamb".splitn(3, ' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
 impl<'a, P: Pattern<'a>> RSplitN<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_as_str)]
+    /// #![feature(str_split_remainder)]
     /// let mut split = "Mary had a little lamb".rsplitn(3, ' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "Mary had a little");
+    /// assert_eq!(split.remainder(), Some("Mary had a little"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
@@ -1239,22 +1252,22 @@ impl<'a> SplitWhitespace<'a> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_whitespace_as_str)]
+    /// #![feature(str_split_whitespace_remainder)]
     ///
     /// let mut split = "Mary had a little lamb".split_whitespace();
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     ///
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     ///
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
     #[must_use]
-    #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.inner.iter.as_str()
+    #[unstable(feature = "str_split_whitespace_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.inner.iter.remainder()
     }
 }
 
@@ -1290,32 +1303,34 @@ fn next_back(&mut self) -> Option<&'a str> {
 impl FusedIterator for SplitAsciiWhitespace<'_> {}
 
 impl<'a> SplitAsciiWhitespace<'a> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_whitespace_as_str)]
+    /// #![feature(str_split_whitespace_remainder)]
     ///
     /// let mut split = "Mary had a little lamb".split_ascii_whitespace();
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     ///
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     ///
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
     #[must_use]
-    #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
+    #[unstable(feature = "str_split_whitespace_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
         if self.inner.iter.iter.finished {
-            return "";
+            return None;
         }
 
         // SAFETY: Slice is created from str.
-        unsafe { crate::str::from_utf8_unchecked(&self.inner.iter.iter.v) }
+        Some(unsafe { crate::str::from_utf8_unchecked(&self.inner.iter.iter.v) })
     }
 }
 
@@ -1358,23 +1373,25 @@ fn next_back(&mut self) -> Option<&'a str> {
 impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
 
 impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> {
-    /// Returns remainder of the split string
+    /// Returns remainder of the split string.
+    ///
+    /// If the iterator is empty, returns `None`.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(str_split_inclusive_as_str)]
+    /// #![feature(str_split_inclusive_remainder)]
     /// let mut split = "Mary had a little lamb".split_inclusive(' ');
-    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// assert_eq!(split.remainder(), Some("Mary had a little lamb"));
     /// split.next();
-    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// assert_eq!(split.remainder(), Some("had a little lamb"));
     /// split.by_ref().for_each(drop);
-    /// assert_eq!(split.as_str(), "");
+    /// assert_eq!(split.remainder(), None);
     /// ```
     #[inline]
-    #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")]
-    pub fn as_str(&self) -> &'a str {
-        self.0.as_str()
+    #[unstable(feature = "str_split_inclusive_remainder", issue = "77998")]
+    pub fn remainder(&self) -> Option<&'a str> {
+        self.0.remainder()
     }
 }
 
index 1b7578376b42bac72c1232b9078acf509330aa84..a4425fd234a4e22ad79ee3dfd4418464d80723ae 100644 (file)
@@ -181,6 +181,9 @@ pub struct Context<'a> {
     // are contravariant while return-position lifetimes are
     // covariant).
     _marker: PhantomData<fn(&'a ()) -> &'a ()>,
+    // Ensure `Context` is `!Send` and `!Sync` in order to allow
+    // for future `!Send` and / or `!Sync` fields.
+    _marker2: PhantomData<*mut ()>,
 }
 
 impl<'a> Context<'a> {
@@ -190,7 +193,7 @@ impl<'a> Context<'a> {
     #[must_use]
     #[inline]
     pub const fn from_waker(waker: &'a Waker) -> Self {
-        Context { waker, _marker: PhantomData }
+        Context { waker, _marker: PhantomData, _marker2: PhantomData }
     }
 
     /// Returns a reference to the [`Waker`] for the current task.
index 56be30e9282452b8b9aa0a8b59b9255f072dd350..163b34c9648529463304ec451c8cbff083d2159c 100644 (file)
@@ -1,4 +1,4 @@
-use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
+use core::task::{Poll, RawWaker, RawWakerVTable, Waker};
 
 #[test]
 fn poll_const() {
@@ -21,9 +21,5 @@ fn waker_const() {
 
     static WAKER: Waker = unsafe { Waker::from_raw(VOID_WAKER) };
 
-    static CONTEXT: Context<'static> = Context::from_waker(&WAKER);
-
-    static WAKER_REF: &'static Waker = CONTEXT.waker();
-
-    WAKER_REF.wake_by_ref();
+    WAKER.wake_by_ref();
 }
index 61c1ff578b2cad4ec3f8c46b09bd71ab80ef0d1b..c5a5991cc81c47d340a3b7b113c56339671acd7e 100644 (file)
@@ -338,7 +338,7 @@ fn default_alloc_error_hook(layout: Layout) {
 
     #[allow(unused_unsafe)]
     if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
-        panic!("memory allocation of {} bytes failed\n", layout.size());
+        panic!("memory allocation of {} bytes failed", layout.size());
     } else {
         rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
     }
index 23a13523fc275be62e588a04935d0ffa12f51d6f..de528e85368cbf5ed6b471b7411f4e3b97b53ca4 100644 (file)
@@ -2137,8 +2137,10 @@ fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
     }
 
     /// Read all bytes until a newline (the `0xA` byte) is reached, and append
-    /// them to the provided buffer. You do not need to clear the buffer before
-    /// appending.
+    /// them to the provided `String` buffer.
+    ///
+    /// Previous content of the buffer will be preserved. To avoid appending to
+    /// the buffer, you need to [`clear`] it first.
     ///
     /// This function will read bytes from the underlying stream until the
     /// newline delimiter (the `0xA` byte) or EOF is found. Once found, all bytes
@@ -2151,9 +2153,11 @@ fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
     ///
     /// This function is blocking and should be used carefully: it is possible for
     /// an attacker to continuously send bytes without ever sending a newline
-    /// or EOF.
+    /// or EOF. You can use [`take`] to limit the maximum number of bytes read.
     ///
     /// [`Ok(0)`]: Ok
+    /// [`clear`]: String::clear
+    /// [`take`]: crate::io::Read::take
     ///
     /// # Errors
     ///
index ef8a14be73d18dd0b4af57c6835639efdb98d16f..19d8f1edaf4c91087036159194f1c6f8b67034c0 100644 (file)
@@ -1414,7 +1414,8 @@ fn _set_file_name(&mut self, file_name: &OsStr) {
         self.push(file_name);
     }
 
-    /// Updates [`self.extension`] to `extension`.
+    /// Updates [`self.extension`] to `Some(extension)` or to `None` if
+    /// `extension` is empty.
     ///
     /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
     /// returns `true` and updates the extension otherwise.
@@ -1422,6 +1423,20 @@ fn _set_file_name(&mut self, file_name: &OsStr) {
     /// If [`self.extension`] is [`None`], the extension is added; otherwise
     /// it is replaced.
     ///
+    /// If `extension` is the empty string, [`self.extension`] will be [`None`]
+    /// afterwards, not `Some("")`.
+    ///
+    /// # Caveats
+    ///
+    /// The new `extension` may contain dots and will be used in its entirety,
+    /// but only the part after the final dot will be reflected in
+    /// [`self.extension`].
+    ///
+    /// If the file stem contains internal dots and `extension` is empty, part
+    /// of the old file stem will be considered the new [`self.extension`].
+    ///
+    /// See the examples below.
+    ///
     /// [`self.file_name`]: Path::file_name
     /// [`self.extension`]: Path::extension
     ///
@@ -1435,8 +1450,20 @@ fn _set_file_name(&mut self, file_name: &OsStr) {
     /// p.set_extension("force");
     /// assert_eq!(Path::new("/feel/the.force"), p.as_path());
     ///
-    /// p.set_extension("dark_side");
-    /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path());
+    /// p.set_extension("dark.side");
+    /// assert_eq!(Path::new("/feel/the.dark.side"), p.as_path());
+    ///
+    /// p.set_extension("cookie");
+    /// assert_eq!(Path::new("/feel/the.dark.cookie"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the.dark"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the"), p.as_path());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
index 9cf43fc7a2193f1b67c5cd51e2927e98dff7b941..f3998e98583ecd32d564590389104cb35d95d3ff 100644 (file)
@@ -934,8 +934,7 @@ def main():
     if len(sys.argv) > 1 and sys.argv[1] == 'help':
         sys.argv = [sys.argv[0], '-h'] + sys.argv[2:]
 
-    help_triggered = (
-        '-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1)
+    help_triggered = len(sys.argv) == 1 or any(x in ["-h", "--help", "--version"] for x in sys.argv)
     try:
         bootstrap(help_triggered)
         if not help_triggered:
index 32e5d414061eccdfe402fcc7393bdbecfac493e3..b203ecd3844b039d11358abc156f6d7b427a8be6 100644 (file)
@@ -105,7 +105,7 @@ fn run(self, builder: &Builder<'_>) {
             "Checking stage{} library artifacts ({} -> {})",
             builder.top_stage, &compiler.host, target
         ));
-        run_cargo(builder, cargo, &libstd_stamp(builder, compiler, target), vec![], true);
+        run_cargo(builder, cargo, &libstd_stamp(builder, compiler, target), vec![], true, false);
 
         // We skip populating the sysroot in non-zero stage because that'll lead
         // to rlib/rmeta conflicts if std gets built during this session.
@@ -155,7 +155,14 @@ fn run(self, builder: &Builder<'_>) {
             "Checking stage{} library test/bench/example targets ({} -> {})",
             builder.top_stage, &compiler.host, target
         ));
-        run_cargo(builder, cargo, &libstd_test_stamp(builder, compiler, target), vec![], true);
+        run_cargo(
+            builder,
+            cargo,
+            &libstd_test_stamp(builder, compiler, target),
+            vec![],
+            true,
+            false,
+        );
     }
 }
 
@@ -225,7 +232,7 @@ fn run(self, builder: &Builder<'_>) {
             "Checking stage{} compiler artifacts ({} -> {})",
             builder.top_stage, &compiler.host, target
         ));
-        run_cargo(builder, cargo, &librustc_stamp(builder, compiler, target), vec![], true);
+        run_cargo(builder, cargo, &librustc_stamp(builder, compiler, target), vec![], true, false);
 
         let libdir = builder.sysroot_libdir(compiler, target);
         let hostdir = builder.sysroot_libdir(compiler, compiler.host);
@@ -285,6 +292,7 @@ fn run(self, builder: &Builder<'_>) {
             &codegen_backend_stamp(builder, compiler, target, backend),
             vec![],
             true,
+            false,
         );
     }
 }
@@ -343,7 +351,7 @@ fn run(self, builder: &Builder<'_>) {
             "Checking stage{} {} artifacts ({} -> {})",
             compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple
         ));
-        run_cargo(builder, cargo, &stamp(builder, compiler, target), vec![], true);
+        run_cargo(builder, cargo, &stamp(builder, compiler, target), vec![], true, false);
 
         /// Cargo's output path in a given stage, compiled by a particular
         /// compiler for the specified target.
@@ -417,6 +425,7 @@ fn run(self, builder: &Builder<'_>) {
                     &stamp(builder, compiler, target),
                     vec![],
                     true,
+                    false,
                 );
 
                 /// Cargo's output path in a given stage, compiled by a particular
index f9a04f2e91dbf3733510d9a88d02fb61b8365128..147ded3a9eed7c13ee41b09b2117bf6100e7b56f 100644 (file)
@@ -141,7 +141,14 @@ fn run(self, builder: &Builder<'_>) {
             &compiler.host,
             target,
         ));
-        run_cargo(builder, cargo, &libstd_stamp(builder, compiler, target), target_deps, false);
+        run_cargo(
+            builder,
+            cargo,
+            &libstd_stamp(builder, compiler, target),
+            target_deps,
+            false,
+            false,
+        );
 
         builder.ensure(StdLink::from_std(
             self,
@@ -728,7 +735,14 @@ fn run(self, builder: &Builder<'_>) {
             &compiler.host,
             target,
         ));
-        run_cargo(builder, cargo, &librustc_stamp(builder, compiler, target), vec![], false);
+        run_cargo(
+            builder,
+            cargo,
+            &librustc_stamp(builder, compiler, target),
+            vec![],
+            false,
+            true, // Only ship rustc_driver.so and .rmeta files, not all intermediate .rlib files.
+        );
 
         builder.ensure(RustcLink::from_rustc(
             self,
@@ -984,7 +998,7 @@ fn run(self, builder: &Builder<'_>) {
             "Building stage{} codegen backend {} ({} -> {})",
             compiler.stage, backend, &compiler.host, target
         ));
-        let files = run_cargo(builder, cargo, &tmp_stamp, vec![], false);
+        let files = run_cargo(builder, cargo, &tmp_stamp, vec![], false, false);
         if builder.config.dry_run() {
             return;
         }
@@ -1411,6 +1425,7 @@ pub fn run_cargo(
     stamp: &Path,
     additional_target_deps: Vec<(PathBuf, DependencyType)>,
     is_check: bool,
+    rlib_only_metadata: bool,
 ) -> Vec<PathBuf> {
     if builder.config.dry_run() {
         return Vec::new();
@@ -1444,13 +1459,35 @@ pub fn run_cargo(
         };
         for filename in filenames {
             // Skip files like executables
-            if !(filename.ends_with(".rlib")
-                || filename.ends_with(".lib")
+            let mut keep = false;
+            if filename.ends_with(".lib")
                 || filename.ends_with(".a")
                 || is_debug_info(&filename)
                 || is_dylib(&filename)
-                || (is_check && filename.ends_with(".rmeta")))
             {
+                // Always keep native libraries, rust dylibs and debuginfo
+                keep = true;
+            }
+            if is_check && filename.ends_with(".rmeta") {
+                // During check builds we need to keep crate metadata
+                keep = true;
+            } else if rlib_only_metadata {
+                if filename.contains("jemalloc_sys") || filename.contains("rustc_smir") {
+                    // jemalloc_sys and rustc_smir are not linked into librustc_driver.so,
+                    // so we need to distribute them as rlib to be able to use them.
+                    keep |= filename.ends_with(".rlib");
+                } else {
+                    // Distribute the rest of the rustc crates as rmeta files only to reduce
+                    // the tarball sizes by about 50%. The object files are linked into
+                    // librustc_driver.so, so it is still possible to link against them.
+                    keep |= filename.ends_with(".rmeta");
+                }
+            } else {
+                // In all other cases keep all rlibs
+                keep |= filename.ends_with(".rlib");
+            }
+
+            if !keep {
                 continue;
             }
 
index 340aa78ebf9b5b71a45fca0b2b7bcfa5fc3f6c6d..68215790bed177e3fdd3b4376da622b612bc689a 100644 (file)
@@ -2067,6 +2067,9 @@ fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
 
         builder.ensure(crate::native::Llvm { target });
 
+        // We want to package `lld` to use it with `download-ci-llvm`.
+        builder.ensure(crate::native::Lld { target });
+
         let src_bindir = builder.llvm_out(target).join("bin");
         // If updating this list, you likely want to change
         // src/bootstrap/download-ci-llvm-stamp as well, otherwise local users
index d19a1ae95cf145dcc44f488a8facbb356f12a35a..94630e40f3c4ca5a68e3bd5e149fa190fd265b15 100644 (file)
@@ -1,4 +1,4 @@
 Change this file to make users of the `download-ci-llvm` configuration download
 a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
 
-Last change is for: https://github.com/rust-lang/rust/pull/102790
+Last change is for: https://github.com/rust-lang/rust/pull/104748
index 4e503dfe864e2937eca0461125effb8147739ff1..781a738a81196877582a4b34daa4f43d109bdf8a 100644 (file)
@@ -63,13 +63,13 @@ fn push_all(&mut self, s: impl AsRef<OsStr>) {
     }
 }
 
-// This returns whether we've already previously built LLVM.
-//
-// It's used to avoid busting caches during x.py check -- if we've already built
-// LLVM, it's fine for us to not try to avoid doing so.
-//
-// This will return the llvm-config if it can get it (but it will not build it
-// if not).
+/// This returns whether we've already previously built LLVM.
+///
+/// It's used to avoid busting caches during x.py check -- if we've already built
+/// LLVM, it's fine for us to not try to avoid doing so.
+///
+/// This will return the llvm-config if it can get it (but it will not build it
+/// if not).
 pub fn prebuilt_llvm_config(
     builder: &Builder<'_>,
     target: TargetSelection,
@@ -823,8 +823,21 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         }
         let target = self.target;
 
-        let LlvmResult { llvm_config, llvm_cmake_dir } =
-            builder.ensure(Llvm { target: self.target });
+        let LlvmResult { llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target });
+
+        // The `dist` step packages LLD next to LLVM's binaries for download-ci-llvm. The root path
+        // we usually expect here is `./build/$triple/ci-llvm/`, with the binaries in its `bin`
+        // subfolder. We check if that's the case, and if LLD's binary already exists there next to
+        // `llvm-config`: if so, we can use it instead of building LLVM/LLD from source.
+        let ci_llvm_bin = llvm_config.parent().unwrap();
+        if ci_llvm_bin.is_dir() && ci_llvm_bin.file_name().unwrap() == "bin" {
+            let lld_path = ci_llvm_bin.join(exe("lld", target));
+            if lld_path.exists() {
+                // The following steps copying `lld` as `rust-lld` to the sysroot, expect it in the
+                // `bin` subfolder of this step's out dir.
+                return ci_llvm_bin.parent().unwrap().to_path_buf();
+            }
+        }
 
         let out_dir = builder.lld_out(target);
         let done_stamp = out_dir.join("lld-finished-building");
index c340294fc7375304c83e0e5a5e15270a46e667d1..dc0e591cad6f6f9aec51a1ab2eec129f01e9988b 100644 (file)
@@ -32,5 +32,4 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require
 COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
 COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
 
-ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
 ENV SCRIPT python3 ../x.py test --stage 0 src/tools/tidy tidyselftest
index b64300277508dd15af81644f540beca9ccafbcfb..0db9c993eecb407f2fd72cb4a3a0a76ef3535cb4 100755 (executable)
@@ -184,11 +184,11 @@ if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then
   $SRC/configure --set rust.parallel-compiler
 
   # Save the build metrics before we wipe the directory
-  if [ $HAS_METRICS = 1 ]; then
+  if [ "$HAS_METRICS" = 1 ]; then
     mv build/metrics.json .
   fi
   rm -rf build
-  if [ $HAS_METRICS = 1 ]; then
+  if [ "$HAS_METRICS" = 1 ]; then
     mkdir build
     mv metrics.json build
   fi
index a60f4316ec923a5ac2ed6a2eba6960edb832d855..2bd5d42c9956369132228da6409f0e68da56c51a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a60f4316ec923a5ac2ed6a2eba6960edb832d855
+Subproject commit 2bd5d42c9956369132228da6409f0e68da56c51a
index dd37e21ccee43918ed18a71581bb2af537ffe4fc..8ca261268068d80c0969260fff15199bad87b587 160000 (submodule)
@@ -1 +1 @@
-Subproject commit dd37e21ccee43918ed18a71581bb2af537ffe4fc
+Subproject commit 8ca261268068d80c0969260fff15199bad87b587
index 995df09b65c582eb6290ab7ea5d9485983eb4c37..8888f9428fe9a48f31de6bd2cef9b9bf80791edc 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 995df09b65c582eb6290ab7ea5d9485983eb4c37
+Subproject commit 8888f9428fe9a48f31de6bd2cef9b9bf80791edc
index 8b42eb5f57d3d8ed2257a22d0e850d9db52afed3..b3e2a6e6c8a3aae5b5d950c63046f23bae07096d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8b42eb5f57d3d8ed2257a22d0e850d9db52afed3
+Subproject commit b3e2a6e6c8a3aae5b5d950c63046f23bae07096d
index 8f4099653562e040b9d753563f9de583fad8fbc5..025a4379f45a31a289177d6daad62200c3aa6302 100644 (file)
@@ -1853,7 +1853,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
         ty::Placeholder(..) => panic!("Placeholder"),
         ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
         ty::Infer(..) => panic!("Infer"),
-        ty::Error(_) => panic!("Error"),
+        ty::Error(_) => rustc_errors::FatalError.raise(),
     }
 }
 
@@ -1949,20 +1949,27 @@ pub(crate) fn clean_field_with_def_id(
 }
 
 pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
+    let discriminant = match variant.discr {
+        ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
+        ty::VariantDiscr::Relative(_) => None,
+    };
+
     let kind = match variant.ctor_kind() {
-        Some(CtorKind::Const) => Variant::CLike(match variant.discr {
-            ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
-            ty::VariantDiscr::Relative(_) => None,
-        }),
-        Some(CtorKind::Fn) => Variant::Tuple(
+        Some(CtorKind::Const) => VariantKind::CLike,
+        Some(CtorKind::Fn) => VariantKind::Tuple(
             variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
         ),
-        None => Variant::Struct(VariantStruct {
-            ctor_kind: None,
+        None => VariantKind::Struct(VariantStruct {
             fields: variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
         }),
     };
-    Item::from_def_id_and_parts(variant.def_id, Some(variant.name), VariantItem(kind), cx)
+
+    Item::from_def_id_and_parts(
+        variant.def_id,
+        Some(variant.name),
+        VariantItem(Variant { kind, discriminant }),
+        cx,
+    )
 }
 
 fn clean_variant_data<'tcx>(
@@ -1970,19 +1977,22 @@ fn clean_variant_data<'tcx>(
     disr_expr: &Option<hir::AnonConst>,
     cx: &mut DocContext<'tcx>,
 ) -> Variant {
-    match variant {
-        hir::VariantData::Struct(..) => Variant::Struct(VariantStruct {
-            ctor_kind: None,
+    let discriminant = disr_expr.map(|disr| Discriminant {
+        expr: Some(disr.body),
+        value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
+    });
+
+    let kind = match variant {
+        hir::VariantData::Struct(..) => VariantKind::Struct(VariantStruct {
             fields: variant.fields().iter().map(|x| clean_field(x, cx)).collect(),
         }),
         hir::VariantData::Tuple(..) => {
-            Variant::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
+            VariantKind::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
         }
-        hir::VariantData::Unit(..) => Variant::CLike(disr_expr.map(|disr| Discriminant {
-            expr: Some(disr.body),
-            value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
-        })),
-    }
+        hir::VariantData::Unit(..) => VariantKind::CLike,
+    };
+
+    Variant { discriminant, kind }
 }
 
 fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
index 62217df8de79ce15ef35a6191d6eab12a4dcbb00..6d55a6794f581ae329398373ddd1cb04a720294c 100644 (file)
@@ -807,8 +807,11 @@ pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
         match self {
             StructItem(s) => s.fields.iter(),
             UnionItem(u) => u.fields.iter(),
-            VariantItem(Variant::Struct(v)) => v.fields.iter(),
-            VariantItem(Variant::Tuple(v)) => v.iter(),
+            VariantItem(v) => match &v.kind {
+                VariantKind::CLike => [].iter(),
+                VariantKind::Tuple(t) => t.iter(),
+                VariantKind::Struct(s) => s.fields.iter(),
+            },
             EnumItem(e) => e.variants.iter(),
             TraitItem(t) => t.items.iter(),
             ImplItem(i) => i.items.iter(),
@@ -824,7 +827,6 @@ pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
             | TyMethodItem(_)
             | MethodItem(_, _)
             | StructFieldItem(_)
-            | VariantItem(_)
             | ForeignFunctionItem(_)
             | ForeignStaticItem(_)
             | ForeignTypeItem
@@ -2109,7 +2111,6 @@ pub(crate) fn has_stripped_entries(&self) -> bool {
 /// only as a variant in an enum.
 #[derive(Clone, Debug)]
 pub(crate) struct VariantStruct {
-    pub(crate) ctor_kind: Option<CtorKind>,
     pub(crate) fields: Vec<Item>,
 }
 
@@ -2136,17 +2137,23 @@ pub(crate) fn variants(&self) -> impl Iterator<Item = &Item> {
 }
 
 #[derive(Clone, Debug)]
-pub(crate) enum Variant {
-    CLike(Option<Discriminant>),
+pub(crate) struct Variant {
+    pub kind: VariantKind,
+    pub discriminant: Option<Discriminant>,
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum VariantKind {
+    CLike,
     Tuple(Vec<Item>),
     Struct(VariantStruct),
 }
 
 impl Variant {
     pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
-        match *self {
-            Self::Struct(ref struct_) => Some(struct_.has_stripped_entries()),
-            Self::CLike(..) | Self::Tuple(_) => None,
+        match &self.kind {
+            VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
+            VariantKind::CLike | VariantKind::Tuple(_) => None,
         }
     }
 }
index c6f1f9de51a49a4745516e4f7a31cf59b8c1543a..656aeefb01a4a807ea8aa8b418957544a28c356c 100644 (file)
@@ -37,17 +37,21 @@ fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
                 i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
                 ImplItem(i)
             }
-            VariantItem(i) => match i {
-                Variant::Struct(mut j) => {
-                    j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                    VariantItem(Variant::Struct(j))
-                }
-                Variant::Tuple(fields) => {
-                    let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                    VariantItem(Variant::Tuple(fields))
-                }
-                Variant::CLike(disr) => VariantItem(Variant::CLike(disr)),
-            },
+            VariantItem(Variant { kind, discriminant }) => {
+                let kind = match kind {
+                    VariantKind::Struct(mut j) => {
+                        j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+                        VariantKind::Struct(j)
+                    }
+                    VariantKind::Tuple(fields) => {
+                        let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+                        VariantKind::Tuple(fields)
+                    }
+                    VariantKind::CLike => VariantKind::CLike,
+                };
+
+                VariantItem(Variant { kind, discriminant })
+            }
             ExternCrateItem { src: _ }
             | ImportItem(_)
             | FunctionItem(_)
index a7b57c373e3bec3b4a9219758d8d020f2b1a0642..c16d6477fc37978c736e7c7ddf296be56f98311e 100644 (file)
@@ -1220,25 +1220,16 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
                     w.write_str("    ");
                     let name = v.name.unwrap();
                     match *v.kind {
-                        clean::VariantItem(ref var) => match var {
-                            // FIXME(#101337): Show discriminant
-                            clean::Variant::CLike(..) => write!(w, "{}", name),
-                            clean::Variant::Tuple(ref s) => {
+                        // FIXME(#101337): Show discriminant
+                        clean::VariantItem(ref var) => match var.kind {
+                            clean::VariantKind::CLike => write!(w, "{}", name),
+                            clean::VariantKind::Tuple(ref s) => {
                                 write!(w, "{}(", name);
                                 print_tuple_struct_fields(w, cx, s);
                                 w.write_str(")");
                             }
-                            clean::Variant::Struct(ref s) => {
-                                render_struct(
-                                    w,
-                                    v,
-                                    None,
-                                    s.ctor_kind,
-                                    &s.fields,
-                                    "    ",
-                                    false,
-                                    cx,
-                                );
+                            clean::VariantKind::Struct(ref s) => {
+                                render_struct(w, v, None, None, &s.fields, "    ", false, cx);
                             }
                         },
                         _ => unreachable!(),
@@ -1286,25 +1277,28 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
                 " rightside",
             );
             write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap());
-            if let clean::VariantItem(clean::Variant::Tuple(ref s)) = *variant.kind {
+
+            let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() };
+
+            if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
                 w.write_str("(");
                 print_tuple_struct_fields(w, cx, s);
                 w.write_str(")");
             }
             w.write_str("</h3></section>");
 
-            use crate::clean::Variant;
-
-            let heading_and_fields = match &*variant.kind {
-                clean::VariantItem(Variant::Struct(s)) => Some(("Fields", &s.fields)),
-                // Documentation on tuple variant fields is rare, so to reduce noise we only emit
-                // the section if at least one field is documented.
-                clean::VariantItem(Variant::Tuple(fields))
-                    if fields.iter().any(|f| f.doc_value().is_some()) =>
-                {
-                    Some(("Tuple Fields", fields))
+            let heading_and_fields = match &variant_data.kind {
+                clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)),
+                clean::VariantKind::Tuple(fields) => {
+                    // Documentation on tuple variant fields is rare, so to reduce noise we only emit
+                    // the section if at least one field is documented.
+                    if fields.iter().any(|f| f.doc_value().is_some()) {
+                        Some(("Tuple Fields", fields))
+                    } else {
+                        None
+                    }
                 }
-                _ => None,
+                clean::VariantKind::CLike => None,
             };
 
             if let Some((heading, fields)) = heading_and_fields {
index b5f1581321edc084bd2f7c08710037846a0d5e51..6f8a306d665b1575a1398b25231e7e263437acf3 100644 (file)
@@ -76,8 +76,6 @@
 }
 
 * {
-       -webkit-box-sizing: border-box;
-       -moz-box-sizing: border-box;
        box-sizing: border-box;
 }
 
@@ -1387,31 +1385,10 @@ details.dir-entry {
        padding-left: 4px;
 }
 
-details.dir-entry > summary::after {
-       content: " â–º";
-       position: absolute;
-       left: -15px;
-       top: 0px;
-       font-size: 80%;
-       padding: 2px 0px;
-       /* set width to cover gap between arrow and text */
-       width: 25px;
-}
-
-details[open].dir-entry > summary::after {
-       content: " â–¼";
-}
-
-details.dir-entry > summary::-webkit-details-marker,
-details.dir-entry > summary::marker {
-       display: none;
-}
-
 details.dir-entry > summary {
-       margin: 0 0 0 13px;
-       list-style: none;
+       margin: 0 0 0 -4px;
+       padding: 0 0 0 4px;
        cursor: pointer;
-       position: relative;
 }
 
 details.dir-entry div.folders, details.dir-entry div.files {
index d7184053c87a4dd6b5521e99e1cb6672eba102f4..84af194904d1bca771e5b84fcb718180fa5d9943 100644 (file)
@@ -646,15 +646,20 @@ fn from_tcx(enum_: clean::Enum, tcx: TyCtxt<'_>) -> Self {
 
 impl FromWithTcx<clean::Variant> for Variant {
     fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
-        use clean::Variant::*;
-        match variant {
-            CLike(disr) => Variant::Plain(disr.map(|disr| disr.into_tcx(tcx))),
-            Tuple(fields) => Variant::Tuple(ids_keeping_stripped(fields, tcx)),
-            Struct(s) => Variant::Struct {
+        use clean::VariantKind::*;
+
+        let discriminant = variant.discriminant.map(|d| d.into_tcx(tcx));
+
+        let kind = match variant.kind {
+            CLike => VariantKind::Plain,
+            Tuple(fields) => VariantKind::Tuple(ids_keeping_stripped(fields, tcx)),
+            Struct(s) => VariantKind::Struct {
                 fields_stripped: s.has_stripped_entries(),
                 fields: ids(s.fields, tcx),
             },
-        }
+        };
+
+        Variant { kind, discriminant }
     }
 }
 
index 995fb5dcc1c86de89b780320701190eb25c3790d..bf111133b9f7f5f85ef2fdbfdebe54843d422802 100644 (file)
@@ -132,7 +132,10 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             // implementations of traits are always public.
             clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
             // Variant fields have inherited visibility
-            clean::VariantItem(clean::Variant::Struct(..) | clean::Variant::Tuple(..)) => true,
+            clean::VariantItem(clean::Variant {
+                kind: clean::VariantKind::Struct(..) | clean::VariantKind::Tuple(..),
+                ..
+            }) => true,
             _ => false,
         };
 
index d29ceead4f3a549026a519f8ee83a83695ae6c0b..390b9436121951206463db0210b4f407609c1c2d 100644 (file)
@@ -17,10 +17,10 @@ fn visit_inner_recur(&mut self, kind: &ItemKind) {
             EnumItem(i) => i.variants.iter().for_each(|x| self.visit_item(x)),
             TraitItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
             ImplItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
-            VariantItem(i) => match i {
-                Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
-                Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
-                Variant::CLike(_) => {}
+            VariantItem(i) => match &i.kind {
+                VariantKind::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
+                VariantKind::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
+                VariantKind::CLike => {}
             },
             ExternCrateItem { src: _ }
             | ImportItem(_)
index 310a01194eaf8744e1e048417309b8a3acd1c18b..7db470359672f834fdaff1017f3a496a5979e28f 100644 (file)
@@ -410,7 +410,7 @@ fn visit_foreign_item_inner(
 
     /// This method will create a new module and push it onto the "modules stack" then call
     /// `visit_mod_contents`. Once done, it'll remove it from the "modules stack" and instead
-    /// add into into the list of modules of the current module.
+    /// add into the list of modules of the current module.
     fn enter_mod(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>, name: Symbol) {
         self.modules.push(Module::new(name, id, m.spans.inner_span));
 
index 1ee96b8231cd1418349c17977a645c44d2d75a2c..387d5787dfcb25fe0348bd0daf998796595c5359 100644 (file)
@@ -9,7 +9,7 @@
 use serde::{Deserialize, Serialize};
 
 /// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 23;
+pub const FORMAT_VERSION: u32 = 24;
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
@@ -333,11 +333,18 @@ pub struct Enum {
     pub impls: Vec<Id>,
 }
 
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Variant {
+    /// Whether the variant is plain, a tuple-like, or struct-like. Contains the fields.
+    pub kind: VariantKind,
+    /// The discriminant, if explicitly specified.
+    pub discriminant: Option<Discriminant>,
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
-#[serde(tag = "variant_kind", content = "variant_inner")]
-pub enum Variant {
-    /// A variant with no parentheses, and possible discriminant.
+pub enum VariantKind {
+    /// A variant with no parentheses
     ///
     /// ```rust
     /// enum Demo {
@@ -345,7 +352,7 @@ pub enum Variant {
     ///     PlainWithDiscriminant = 1,
     /// }
     /// ```
-    Plain(Option<Discriminant>),
+    Plain,
     /// A variant with unnamed fields.
     ///
     /// Unlike most of json, `#[doc(hidden)]` fields will be given as `None`
index 44fee952307f29b5c43ef7ca60ae7826f5662a70..0f9e90f6ba77990d2c265057699170a5cd372dbe 100644 (file)
@@ -145,7 +145,7 @@ pub fn raw_struct(_: *const S) {
 
 // `Box` can get deallocated during execution of the function, so it should
 // not get `dereferenceable`.
-// CHECK: noalias noundef nonnull align 4 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x)
+// CHECK: noundef nonnull align 4 {{i32\*|ptr}} @_box({{i32\*|ptr}} noalias noundef nonnull align 4 %x)
 #[no_mangle]
 pub fn _box(x: Box<i32>) -> Box<i32> {
   x
diff --git a/src/test/codegen/issue-103840.rs b/src/test/codegen/issue-103840.rs
new file mode 100644 (file)
index 0000000..f19d703
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-flags: -O
+#![crate_type = "lib"]
+
+pub fn foo(t: &mut Vec<usize>) {
+    // CHECK-NOT: __rust_dealloc
+    let mut taken = std::mem::take(t);
+    taken.pop();
+    *t = taken;
+}
index dd3dce4e7209c746dfd49a479156ae8b6b23b060..83737a02200918225bc868fb2f5b78a011684042 100644 (file)
@@ -2,8 +2,6 @@
 // compile-flags: -Zquery-dep-graph
 // [rpass1]compile-flags: -Zincremental-ignore-spans
 // [rpass2]compile-flags: -Zincremental-ignore-spans
-// [rpass3]compile-flags: -Zincremental-relative-spans
-// [rpass4]compile-flags: -Zincremental-relative-spans
 
 #![feature(rustc_attrs)]
 #![rustc_partition_reused(module = "change_symbol_export_status-mod1", cfg = "rpass2")]
index f3a7722cdcad020aa0faf147bc720ef3586349d1..65df2e8292a047cf3ba9578040dde36925ae074e 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 
 #![allow(warnings)]
index c769246b29b2f9565a3c396ee5a79716261d9589..7bf99f6112ed9f21f9f3323bc3b1ba3f760d0a01 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 70ef10645f19f3ab8ea25ab91a8930805efab064..db367d07094d7786d34e792938e303870f601c2b 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 0f8898c389b7f4b33a819f03ff42622696884748..bc83723a908f29bc5995b4efce419cd3ef4574a7 100644 (file)
@@ -16,9 +16,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 87fd21fd1b8107ccea5fdc8276dba39c770754d9..9ac9ae24f81bc524d701fa9cab4fc417c35fef2a 100644 (file)
@@ -4,9 +4,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 3121abbea369b04de3b071b4389f918b81ddf32b..1906843c7a247a569c95c9f6231a36d6549fde2f 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 16d6af01695f1965df01d432e9b941ba9eb21bc5..193e792c84330203c7a3aa3d5ed053e2726e356b 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 3ff949fbb3f808b5f6d7d20236f68aa09a24892f..182ca7d926c6bdd6c521a96374c25dec1e7e7c53 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(linkage)]
index cff557dcb74b8830e7ae14e93d9f0ab6b9741f13..937fd3ac879a920b1a74a89e319c56b28e6bead4 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 9ef46847243641bd3997a869be5b865234fdc8a3..b1ac6f6fa6c2b3acc846fd3f35a31a8e6ded4809 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 1abbff32c6f349ece60c2d60622a4bf3c6bc85e6..285f857c9cbcf7565ea9c832533aa8c0c6e5c322 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 
 #![allow(warnings)]
index dc878d6827cbf87f3b5ea96738b27c1d700cb1be..3118aa1356452985aaf66035a3a8c01de3fb7d63 100644 (file)
@@ -12,9 +12,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 01320cd51f4453d356a4c23a573fed3b9e7ddd0c..180bf6fec8772b72c22b3026b5189a16608d0863 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index ada541e644a3130236366d1b562303afe9059f38..87b86479d07bd9f8ed7146d5808fad1e0c6a0e72 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index fa054c7decc57056b3b1bcf1758f08e1cf664a42..4429df6833e486ec96a1007547058fce717a8a92 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 67d87f5c4ed92e7cad5c7f9d97f113e08a82e05a..bb83f8300d06d69169b40b3e00f07806a6d78b29 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index fc9671cb41b47ef529455ab52a8875a4d0573dc0..e50e5674c661e4ea96901ac744704d6f2296ebb2 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 7a91722d70fda1e4027728bbb078e8b7acbeb7bb..4a2706b4f0100817699a3c234502e467f364598c 100644 (file)
@@ -16,9 +16,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index c453eeceb77f53b1266e25a5eccef6a814f5a297..b583bee2f2449b8d34eab33e428e091769a97a13 100644 (file)
@@ -16,9 +16,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index f555f555f9236c7c214c78324d5ce8a345ed7094..3b2e18d17a96b51941e4e2aa68ca7cee3d5aefee 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 18fb716353fa7f55484b766af5477efd6245c2af..58af51eef077f1809a3a93ecc218baf13292af75 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 88fd4d89b2827661b9d9f74dcaf4be3e5692d4d7..c81b0d0afb8114fd16a1505eb61e5d3a166a4cdc 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 9b4d23757b871340e7418c03025e449d978ccf63..c1cc0b62bc2442ebff17709558d120ec88421fa9 100644 (file)
@@ -11,9 +11,6 @@
 // [cfail1]compile-flags: -Zincremental-ignore-spans
 // [cfail2]compile-flags: -Zincremental-ignore-spans
 // [cfail3]compile-flags: -Zincremental-ignore-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index 639454cc975300dad6299d4a6cf761ad4450e5c7..38ab28461911b6e2a91acc587db5dc4b08ebb03f 100644 (file)
@@ -1,21 +1,17 @@
 // This test makes sure that just changing a definition's location in the
 // source file also changes its incr. comp. hash, if debuginfo is enabled.
 
-// revisions:rpass1 rpass2 rpass3 rpass4
+// revisions:rpass1 rpass2
 
 // ignore-asmjs wasm2js does not support source maps yet
 // compile-flags: -g -Z query-dep-graph
-// [rpass3]compile-flags: -Zincremental-relative-spans
-// [rpass4]compile-flags: -Zincremental-relative-spans
 
 #![feature(rustc_attrs)]
 #![rustc_partition_codegened(module = "spans_significant_w_debuginfo", cfg = "rpass2")]
-#![rustc_partition_codegened(module = "spans_significant_w_debuginfo", cfg = "rpass4")]
 
-#[cfg(any(rpass1, rpass3))]
+#[cfg(rpass1)]
 pub fn main() {}
 
-#[cfg(any(rpass2, rpass4))]
-#[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir", cfg = "rpass2")]
-#[rustc_clean(cfg = "rpass4")]
+#[cfg(rpass2)]
+#[rustc_clean(cfg = "rpass2")]
 pub fn main() {}
index 6f51c9729e3706e15e09cd655258c317d6fae109..085e4cd78ca1ce6718e34320b49e9e1e3dfcfd8e 100644 (file)
@@ -1,26 +1,22 @@
 // This test makes sure that just changing a definition's location in the
 // source file also changes its incr. comp. hash, if debuginfo is enabled.
 
-// revisions:rpass1 rpass2 rpass3 rpass4
-// [rpass3]compile-flags: -Zincremental-relative-spans
-// [rpass4]compile-flags: -Zincremental-relative-spans
+// revisions:rpass1 rpass2
 
 // compile-flags: -C overflow-checks=on -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![rustc_partition_codegened(module = "spans_significant_w_panic", cfg = "rpass2")]
-#![rustc_partition_codegened(module = "spans_significant_w_panic", cfg = "rpass4")]
 
-#[cfg(any(rpass1, rpass3))]
+#[cfg(rpass1)]
 pub fn main() {
     if std::hint::black_box(false) {
         panic!()
     }
 }
 
-#[cfg(any(rpass2, rpass4))]
-#[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir", cfg = "rpass2")]
-#[rustc_clean(cfg = "rpass4")]
+#[cfg(rpass2)]
+#[rustc_clean(cfg = "rpass2")]
 pub fn main() {
     if std::hint::black_box(false) {
         panic!()
index cae7b4aab7565ed60455eec442a1a4de705760e2..e15a8d18f853dfd9bd43f12fd78c7a1f1ea8d256 100644 (file)
@@ -1,7 +1,5 @@
-// revisions: cfail1 cfail2 cfail3 cfail4
+// revisions: cfail1 cfail2
 // compile-flags: -Z query-dep-graph
-// [cfail3]compile-flags: -Zincremental-relative-spans
-// [cfail4]compile-flags: -Zincremental-relative-spans
 // build-pass (FIXME(62277): could be check-pass?)
 
 #![allow(warnings)]
 // needed even for callers of `x`.
 
 pub mod x {
-    #[cfg(any(cfail1, cfail3))]
+    #[cfg(cfail1)]
     pub fn x() {
         println!("{}", "1");
     }
 
-    #[cfg(any(cfail2, cfail4))]
-    #[rustc_clean(except = "hir_owner,hir_owner_nodes,optimized_mir,promoted_mir", cfg = "cfail2")]
-    #[rustc_clean(except = "hir_owner_nodes,promoted_mir", cfg = "cfail4")]
+    #[cfg(cfail2)]
+    #[rustc_clean(except = "hir_owner_nodes,promoted_mir", cfg = "cfail2")]
     pub fn x() {
         println!("{}", "2");
     }
@@ -30,7 +27,6 @@ pub mod y {
     use x;
 
     #[rustc_clean(cfg = "cfail2")]
-    #[rustc_clean(cfg = "cfail4")]
     pub fn y() {
         x::x();
     }
@@ -40,7 +36,6 @@ pub mod z {
     use y;
 
     #[rustc_clean(cfg = "cfail2")]
-    #[rustc_clean(cfg = "cfail4")]
     pub fn z() {
         y::y();
     }
index 31f329a7f726b2083d9b80837fc98a57158038dd..368a726ea904de1a8164b3dd0c78ca483a1066e0 100644 (file)
@@ -3,10 +3,7 @@
 // ends up with any spans in its LLVM bitecode, so LLVM is able to skip
 // re-building any modules which import 'inlined_fn'
 
-// revisions: cfail1 cfail2 cfail3 cfail4 cfail5 cfail6
-// [cfail4]compile-flags: -Zincremental-relative-spans
-// [cfail5]compile-flags: -Zincremental-relative-spans
-// [cfail6]compile-flags: -Zincremental-relative-spans
+// revisions: cfail1 cfail2 cfail3
 // compile-flags: -Z query-dep-graph -O
 // build-pass (FIXME(62277): could be check-pass?)
 
     cfg = "cfail3",
     kind = "post-lto"
 )]
-#![rustc_expected_cgu_reuse(
-    module = "cgu_keeps_identical_fn-foo",
-    cfg = "cfail5",
-    kind = "post-lto"
-)]
-#![rustc_expected_cgu_reuse(
-    module = "cgu_keeps_identical_fn-foo",
-    cfg = "cfail6",
-    kind = "post-lto"
-)]
 #![rustc_expected_cgu_reuse(
     module = "cgu_keeps_identical_fn-bar",
     cfg = "cfail2",
     cfg = "cfail3",
     kind = "post-lto"
 )]
-#![rustc_expected_cgu_reuse(
-    module = "cgu_keeps_identical_fn-bar",
-    cfg = "cfail5",
-    kind = "post-lto"
-)]
-#![rustc_expected_cgu_reuse(
-    module = "cgu_keeps_identical_fn-bar",
-    cfg = "cfail6",
-    kind = "post-lto"
-)]
 
 mod foo {
 
index afe157ccd7faa3d08361122791c41967f3014620..5f3ee467c88cb026144d63eff156b74d19306742 100644 (file)
@@ -10,6 +10,8 @@
 +         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         let mut _4: &fn() {main};        // in scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         let mut _5: ();                  // in scope 1 at $DIR/cycle.rs:6:5: 6:8
++         scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
++         }
 +     }
   
       bb0: {
 +         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         _3 = <fn() {main} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+                                          // mir::Constant
-+                                          // + span: $DIR/cycle.rs:6:5: 6:6
-+                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {main}, ()) -> <fn() {main} as FnOnce<()>>::Output {<fn() {main} as Fn<()>>::call}, val: Value(<ZST>) }
++         _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
           return;                          // scope 0 at $DIR/cycle.rs:+2:2: +2:2
 +     }
 + 
-+     bb2: {
-+         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
-+         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++     bb2 (cleanup): {
++         drop(_2) -> bb3;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
 +     }
 + 
 +     bb3 (cleanup): {
-+         drop(_2) -> bb4;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
 +     }
 + 
-+     bb4 (cleanup): {
-+         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
++     bb4: {
++         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
++         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
       }
   }
   
index bd89e09ecd148b4e52384621802be95f24c94e43..6b4c63bbd917f61b488587ec177c7ec8d02b848a 100644 (file)
@@ -10,6 +10,8 @@
 +         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         let mut _4: &fn() {g};           // in scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         let mut _5: ();                  // in scope 1 at $DIR/cycle.rs:6:5: 6:8
++         scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8
++         }
 +     }
   
       bb0: {
 +         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         _3 = <fn() {g} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+                                          // mir::Constant
-+                                          // + span: $DIR/cycle.rs:6:5: 6:6
-+                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {g}, ()) -> <fn() {g} as FnOnce<()>>::Output {<fn() {g} as Fn<()>>::call}, val: Value(<ZST>) }
++         _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
           return;                          // scope 0 at $DIR/cycle.rs:+2:2: +2:2
 +     }
 + 
-+     bb2: {
-+         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
-+         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
-+         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++     bb2 (cleanup): {
++         drop(_2) -> bb3;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
 +     }
 + 
 +     bb3 (cleanup): {
-+         drop(_2) -> bb4;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
 +     }
 + 
-+     bb4 (cleanup): {
-+         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
++     bb4: {
++         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
++         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
       }
   }
   
index d9fd7b324c7619e79a1fa373b9ebba312225d8c6..7fd62be7ab9c35cedea97f6a4727f9742a89d107 100644 (file)
@@ -8,43 +8,68 @@
 +         let _2: ();                      // in scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
 +         let _3: ();                      // in scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
 +         let _4: ();                      // in scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++         scope 2 (inlined <() as F>::call) { // at $DIR/exponential_runtime.rs:73:9: 73:25
++             let _5: ();                  // in scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
++             let _6: ();                  // in scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++             let _7: ();                  // in scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++         }
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
 -         _1 = <() as G>::call() -> bb1;   // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
 +         StorageLive(_2);                 // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
-+         _2 = <() as F>::call() -> bb1;   // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
++         StorageLive(_5);                 // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
++         _5 = <() as E>::call() -> bb3;   // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
                                            // mir::Constant
 -                                          // + span: $DIR/exponential_runtime.rs:86:5: 86:20
 -                                          // + literal: Const { ty: fn() {<() as G>::call}, val: Value(<ZST>) }
-+                                          // + span: $DIR/exponential_runtime.rs:73:9: 73:23
-+                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
++                                          // + span: $DIR/exponential_runtime.rs:61:9: 61:23
++                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
-+         StorageDead(_2);                 // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
-+         StorageLive(_3);                 // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
-+         _3 = <() as F>::call() -> bb2;   // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
-+                                          // mir::Constant
-+                                          // + span: $DIR/exponential_runtime.rs:74:9: 74:23
-+                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
-+     }
-+ 
-+     bb2: {
 +         StorageDead(_3);                 // scope 1 at $DIR/exponential_runtime.rs:74:25: 74:26
 +         StorageLive(_4);                 // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
-+         _4 = <() as F>::call() -> bb3;   // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
++         _4 = <() as F>::call() -> bb2;   // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
 +                                          // mir::Constant
 +                                          // + span: $DIR/exponential_runtime.rs:75:9: 75:23
 +                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
 +     }
 + 
-+     bb3: {
++     bb2: {
 +         StorageDead(_4);                 // scope 1 at $DIR/exponential_runtime.rs:75:25: 75:26
           StorageDead(_1);                 // scope 0 at $DIR/exponential_runtime.rs:+1:22: +1:23
           _0 = const ();                   // scope 0 at $DIR/exponential_runtime.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/exponential_runtime.rs:+2:2: +2:2
++     }
++ 
++     bb3: {
++         StorageDead(_5);                 // scope 2 at $DIR/exponential_runtime.rs:61:25: 61:26
++         StorageLive(_6);                 // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++         _6 = <() as E>::call() -> bb4;   // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
++                                          // mir::Constant
++                                          // + span: $DIR/exponential_runtime.rs:62:9: 62:23
++                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
++     }
++ 
++     bb4: {
++         StorageDead(_6);                 // scope 2 at $DIR/exponential_runtime.rs:62:25: 62:26
++         StorageLive(_7);                 // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++         _7 = <() as E>::call() -> bb5;   // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
++                                          // mir::Constant
++                                          // + span: $DIR/exponential_runtime.rs:63:9: 63:23
++                                          // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
++     }
++ 
++     bb5: {
++         StorageDead(_7);                 // scope 2 at $DIR/exponential_runtime.rs:63:25: 63:26
++         StorageDead(_2);                 // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
++         StorageLive(_3);                 // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++         _3 = <() as F>::call() -> bb1;   // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
++                                          // mir::Constant
++                                          // + span: $DIR/exponential_runtime.rs:74:9: 74:23
++                                          // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
       }
   }
   
index f54a1a747d47436aba941cb1ab4df23f43bad2b4..5510cd7bc8ced1d003fbd3b3fd914263c1466c44 100644 (file)
@@ -5,17 +5,20 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10
       let _1: ();                          // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
 +     scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle.rs:14:5: 14:24
++         scope 2 (inlined <A<C> as Call>::call) { // at $DIR/inline_cycle.rs:43:9: 43:23
++             scope 3 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle.rs:28:9: 28:31
++             }
++         }
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
 -         _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
-+         _1 = <A<C> as Call>::call() -> bb1; // scope 1 at $DIR/inline_cycle.rs:43:9: 43:23
++         _1 = <C as Call>::call() -> bb1; // scope 3 at $DIR/inline_cycle.rs:36:9: 36:28
                                            // mir::Constant
 -                                          // + span: $DIR/inline_cycle.rs:14:5: 14:22
--                                          // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
-+                                          // + span: $DIR/inline_cycle.rs:43:9: 43:21
-+                                          // + literal: Const { ty: fn() {<A<C> as Call>::call}, val: Value(<ZST>) }
++                                          // + span: $DIR/inline_cycle.rs:36:9: 36:26
+                                           // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
index a940848c269cda8d5a5a98dd968f334f687dd0a4..64c0065b5436dea0b630e1879b8a39ec1d2b8e5d 100644 (file)
@@ -9,6 +9,8 @@
 +         debug f => _2;                   // in scope 1 at $DIR/inline_cycle.rs:53:22: 53:23
 +         let _3: ();                      // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
 +         let mut _4: ();                  // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
++         scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline_cycle.rs:54:5: 54:8
++         }
 +     }
   
       bb0: {
                                            // + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
 +         StorageLive(_3);                 // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
 +         StorageLive(_4);                 // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+         _3 = <fn() {f} as FnOnce<()>>::call_once(move _2, move _4) -> bb1; // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
-+                                          // mir::Constant
-+                                          // + span: $DIR/inline_cycle.rs:54:5: 54:6
-+                                          // + literal: Const { ty: extern "rust-call" fn(fn() {f}, ()) -> <fn() {f} as FnOnce<()>>::Output {<fn() {f} as FnOnce<()>>::call_once}, val: Value(<ZST>) }
++         _3 = move _2() -> bb1;           // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
index 04de3e61e5ff81f6b148d18fae783ac62bad7dc8..52debab4dd1c0348ed20ea66294415146254c6f6 100644 (file)
@@ -6,18 +6,21 @@
       let _1: ();                          // in scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
 +     scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle_generic.rs:9:5: 9:24
 +         scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline_cycle_generic.rs:38:9: 38:31
++             scope 3 (inlined <A as Call>::call) { // at $DIR/inline_cycle_generic.rs:31:9: 31:28
++                 scope 4 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle_generic.rs:23:9: 23:31
++                 }
++             }
 +         }
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
 -         _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
-+         _1 = <A as Call>::call() -> bb1; // scope 2 at $DIR/inline_cycle_generic.rs:31:9: 31:28
++         _1 = <C as Call>::call() -> bb1; // scope 4 at $DIR/inline_cycle_generic.rs:31:9: 31:28
                                            // mir::Constant
 -                                          // + span: $DIR/inline_cycle_generic.rs:9:5: 9:22
--                                          // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
 +                                          // + span: $DIR/inline_cycle_generic.rs:31:9: 31:26
-+                                          // + literal: Const { ty: fn() {<A as Call>::call}, val: Value(<ZST>) }
+                                           // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
index a01bcf1645b0571fe7f662353b5bf6ce1db23725..f82fcf4c82129634ee7d4a2288e85226031378fe 100644 (file)
@@ -20,6 +20,8 @@
 +                 debug b => _9;           // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10
 +             }
 +         }
++         scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16
++         }
 +     }
   
       bb0: {
 +         StorageLive(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
 +         _4 = &_2;                        // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
 +         StorageLive(_5);                 // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+         _3 = <fn() -> ! {sleep} as Fn<()>>::call(move _4, move _5) -> [return: bb1, unwind: bb5]; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
-+                                          // mir::Constant
-+                                          // + span: $DIR/inline_diverging.rs:27:13: 27:14
-+                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
++         _3 = move (*_4)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL
 +     }
 + 
 +     bb1: {
-+         StorageDead(_5);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
-+         StorageDead(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
-+         StorageLive(_6);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
-+         _6 = &_2;                        // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
-+         StorageLive(_7);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
-+         _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb2, unwind: bb4]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
-+                                          // mir::Constant
-+                                          // + span: $DIR/inline_diverging.rs:28:13: 28:14
-+                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
-+     }
-+ 
-+     bb2: {
 +         StorageDead(_7);                 // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
 +         StorageDead(_6);                 // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
 +         StorageLive(_8);                 // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
 +         (_1.1: !) = move _9;             // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
 +         StorageDead(_8);                 // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11
 +         StorageDead(_3);                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
-+         drop(_2) -> bb3;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++         drop(_2) -> bb2;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
 +     }
 + 
-+     bb3: {
++     bb2: {
 +         unreachable;                     // scope 0 at $DIR/inline_diverging.rs:30:2: 30:2
 +     }
 + 
++     bb3 (cleanup): {
++         drop(_3) -> bb4;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++     }
++ 
 +     bb4 (cleanup): {
-+         drop(_3) -> bb5;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++         drop(_2) -> bb5;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
 +     }
 + 
 +     bb5 (cleanup): {
-+         drop(_2) -> bb6;                 // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
++         resume;                          // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2
 +     }
 + 
-+     bb6 (cleanup): {
-+         resume;                          // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2
++     bb6: {
++         StorageDead(_5);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++         StorageDead(_4);                 // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
++         StorageLive(_6);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++         _6 = &_2;                        // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
++         StorageLive(_7);                 // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++         _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
++                                          // mir::Constant
++                                          // + span: $DIR/inline_diverging.rs:28:13: 28:14
++                                          // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
       }
   }
   
index 6ae16bdb5b88a6b673807d83b9a32fedf2c0b6c6..e57544e09e2a0f6a137240c628ad852ebeff31a3 100644 (file)
@@ -22,6 +22,9 @@
                   let mut _18: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
                   scope 9 {
                       debug e => _16;      // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+                      scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
+                          debug t => _18;  // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+                      }
                   }
               }
           }
           StorageLive(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageLive(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           _18 = move _16;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
--         _17 = <i32 as From<i32>>::from(move _18) -> bb8; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-+         _17 = <i32 as From<i32>>::from(move _18) -> bb7; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/result.rs:LL:COL
-                                           // + literal: Const { ty: fn(i32) -> i32 {<i32 as From<i32>>::from}, val: Value(<ZST>) }
+          _17 = move _18;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+          StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          StorageDead(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
+          StorageDead(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
+          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
+          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
+          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
+          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
       }
   
 -     bb5: {
 +         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
 +         switchInt(move _5) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
       }
-  
--     bb8: {
-+     bb7: {
-          StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-      }
   }
   
diff --git a/src/test/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir b/src/test/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir
new file mode 100644 (file)
index 0000000..916f990
--- /dev/null
@@ -0,0 +1,52 @@
+// MIR for `ezmap` after PreCodegen
+
+fn ezmap(_1: Option<i32>) -> Option<i32> {
+    debug x => _1;                       // in scope 0 at $DIR/simple_option_map_e2e.rs:+0:14: +0:15
+    let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/simple_option_map_e2e.rs:+0:33: +0:44
+    let mut _2: [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]; // in scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21
+    scope 1 (inlined map::<i32, i32, [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]>) { // at $DIR/simple_option_map_e2e.rs:14:5: 14:22
+        debug slf => _1;                 // in scope 1 at $DIR/simple_option_map_e2e.rs:2:17: 2:20
+        debug f => _2;                   // in scope 1 at $DIR/simple_option_map_e2e.rs:2:33: 2:34
+        let mut _3: isize;               // in scope 1 at $DIR/simple_option_map_e2e.rs:7:9: 7:16
+        let mut _4: i32;                 // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+        let mut _5: i32;                 // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+        scope 2 {
+            debug x => _5;               // in scope 2 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+            scope 3 (inlined ezmap::{closure#0}) { // at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+                debug n => _5;           // in scope 3 at $DIR/simple_option_map_e2e.rs:+1:13: +1:14
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21
+        _3 = discriminant(_1);           // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14
+        switchInt(move _3) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 1 at $DIR/simple_option_map_e2e.rs:6:5: 6:14
+    }
+
+    bb1: {
+        Deinit(_0);                      // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+        discriminant(_0) = 0;            // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+        goto -> bb4;                     // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
+    }
+
+    bb2: {
+        unreachable;                     // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14
+    }
+
+    bb3: {
+        _5 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+        StorageLive(_4);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
+        _4 = Add(move _5, const 1_i32);  // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
+        Deinit(_0);                      // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
+        ((_0 as Some).0: i32) = move _4; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
+        discriminant(_0) = 1;            // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
+        StorageDead(_4);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:29: 7:30
+        goto -> bb4;                     // scope 1 at $DIR/simple_option_map_e2e.rs:10:1: 10:2
+    }
+
+    bb4: {
+        StorageDead(_2);                 // scope 0 at $DIR/simple_option_map_e2e.rs:+1:21: +1:22
+        return;                          // scope 0 at $DIR/simple_option_map_e2e.rs:+2:2: +2:2
+    }
+}
diff --git a/src/test/mir-opt/simple_option_map_e2e.rs b/src/test/mir-opt/simple_option_map_e2e.rs
new file mode 100644 (file)
index 0000000..2acd2a2
--- /dev/null
@@ -0,0 +1,19 @@
+#[inline(always)]
+fn map<T, U, F>(slf: Option<T>, f: F) -> Option<U>
+where
+    F: FnOnce(T) -> U,
+{
+    match slf {
+        Some(x) => Some(f(x)),
+        None => None,
+    }
+}
+
+// EMIT_MIR simple_option_map_e2e.ezmap.PreCodegen.after.mir
+pub fn ezmap(x: Option<i32>) -> Option<i32> {
+    map(x, |n| n + 1)
+}
+
+fn main() {
+    assert_eq!(None, ezmap(None));
+}
index 74aaabfbf1b4b5416f4f331c0d1da05b088fb0ec..384589de3b4807b789679eca7020edfdd3006ad1 100644 (file)
@@ -5,6 +5,11 @@
 extern crate rustc_graphviz;
 // A simple rust project
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 extern crate krate2;
 extern crate krate2 as krate3;
 
index 8645c1b1949e3f79533a5d76345bea8aec5285b6..6f9209e0ab4a00fc6e0b0dd544312fbef169f0b9 100644 (file)
@@ -1,3 +1,4 @@
+// This test checks the appearance of the tables in the doc comments.
 goto: "file://" + |DOC_PATH| + "/test_docs/doc_block_table/struct.DocBlockTable.html#method.func"
 
 compare-elements-css: (".impl-items .docblock table th", ".top-doc .docblock table th", ["border"])
index 8a33e713191292cebd0082c94858ddf0b12fe3cf..aa79219696020726ead0c3ed38077cf6ebc3aa6e 100644 (file)
@@ -111,8 +111,57 @@ assert-property: ("#source-sidebar details:first-of-type", {"open": "true"})
 click: "#source-sidebar details:first-of-type > summary"
 assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
 
-// Check the spacing.
-assert-css: ("#source-sidebar > details.dir-entry", {"padding-left": "4px"})
+// And open it again, since it'll be the reference we use to check positions.
+click: "#source-sidebar details:first-of-type > summary"
+assert-property: ("#source-sidebar details:first-of-type", {"open": "true"})
+
+// Check the sidebar directory entries have a marker and spacing (desktop).
+store-property: (
+    link_height,
+    "#source-sidebar > details:first-of-type.dir-entry[open] > .files > a",
+    "offsetHeight"
+)
+define-function: (
+    "check-sidebar-dir-entry",
+    (x, y),
+    [
+        ("assert", "details:first-of-type.dir-entry[open] > summary::marker"),
+        ("assert-css", ("#source-sidebar > details:first-of-type.dir-entry", {"padding-left": "4px"})),
+        // This check ensures that the summary is only one line.
+       ("assert-property", (
+            "#source-sidebar > details:first-of-type.dir-entry[open] > summary",
+            {"offsetHeight": |link_height|}
+        )),
+        ("assert-position", (
+            "#source-sidebar > details:first-of-type.dir-entry[open] > summary",
+            {"x": |x|, "y": |y|}
+        )),
+        ("assert-property", (
+            "#source-sidebar > details:first-of-type.dir-entry[open] > .files > a",
+            {"offsetHeight": |link_height|}
+        )),
+        ("assert-position", (
+            "#source-sidebar > details:first-of-type.dir-entry[open] > .files > a",
+            // left margin
+            {"x": |x| + 27, "y": |y| + |link_height|}
+        )),
+    ]
+)
+store-property: (
+    source_sidebar_title_height,
+    "#source-sidebar > .title",
+    "offsetHeight"
+)
+store-property: (
+    source_sidebar_title_y,
+    "#source-sidebar > .title",
+    "offsetTop"
+)
+call-function: ("check-sidebar-dir-entry", {
+    "x": 0,
+    // border + margin = 6
+    "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
+})
 
 // Check the search form
 assert-css: ("nav.sub", {"flex-direction": "row"})
@@ -125,13 +174,45 @@ assert-property: ("nav.sub form", {"offsetTop": 28, "offsetHeight": 34})
 assert-property: ("#main-content", {"offsetTop": 90})
 // 28 = 90 - 34 - 28
 
-// Now do the same check on moderately-sized mobile.
+// Now do the same check on moderately-sized, tablet mobile.
 size: (700, 700)
 assert-css: ("nav.sub", {"flex-direction": "row"})
 assert-property: ("nav.sub form", {"offsetTop": 21, "offsetHeight": 34})
 assert-property: ("#main-content", {"offsetTop": 76})
 // 21 = 76 - 34 - 21
 
-// Tiny mobile gets a different display where the logo is stacked on top.
+// Check the sidebar directory entries have a marker and spacing (tablet).
+store-property: (
+    source_sidebar_title_height,
+    "#source-sidebar > .title",
+    "offsetHeight"
+)
+store-property: (
+    source_sidebar_title_y,
+    "#source-sidebar > .title",
+    "offsetTop"
+)
+call-function: ("check-sidebar-dir-entry", {
+    "x": 0,
+    "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
+})
+
+// Tiny, phone mobile gets a different display where the logo is stacked on top.
 size: (450, 700)
 assert-css: ("nav.sub", {"flex-direction": "column"})
+
+// Check the sidebar directory entries have a marker and spacing (phone).
+store-property: (
+    source_sidebar_title_height,
+    "#source-sidebar > .title",
+    "offsetHeight"
+)
+store-property: (
+    source_sidebar_title_y,
+    "#source-sidebar > .title",
+    "offsetTop"
+)
+call-function: ("check-sidebar-dir-entry", {
+    "x": 0,
+    "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6,
+})
index 8c221615aa753ebc9b38ee9f480af7fe10881bed..06906df3b2c64abed8e5e711db781e987d32d270 100644 (file)
@@ -1,12 +1,12 @@
 #[repr(i8)]
 pub enum Ordering {
-    // @is "$.index[*][?(@.name=='Less')].inner.variant_inner.expr" '"-1"'
-    // @is "$.index[*][?(@.name=='Less')].inner.variant_inner.value" '"-1"'
+    // @is "$.index[*][?(@.name=='Less')].inner.discriminant.expr" '"-1"'
+    // @is "$.index[*][?(@.name=='Less')].inner.discriminant.value" '"-1"'
     Less = -1,
-    // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.expr" '"0"'
-    // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.value" '"0"'
+    // @is "$.index[*][?(@.name=='Equal')].inner.discriminant.expr" '"0"'
+    // @is "$.index[*][?(@.name=='Equal')].inner.discriminant.value" '"0"'
     Equal = 0,
-    // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.expr" '"1"'
-    // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.value" '"1"'
+    // @is "$.index[*][?(@.name=='Greater')].inner.discriminant.expr" '"1"'
+    // @is "$.index[*][?(@.name=='Greater')].inner.discriminant.value" '"1"'
     Greater = 1,
 }
index 235b0b47381fce51acaac7d2c1163b23b7eb1951..e639965e79b428e180ed94a959dd3d5219e10365 100644 (file)
@@ -1,30 +1,30 @@
 pub enum Foo {
-    // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.value" '"0"'
-    // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='Addition')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='Addition')].inner.discriminant.expr" '"{ _ }"'
     Addition = 0 + 0,
-    // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.value" '"1"'
-    // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.expr" '"0b1"'
+    // @is "$.index[*][?(@.name=='Bin')].inner.discriminant.value" '"1"'
+    // @is "$.index[*][?(@.name=='Bin')].inner.discriminant.expr" '"0b1"'
     Bin = 0b1,
-    // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.value" '"2"'
-    // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.expr" '"0o2"'
+    // @is "$.index[*][?(@.name=='Oct')].inner.discriminant.value" '"2"'
+    // @is "$.index[*][?(@.name=='Oct')].inner.discriminant.expr" '"0o2"'
     Oct = 0o2,
-    // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.value" '"3"'
-    // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.expr" '"THREE"'
+    // @is "$.index[*][?(@.name=='PubConst')].inner.discriminant.value" '"3"'
+    // @is "$.index[*][?(@.name=='PubConst')].inner.discriminant.expr" '"THREE"'
     PubConst = THREE,
-    // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.value" '"4"'
-    // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.expr" '"0x4"'
+    // @is "$.index[*][?(@.name=='Hex')].inner.discriminant.value" '"4"'
+    // @is "$.index[*][?(@.name=='Hex')].inner.discriminant.expr" '"0x4"'
     Hex = 0x4,
-    // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.value" '"5"'
-    // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='Cast')].inner.discriminant.value" '"5"'
+    // @is "$.index[*][?(@.name=='Cast')].inner.discriminant.expr" '"{ _ }"'
     Cast = 5 as isize,
-    // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.value" '"6"'
-    // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='PubCall')].inner.discriminant.value" '"6"'
+    // @is "$.index[*][?(@.name=='PubCall')].inner.discriminant.expr" '"{ _ }"'
     PubCall = six(),
-    // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.value" '"7"'
-    // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='PrivCall')].inner.discriminant.value" '"7"'
+    // @is "$.index[*][?(@.name=='PrivCall')].inner.discriminant.expr" '"{ _ }"'
     PrivCall = seven(),
-    // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.value" '"8"'
-    // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.expr" '"EIGHT"'
+    // @is "$.index[*][?(@.name=='PrivConst')].inner.discriminant.value" '"8"'
+    // @is "$.index[*][?(@.name=='PrivConst')].inner.discriminant.expr" '"EIGHT"'
     PrivConst = EIGHT,
 }
 
index 8df73d78d237fd2e09cd2deccd8a90dee5bfb821..e56d5594f2fc915730be2531d85e2f47e43fa20d 100644 (file)
@@ -4,40 +4,40 @@
 
 #[repr(u64)]
 pub enum U64 {
-    // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.value" '"0"'
-    // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.expr" '"u64::MIN"'
+    // @is "$.index[*][?(@.name=='U64Min')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='U64Min')].inner.discriminant.expr" '"u64::MIN"'
     U64Min = u64::MIN,
-    // @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.value" '"18446744073709551615"'
-    // @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.expr" '"u64::MAX"'
+    // @is "$.index[*][?(@.name=='U64Max')].inner.discriminant.value" '"18446744073709551615"'
+    // @is "$.index[*][?(@.name=='U64Max')].inner.discriminant.expr" '"u64::MAX"'
     U64Max = u64::MAX,
 }
 
 #[repr(i64)]
 pub enum I64 {
-    // @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.value" '"-9223372036854775808"'
-    // @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.expr" '"i64::MIN"'
+    // @is "$.index[*][?(@.name=='I64Min')].inner.discriminant.value" '"-9223372036854775808"'
+    // @is "$.index[*][?(@.name=='I64Min')].inner.discriminant.expr" '"i64::MIN"'
     I64Min = i64::MIN,
-    // @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.value" '"9223372036854775807"'
-    // @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.expr" '"i64::MAX"'
+    // @is "$.index[*][?(@.name=='I64Max')].inner.discriminant.value" '"9223372036854775807"'
+    // @is "$.index[*][?(@.name=='I64Max')].inner.discriminant.expr" '"i64::MAX"'
     I64Max = i64::MAX,
 }
 
 #[repr(u128)]
 pub enum U128 {
-    // @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.value" '"0"'
-    // @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.expr" '"u128::MIN"'
+    // @is "$.index[*][?(@.name=='U128Min')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='U128Min')].inner.discriminant.expr" '"u128::MIN"'
     U128Min = u128::MIN,
-    // @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.value" '"340282366920938463463374607431768211455"'
-    // @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.expr" '"u128::MAX"'
+    // @is "$.index[*][?(@.name=='U128Max')].inner.discriminant.value" '"340282366920938463463374607431768211455"'
+    // @is "$.index[*][?(@.name=='U128Max')].inner.discriminant.expr" '"u128::MAX"'
     U128Max = u128::MAX,
 }
 
 #[repr(i128)]
 pub enum I128 {
-    // @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.value" '"-170141183460469231731687303715884105728"'
-    // @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.expr" '"i128::MIN"'
+    // @is "$.index[*][?(@.name=='I128Min')].inner.discriminant.value" '"-170141183460469231731687303715884105728"'
+    // @is "$.index[*][?(@.name=='I128Min')].inner.discriminant.expr" '"i128::MIN"'
     I128Min = i128::MIN,
-    // @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.value" '"170141183460469231731687303715884105727"'
-    // @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.expr" '"i128::MAX"'
+    // @is "$.index[*][?(@.name=='I128Max')].inner.discriminant.value" '"170141183460469231731687303715884105727"'
+    // @is "$.index[*][?(@.name=='I128Max')].inner.discriminant.expr" '"i128::MAX"'
     I128Max = i128::MAX,
 }
index 3417baa0760e1a76cc5a71a6af54357dc987c84c..6889b305ffb41b32c475100bfe62afd7ad5b86ad 100644 (file)
@@ -1,15 +1,15 @@
 #[repr(u32)]
 pub enum Foo {
-    // @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.value" '"0"'
-    // @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.expr" '"0"'
+    // @is "$.index[*][?(@.name=='Basic')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='Basic')].inner.discriminant.expr" '"0"'
     Basic = 0,
-    // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.value" '"10"'
-    // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.expr" '"10u32"'
+    // @is "$.index[*][?(@.name=='Suffix')].inner.discriminant.value" '"10"'
+    // @is "$.index[*][?(@.name=='Suffix')].inner.discriminant.expr" '"10u32"'
     Suffix = 10u32,
-    // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.value" '"100"'
-    // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.expr" '"1_0_0"'
+    // @is "$.index[*][?(@.name=='Underscore')].inner.discriminant.value" '"100"'
+    // @is "$.index[*][?(@.name=='Underscore')].inner.discriminant.expr" '"1_0_0"'
     Underscore = 1_0_0,
-    // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.value" '"1000"'
-    // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.expr" '"1_0_0_0u32"'
+    // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.discriminant.value" '"1000"'
+    // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.discriminant.expr" '"1_0_0_0u32"'
     SuffixUnderscore = 1_0_0_0u32,
 }
index 6af944a2219ef6f4c7f0dad91c13da9ca95f3022..6a4f54de617454a7528bc299db0e0edf81439d6c 100644 (file)
@@ -1,10 +1,10 @@
 pub enum Foo {
-    // @is "$.index[*][?(@.name=='Has')].inner.variant_inner" '{"expr":"0", "value":"0"}'
+    // @is "$.index[*][?(@.name=='Has')].inner.discriminant" '{"expr":"0", "value":"0"}'
     Has = 0,
-    // @is "$.index[*][?(@.name=='Doesnt')].inner.variant_inner" null
+    // @is "$.index[*][?(@.name=='Doesnt')].inner.discriminant" null
     Doesnt,
-    // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant_inner" null
+    // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.discriminant" null
     AlsoDoesnt,
-    // @is "$.index[*][?(@.name=='AlsoHas')].inner.variant_inner" '{"expr":"44", "value":"44"}'
+    // @is "$.index[*][?(@.name=='AlsoHas')].inner.discriminant" '{"expr":"44", "value":"44"}'
     AlsoHas = 44,
 }
diff --git a/src/test/rustdoc-json/enums/discriminant/struct.rs b/src/test/rustdoc-json/enums/discriminant/struct.rs
new file mode 100644 (file)
index 0000000..e91a632
--- /dev/null
@@ -0,0 +1,15 @@
+// ignore-tidy-linelength
+
+#[repr(i32)]
+// @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(i32)]"]'
+pub enum Foo {
+    // @is    "$.index[*][?(@.name=='Struct')].inner.discriminant" null
+    // @count "$.index[*][?(@.name=='Struct')].inner.kind.struct.fields[*]" 0
+    Struct {},
+    // @is    "$.index[*][?(@.name=='StructWithDiscr')].inner.discriminant" '{"expr": "42", "value": "42"}'
+    // @count "$.index[*][?(@.name=='StructWithDiscr')].inner.kind.struct.fields[*]" 1
+    StructWithDiscr { x: i32 } = 42,
+    // @is    "$.index[*][?(@.name=='StructWithHexDiscr')].inner.discriminant"  '{"expr": "0x42", "value": "66"}'
+    // @count "$.index[*][?(@.name=='StructWithHexDiscr')].inner.kind.struct.fields[*]" 2
+    StructWithHexDiscr { x: i32, y: bool } = 0x42,
+}
diff --git a/src/test/rustdoc-json/enums/discriminant/tuple.rs b/src/test/rustdoc-json/enums/discriminant/tuple.rs
new file mode 100644 (file)
index 0000000..b94d573
--- /dev/null
@@ -0,0 +1,15 @@
+// ignore-tidy-linelength
+
+#[repr(u32)]
+// @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(u32)]"]'
+pub enum Foo {
+    // @is    "$.index[*][?(@.name=='Tuple')].inner.discriminant" null
+    // @count "$.index[*][?(@.name=='Tuple')].inner.kind.tuple[*]" 0
+    Tuple(),
+    // @is    "$.index[*][?(@.name=='TupleWithDiscr')].inner.discriminant" '{"expr": "1", "value": "1"}'
+    // @count "$.index[*][?(@.name=='TupleWithDiscr')].inner.kind.tuple[*]" 1
+    TupleWithDiscr(i32) = 1,
+    // @is    "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.discriminant" '{"expr": "0b10", "value": "2"}'
+    // @count "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.kind.tuple[*]" 2
+    TupleWithBinDiscr(i32, i32) = 0b10,
+}
index e6310cc3b997c28860234fd3c461596c8ec9ada7..78a05431472cb8874cc80439fbc0e973ab18d506 100644 (file)
@@ -5,8 +5,8 @@
 
 // @has "$.index[*][?(@.name=='ParseError')]"
 // @has "$.index[*][?(@.name=='UnexpectedEndTag')]"
-// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_kind" '"tuple"'
-// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_inner" [null]
+// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.kind.tuple" [null]
+// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.discriminant" null
 
 pub enum ParseError {
     UnexpectedEndTag(#[doc(hidden)] u32),
index e9ea3ae23c226808ff861878613b359aca050163..1787a859c8b37c8fb4afb11d80e25dca246f960e 100644 (file)
@@ -5,27 +5,22 @@
 
 pub enum Foo {
     // @set Unit = "$.index[*][?(@.name=='Unit')].id"
-    // @is "$.index[*][?(@.name=='Unit')].inner.variant_kind" '"plain"'
-    // @is "$.index[*][?(@.name=='Unit')].inner.variant_inner" null
+    // @is "$.index[*][?(@.name=='Unit')].inner.kind" '"plain"'
     Unit,
     // @set Named = "$.index[*][?(@.name=='Named')].id"
-    // @is "$.index[*][?(@.name=='Named')].inner.variant_kind" '"struct"'
-    // @is "$.index[*][?(@.name=='Named')].inner.variant_inner" '{"fields": [], "fields_stripped": false}'
+    // @is "$.index[*][?(@.name=='Named')].inner.kind.struct" '{"fields": [], "fields_stripped": false}'
     Named {},
     // @set Tuple = "$.index[*][?(@.name=='Tuple')].id"
-    // @is "$.index[*][?(@.name=='Tuple')].inner.variant_kind" '"tuple"'
-    // @is "$.index[*][?(@.name=='Tuple')].inner.variant_inner" []
+    // @is "$.index[*][?(@.name=='Tuple')].inner.kind.tuple" []
     Tuple(),
     // @set NamedField = "$.index[*][?(@.name=='NamedField')].id"
     // @set x = "$.index[*][?(@.name=='x' && @.kind=='struct_field')].id"
-    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_kind" '"struct"'
-    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields[*]" $x
-    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields_stripped" false
+    // @is "$.index[*][?(@.name=='NamedField')].inner.kind.struct.fields[*]" $x
+    // @is "$.index[*][?(@.name=='NamedField')].inner.kind.struct.fields_stripped" false
     NamedField { x: i32 },
     // @set TupleField = "$.index[*][?(@.name=='TupleField')].id"
-    // @is "$.index[*][?(@.name=='TupleField')].inner.variant_kind" '"tuple"'
     // @set tup_field = "$.index[*][?(@.name=='0' && @.kind=='struct_field')].id"
-    // @is "$.index[*][?(@.name=='TupleField')].inner.variant_inner[*]" $tup_field
+    // @is "$.index[*][?(@.name=='TupleField')].inner.kind.tuple[*]" $tup_field
     TupleField(i32),
 }
 
index f612a34a4927744b55462662c7ee457aef6fa5cf..de939cde2e7b34b990736d3664a39dca6202e0b8 100644 (file)
@@ -9,9 +9,8 @@ pub enum Foo {
         // @set y = "$.index[*][?(@.name=='y')].id"
         y: i32,
     },
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_kind" '"struct"'
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields_stripped" true
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[0]" $b
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[1]" $y
-    // @count "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[*]" 2
+    // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields_stripped" true
+    // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[0]" $b
+    // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[1]" $y
+    // @count "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[*]" 2
 }
index f546eaa0d172df6beb83ecba8d83f213318f50b2..70bfbb81826bee450acfcc2018d34da3661e449a 100644 (file)
 // @set 3.3.1 = "$.index[*][?(@.docs=='3.3.1')].id"
 
 pub enum EnumWithStrippedTupleVariants {
-    // @is    "$.index[*][?(@.name=='None')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='None')].inner.variant_inner[*]" 0
+    // @count "$.index[*][?(@.name=='None')].inner.kind.tuple[*]" 0
     None(),
 
-    // @is    "$.index[*][?(@.name=='One')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='One')].inner.variant_inner[*]" 1
-    // @is    "$.index[*][?(@.name=='One')].inner.variant_inner[0]" $1.1.0
+    // @count "$.index[*][?(@.name=='One')].inner.kind.tuple[*]" 1
+    // @is    "$.index[*][?(@.name=='One')].inner.kind.tuple[0]" $1.1.0
     One(/** 1.1.0*/ bool),
-    // @is    "$.index[*][?(@.name=='OneHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[*]" 1
-    // @is    "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[0]" null
+    // @count "$.index[*][?(@.name=='OneHidden')].inner.kind.tuple[*]" 1
+    // @is    "$.index[*][?(@.name=='OneHidden')].inner.kind.tuple[0]" null
     OneHidden(#[doc(hidden)] bool),
 
-    // @is    "$.index[*][?(@.name=='Two')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Two')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='Two')].inner.variant_inner[0]" $2.1.0
-    // @is    "$.index[*][?(@.name=='Two')].inner.variant_inner[1]" $2.1.1
+    // @count "$.index[*][?(@.name=='Two')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='Two')].inner.kind.tuple[0]" $2.1.0
+    // @is    "$.index[*][?(@.name=='Two')].inner.kind.tuple[1]" $2.1.1
     Two(/** 2.1.0*/ bool, /** 2.1.1*/ bool),
-    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[0]" null
-    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[1]" $2.2.1
+    // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[0]" null
+    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[1]" $2.2.1
     TwoLeftHidden(#[doc(hidden)] bool, /** 2.2.1*/ bool),
-    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[0]" $2.3.0
-    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[1]" null
+    // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[0]" $2.3.0
+    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[1]" null
     TwoRightHidden(/** 2.3.0*/ bool, #[doc(hidden)] bool),
-    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[0]" null
-    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[1]" null
+    // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[0]" null
+    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[1]" null
     TwoBothHidden(#[doc(hidden)] bool, #[doc(hidden)] bool),
 
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Three1')].inner.variant_inner[*]" 3
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[0]" null
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[1]" $3.1.1
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[2]" $3.1.2
+    // @count "$.index[*][?(@.name=='Three1')].inner.kind.tuple[*]" 3
+    // @is    "$.index[*][?(@.name=='Three1')].inner.kind.tuple[0]" null
+    // @is    "$.index[*][?(@.name=='Three1')].inner.kind.tuple[1]" $3.1.1
+    // @is    "$.index[*][?(@.name=='Three1')].inner.kind.tuple[2]" $3.1.2
     Three1(#[doc(hidden)] bool, /** 3.1.1*/ bool, /** 3.1.2*/ bool),
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Three2')].inner.variant_inner[*]" 3
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[0]" $3.2.0
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[1]" null
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[2]" $3.2.2
+    // @count "$.index[*][?(@.name=='Three2')].inner.kind.tuple[*]" 3
+    // @is    "$.index[*][?(@.name=='Three2')].inner.kind.tuple[0]" $3.2.0
+    // @is    "$.index[*][?(@.name=='Three2')].inner.kind.tuple[1]" null
+    // @is    "$.index[*][?(@.name=='Three2')].inner.kind.tuple[2]" $3.2.2
     Three2(/** 3.2.0*/ bool, #[doc(hidden)] bool, /** 3.2.2*/ bool),
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Three3')].inner.variant_inner[*]" 3
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[0]" $3.3.0
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[1]" $3.3.1
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[2]" null
+    // @count "$.index[*][?(@.name=='Three3')].inner.kind.tuple[*]" 3
+    // @is    "$.index[*][?(@.name=='Three3')].inner.kind.tuple[0]" $3.3.0
+    // @is    "$.index[*][?(@.name=='Three3')].inner.kind.tuple[1]" $3.3.1
+    // @is    "$.index[*][?(@.name=='Three3')].inner.kind.tuple[2]" null
     Three3(/** 3.3.0*/ bool, /** 3.3.1*/ bool, #[doc(hidden)] bool),
 }
 
-
 // @is "$.index[*][?(@.docs=='1.1.0')].name" '"0"'
 // @is "$.index[*][?(@.docs=='2.1.0')].name" '"0"'
 // @is "$.index[*][?(@.docs=='2.1.1')].name" '"1"'
index 23b854d8d1721a1c05db3bcd017fe442a757c475..bc870c502a0112b0f801495c15ac061b9ae83870 100644 (file)
@@ -1,11 +1,10 @@
 // @is "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\"
 // @is "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\"
 pub enum EnumStruct {
-    // @is "$.index[*][?(@.name=='VariantS')].inner.variant_kind" \"struct\"
     // @is "$.index[*][?(@.name=='x')].kind" \"struct_field\"
+    // @set x = "$.index[*][?(@.name=='x')].id"
     // @is "$.index[*][?(@.name=='y')].kind" \"struct_field\"
-    VariantS {
-        x: u32,
-        y: String,
-    },
+    // @set y = "$.index[*][?(@.name=='y')].id"
+    // @ismany "$.index[*][?(@.name=='VariantS')].inner.kind.struct.fields[*]" $x $y
+    VariantS { x: u32, y: String },
 }
index b71ec47a804ad961c1da11f06f86a6b71497c6fc..d1207bbfb18da6213394c8f8712c63affd83332a 100644 (file)
@@ -1,8 +1,10 @@
 // @is "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\"
 // @is "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\"
 pub enum EnumTupleStruct {
-    // @is "$.index[*][?(@.name=='VariantA')].inner.variant_kind" \"tuple\"
     // @is "$.index[*][?(@.name=='0')].kind" \"struct_field\"
+    // @set f0 = "$.index[*][?(@.name=='0')].id"
     // @is "$.index[*][?(@.name=='1')].kind" \"struct_field\"
+    // @set f1 = "$.index[*][?(@.name=='1')].id"
+    // @ismany "$.index[*][?(@.name=='VariantA')].inner.kind.tuple[*]" $f0 $f1
     VariantA(u32, String),
 }
diff --git a/src/test/rustdoc-ui/issue-105334.rs b/src/test/rustdoc-ui/issue-105334.rs
new file mode 100644 (file)
index 0000000..ee1adc6
--- /dev/null
@@ -0,0 +1,2 @@
+impl Vec< br##"*.."## > {}
+//~^ ERROR
diff --git a/src/test/rustdoc-ui/issue-105334.stderr b/src/test/rustdoc-ui/issue-105334.stderr
new file mode 100644 (file)
index 0000000..e163bb4
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0747]: constant provided when a type was expected
+  --> $DIR/issue-105334.rs:1:11
+   |
+LL | impl Vec< br##"*.."## > {}
+   |           ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/rustdoc-ui/issue-105737.rs b/src/test/rustdoc-ui/issue-105737.rs
new file mode 100644 (file)
index 0000000..154f069
--- /dev/null
@@ -0,0 +1,4 @@
+impl Vec<lol> {}
+//~^ ERROR
+
+pub fn lol() {}
diff --git a/src/test/rustdoc-ui/issue-105737.stderr b/src/test/rustdoc-ui/issue-105737.stderr
new file mode 100644 (file)
index 0000000..2dd9beb
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0747]: constant provided when a type was expected
+  --> $DIR/issue-105737.rs:1:10
+   |
+LL | impl Vec<lol> {}
+   |          ^^^
+   |
+   = help: `lol` is a function item, not a type
+   = help: function item types cannot be named directly
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/rustdoc-ui/issue-105742.rs b/src/test/rustdoc-ui/issue-105742.rs
new file mode 100644 (file)
index 0000000..cb1de74
--- /dev/null
@@ -0,0 +1,40 @@
+// compile-flags: -Znormalize-docs
+
+use std::ops::Index;
+
+pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+    let _ = s;
+}
+
+pub trait SVec: Index<
+    <Self as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+    Output = <Index<<Self as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+    Output = <Self as SVec>::Item> as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+//~^^^^^ ERROR
+//~^^^^^^ ERROR
+//~^^^^^^^ ERROR
+//~^^^^^^^^ ERROR
+> {
+    type Item<'a, T>;
+
+    fn len(&self) -> <Self as SVec>::Item;
+    //~^ ERROR
+    //~^^ ERROR
+    //~^^^ ERROR
+    //~^^^^ ERROR
+}
diff --git a/src/test/rustdoc-ui/issue-105742.stderr b/src/test/rustdoc-ui/issue-105742.stderr
new file mode 100644 (file)
index 0000000..cc101b7
--- /dev/null
@@ -0,0 +1,385 @@
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     <Self as SVec>::Item<'a>,
+   |                     ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     <Self as SVec>::Item<T>,
+   |                     ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<'a>,
+   |                                     ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<T>,
+   |                                     ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item<'a>> as SVec>::Item,
+   |                              ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item<T>> as SVec>::Item,
+   |                              ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<'a>,
+   |                                              ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<T>,
+   |                                              ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:5:40
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+   |                                        ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item<'_> = T, Output = T>) {
+   |                                        ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:5:40
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+   |                                        ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item<T> = T, Output = T>) {
+   |                                        ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     <Self as SVec>::Item<'a>,
+   |                     ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     <Self as SVec>::Item<T>,
+   |                     ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<'a>,
+   |                                     ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<T>,
+   |                                     ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item<'a>> as SVec>::Item,
+   |                              ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item<T>> as SVec>::Item,
+   |                              ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<'a>,
+   |                                              ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<T>,
+   |                                              ~~~~~~~
+
+error[E0038]: the trait `SVec` cannot be made into an object
+  --> $DIR/issue-105742.rs:5:31
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-105742.rs:12:17
+   |
+LL |    pub trait SVec: Index<
+   |  ____________----__^
+   | |            |
+   | |            this trait cannot be made into an object...
+LL | |      <Self as SVec>::Item,
+LL | |
+LL | |
+...  |
+LL | |/     Output = <Index<<Self as SVec>::Item,
+LL | ||
+LL | ||
+LL | ||
+LL | ||
+LL | ||     Output = <Self as SVec>::Item> as SVec>::Item,
+   | ||_________________________________________________^ ...because it uses `Self` as a type parameter
+...  |
+LL | |
+LL | |  > {
+   | |__^ ...because it uses `Self` as a type parameter
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<'_>;
+   |                                      ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<T>;
+   |                                      ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<'_>;
+   |                                      ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<T>;
+   |                                      ~~~~~~~
+
+error: aborting due to 23 previous errors
+
+Some errors have detailed explanations: E0038, E0107.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/test/rustdoc-ui/issue-106226.rs b/src/test/rustdoc-ui/issue-106226.rs
new file mode 100644 (file)
index 0000000..71b497a
--- /dev/null
@@ -0,0 +1,3 @@
+// This is a regression test for <https://github.com/rust-lang/rust/issues/106226>.
+type F = [_; ()];
+//~^ ERROR
diff --git a/src/test/rustdoc-ui/issue-106226.stderr b/src/test/rustdoc-ui/issue-106226.stderr
new file mode 100644 (file)
index 0000000..2beffbc
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-106226.rs:2:14
+   |
+LL | type F = [_; ()];
+   |              ^^ expected `usize`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/rustdoc-ui/issue-96287.rs b/src/test/rustdoc-ui/issue-96287.rs
new file mode 100644 (file)
index 0000000..8d8b445
--- /dev/null
@@ -0,0 +1,17 @@
+#![feature(type_alias_impl_trait)]
+
+pub trait TraitWithAssoc {
+    type Assoc;
+}
+
+pub type Foo<V> = impl Trait<V::Assoc>;
+//~^ ERROR
+//~^^ ERROR
+
+pub trait Trait<U> {}
+
+impl<W> Trait<W> for () {}
+
+pub fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T> {
+    ()
+}
diff --git a/src/test/rustdoc-ui/issue-96287.stderr b/src/test/rustdoc-ui/issue-96287.stderr
new file mode 100644 (file)
index 0000000..0236b9f
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0220]: associated type `Assoc` not found for `V`
+  --> $DIR/issue-96287.rs:7:33
+   |
+LL | pub type Foo<V> = impl Trait<V::Assoc>;
+   |                                 ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
+
+error[E0220]: associated type `Assoc` not found for `V`
+  --> $DIR/issue-96287.rs:7:33
+   |
+LL | pub type Foo<V> = impl Trait<V::Assoc>;
+   |                                 ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0220`.
index a4b911878e0d6c4866811b697159d0b923212ced..1c376f59e5174a4d82654d5724de868e39e933e9 100644 (file)
@@ -6,6 +6,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::opaque::{MemDecoder, MemEncoder};
 use rustc_serialize::{Decodable, Encodable, Encoder};
index 580c85f9b7848fcaad34d060c827e2c7a5e4cc8e..844d40f2ecd6a4590500b18a1727df21d8dbbca9 100644 (file)
@@ -8,6 +8,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::opaque::{MemDecoder, MemEncoder};
 use rustc_serialize::{Decodable, Encodable, Encoder};
index 921767af981ad6e10062da418868ba91ad99a3c9..214bb4368ffdd808aba26eeb77b533fd77bd339c 100644 (file)
@@ -5,6 +5,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 mod submod {
     use rustc_macros::{Decodable, Encodable};
 
index 8486b8b6e481a3e300696e90f800fd962100a0cc..e1084a08fec93f0baf472ca8bbe16f447cdc528f 100644 (file)
@@ -7,6 +7,11 @@
 
 use rustc_macros::{Decodable, Encodable};
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 pub const other: u8 = 1;
 pub const f: u8 = 1;
 pub const d: u8 = 1;
index 187f9a24a9075fff3ca5db4e7a1270bb38e2bb84..ffad80171da7798645608a04194101cdcb475b90 100644 (file)
 
 extern crate rustc_arena;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_arena::TypedArena;
 
 trait HasId { fn count(&self) -> usize; }
index 6e5eb54629ccde87b9ce5437b39fd819197e2657..10e8beaa7b119d944d9e4a6bad24a2538dd75f5c 100644 (file)
@@ -6,6 +6,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encodable, Decodable)]
index 215dfaed7abbef1b70390efd40c74a97e5abb390..309b5c4a03d57c3b3f0e1e95561720dc60129936 100644 (file)
@@ -7,6 +7,11 @@
 extern crate rustc_macros;
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::opaque::{MemDecoder, MemEncoder};
 use rustc_serialize::{Decodable, Encodable, Encoder};
diff --git a/src/test/ui-fulldeps/missing-rustc-driver-error.rs b/src/test/ui-fulldeps/missing-rustc-driver-error.rs
new file mode 100644 (file)
index 0000000..654cd6f
--- /dev/null
@@ -0,0 +1,11 @@
+// Test that we get the following hint when trying to use a compiler crate without rustc_driver.
+// error-pattern: try adding `extern crate rustc_driver;` at the top level of this crate
+// compile-flags: --emit link
+// The exactly list of required crates depends on the target. as such only test Unix targets.
+// only-unix
+
+#![feature(rustc_private)]
+
+extern crate rustc_serialize;
+
+fn main() {}
diff --git a/src/test/ui-fulldeps/missing-rustc-driver-error.stderr b/src/test/ui-fulldeps/missing-rustc-driver-error.stderr
new file mode 100644 (file)
index 0000000..ad03ba0
--- /dev/null
@@ -0,0 +1,24 @@
+error: crate `rustc_serialize` required to be available in rlib format, but was not found in this form
+   |
+   = help: try adding `extern crate rustc_driver;` at the top level of this crate
+
+error: crate `smallvec` required to be available in rlib format, but was not found in this form
+
+error: crate `thin_vec` required to be available in rlib format, but was not found in this form
+
+error: crate `indexmap` required to be available in rlib format, but was not found in this form
+
+error: crate `hashbrown` required to be available in rlib format, but was not found in this form
+
+error: crate `ahash` required to be available in rlib format, but was not found in this form
+
+error: crate `once_cell` required to be available in rlib format, but was not found in this form
+
+error: crate `getrandom` required to be available in rlib format, but was not found in this form
+
+error: crate `cfg_if` required to be available in rlib format, but was not found in this form
+
+error: crate `libc` required to be available in rlib format, but was not found in this form
+
+error: aborting due to 10 previous errors
+
index bb246de0e572dd4aa65f7a92f33ec63303ce9b19..ff1be0804151b58973c1a41c5616e7a3cc5f73df 100644 (file)
 extern crate rustc_session;
 extern crate rustc_span;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_parse::new_parser_from_file;
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::FilePathMapping;
index a93ba87470a9c045703a8d31a2d39b51884d04a5..6dbabc8eb348512d437c60bbd9aad8113017310e 100644 (file)
 extern crate rustc_span;
 extern crate thin_vec;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_ast::mut_visit::{self, visit_clobber, MutVisitor};
 use rustc_ast::ptr::P;
 use rustc_ast::*;
index 30e62723240681ea2b1d767990a02d4776c2b5a3..63975ef62c591f422762d233682fd092b92a4e81 100644 (file)
 extern crate rustc_arena;
 extern crate libc;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use TypeStructure::{TypeInt, TypeFunction};
 use AstKind::{ExprInt, ExprVar, ExprLambda};
 use rustc_arena::TypedArena;
index 452110a65e4aa18ac966be2213c89c5b4a921696..509a6b1d22ca61769fc0cc714e64b20cd3014db5 100644 (file)
@@ -6,6 +6,11 @@
 #[allow(dead_code)]
 extern crate rustc_serialize;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use rustc_macros::{Decodable, Encodable};
 
 #[derive(Decodable, Encodable, Debug)]
index 0ce1f1d8f7f4ad33ac6926ed5e09576b03027e54..89f2b3bb7d0fe2e9fef3c90d3ec1fe91d205029e 100644 (file)
@@ -25,12 +25,10 @@ fn main() {
 
         // Outputs require mutable places
 
-        let v: Vec<u64> = vec![0, 1, 2];
+        let v: Vec<u64> = vec![0, 1, 2]; //~ ERROR cannot borrow `v` as mutable
         asm!("{}", in(reg) v[0]);
         asm!("{}", out(reg) v[0]);
-        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
         asm!("{}", inout(reg) v[0]);
-        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
 
         // Sym operands must point to a function or static
     }
index eef16a165a87556f187cbdbca517682024a1b87a..41f7c01dc82b1f1878d277ced92289e156d4d6a8 100644 (file)
@@ -25,24 +25,22 @@ LL |         let mut y: u64 = 0;
    |                        +++
 
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
-  --> $DIR/type-check-2-2.rs:30:29
+  --> $DIR/type-check-2-2.rs:28:13
    |
 LL |         let v: Vec<u64> = vec![0, 1, 2];
-   |             - help: consider changing this to be mutable: `mut v`
+   |             ^ not mutable
 LL |         asm!("{}", in(reg) v[0]);
 LL |         asm!("{}", out(reg) v[0]);
-   |                             ^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
-  --> $DIR/type-check-2-2.rs:32:31
-   |
-LL |         let v: Vec<u64> = vec![0, 1, 2];
-   |             - help: consider changing this to be mutable: `mut v`
-...
+   |                             - cannot borrow as mutable
 LL |         asm!("{}", inout(reg) v[0]);
-   |                               ^ cannot borrow as mutable
+   |                               - cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut v: Vec<u64> = vec![0, 1, 2];
+   |             +++
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0381, E0596.
 For more information about an error, try `rustc --explain E0381`.
index 8198df91095f94acd111902c194f58d3cea735f4..1d579ccc90eec1eaaf9eb58209dc79f247c99c80 100644 (file)
@@ -22,11 +22,10 @@ fn main() {
         // Outputs require mutable places
 
         let v: Vec<u64> = vec![0, 1, 2];
+        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
         asm!("{}", in(reg) v[0]);
         asm!("{}", out(reg) v[0]);
-        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
         asm!("{}", inout(reg) v[0]);
-        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
 
         // Sym operands must point to a function or static
 
index bd90461e52c17d750ea85c353e8c0384ae788a88..7970e76d6a1f4e74ae49531248cb057d79af9cae 100644 (file)
@@ -25,24 +25,22 @@ LL |         let mut y: u64 = 0;
    |                        +++
 
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
-  --> $DIR/type-check-5.rs:26:29
+  --> $DIR/type-check-5.rs:24:13
    |
 LL |         let v: Vec<u64> = vec![0, 1, 2];
-   |             - help: consider changing this to be mutable: `mut v`
-LL |         asm!("{}", in(reg) v[0]);
-LL |         asm!("{}", out(reg) v[0]);
-   |                             ^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
-  --> $DIR/type-check-5.rs:28:31
-   |
-LL |         let v: Vec<u64> = vec![0, 1, 2];
-   |             - help: consider changing this to be mutable: `mut v`
+   |             ^ not mutable
 ...
+LL |         asm!("{}", out(reg) v[0]);
+   |                             - cannot borrow as mutable
 LL |         asm!("{}", inout(reg) v[0]);
-   |                               ^ cannot borrow as mutable
+   |                               - cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut v: Vec<u64> = vec![0, 1, 2];
+   |             +++
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0381, E0596.
 For more information about an error, try `rustc --explain E0381`.
index 2d3bb48e03be83ac3a5a042eaf9de06774d0c7c5..bf50443288032c74ada58b0664b71563b1cc570f 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/issue-61452.rs:4:5
    |
-LL | pub async fn f(x: Option<usize>) {
-   |                - help: consider changing this to be mutable: `mut x`
 LL |     x.take();
    |     ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | pub async fn f(mut x: Option<usize>) {
+   |                +++
 
 error[E0384]: cannot assign twice to immutable variable `x`
   --> $DIR/issue-61452.rs:9:5
index 163053471b52daad9ce7b5394f0a693b323ba10e..e58f74546899ba16f109a820b887bc592e8154db 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `data` as mutable, as it is not declared as mutable
   --> $DIR/issue-61187.rs:6:5
    |
-LL | async fn response(data: Vec<u8>) {
-   |                   ---- help: consider changing this to be mutable: `mut data`
 LL |     data.reverse();
    |     ^^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | async fn response(mut data: Vec<u8>) {
+   |                   +++
 
 error: aborting due to previous error
 
index 1b4ac6edcb0d5547ce40b2099cb97c3bb501c55e..20c7fb3a98395bddc9bf07788364b7630dd9d867 100644 (file)
@@ -19,7 +19,7 @@ fn main() {
 
     let y = Int(2);
     //~^ HELP consider changing this to be mutable
-    //~| SUGGESTION mut y
+    //~| SUGGESTION mut
     y   //~ ERROR cannot borrow `y` as mutable, as it is not declared as mutable
         //~| cannot borrow as mutable
     +=
index ce555da8975a7af622eb377ec85f114da441d0b6..2910c910d55241bf4c660f667df359b0ac38289f 100644 (file)
@@ -10,11 +10,13 @@ LL |     x;
 error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
   --> $DIR/augmented-assignments.rs:23:5
    |
-LL |     let y = Int(2);
-   |         - help: consider changing this to be mutable: `mut y`
-...
 LL |     y
    |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut y = Int(2);
+   |         +++
 
 error: aborting due to 2 previous errors
 
index 869375cb2c61be2a0911f28e05e42e2c409b3cd2..a7748209187121bdd6f779b8d9e5644f0eaa0582 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrow-raw-address-of-mutability.rs:5:13
    |
-LL |     let x = 0;
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     let y = &raw mut x;
    |             ^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 0;
+   |         +++
 
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrow-raw-address-of-mutability.rs:11:17
@@ -18,13 +21,16 @@ LL |         let y = &raw mut x;
 error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
   --> $DIR/borrow-raw-address-of-mutability.rs:21:5
    |
-LL |     let f = || {
-   |         - help: consider changing this to be mutable: `mut f`
 LL |         let y = &raw mut x;
    |                          - calling `f` requires mutable binding due to mutable borrow of `x`
 LL |     };
 LL |     f();
    |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut f = || {
+   |         +++
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/borrow-raw-address-of-mutability.rs:29:17
index 312720898473a9717d84ce3e1eedfe39ad786a38..26f3e2bbdb775901eaaed75553e50ca2b2c9c38e 100644 (file)
@@ -1,11 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-access-permissions.rs:9:19
    |
-LL |     let x = 1;
-   |         - help: consider changing this to be mutable: `mut x`
-...
 LL |         let _y1 = &mut x;
    |                   ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 1;
+   |         +++
 
 error[E0596]: cannot borrow immutable static item `static_x` as mutable
   --> $DIR/borrowck-access-permissions.rs:14:19
@@ -16,11 +18,13 @@ LL |         let _y1 = &mut static_x;
 error[E0596]: cannot borrow `*box_x` as mutable, as `box_x` is not declared as mutable
   --> $DIR/borrowck-access-permissions.rs:22:19
    |
-LL |         let box_x = Box::new(1);
-   |             ----- help: consider changing this to be mutable: `mut box_x`
-...
 LL |         let _y1 = &mut *box_x;
    |                   ^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut box_x = Box::new(1);
+   |             +++
 
 error[E0596]: cannot borrow `*ref_x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-access-permissions.rs:30:19
index d4d646e390c31f5269ff87c814641679bb3cdbd6..1c992dfccebfbd95b775536183f5c766c93021a0 100644 (file)
@@ -1,34 +1,46 @@
 error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-argument.rs:10:5
    |
-LL | fn func(arg: S) {
-   |         --- help: consider changing this to be mutable: `mut arg`
 LL |     arg.mutate();
    |     ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn func(mut arg: S) {
+   |         +++
 
 error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-argument.rs:15:9
    |
-LL |     fn method(&self, arg: S) {
-   |                      --- help: consider changing this to be mutable: `mut arg`
 LL |         arg.mutate();
    |         ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     fn method(&self, mut arg: S) {
+   |                      +++
 
 error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-argument.rs:21:9
    |
-LL |     fn default(&self, arg: S) {
-   |                       --- help: consider changing this to be mutable: `mut arg`
 LL |         arg.mutate();
    |         ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     fn default(&self, mut arg: S) {
+   |                       +++
 
 error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-argument.rs:32:17
    |
 LL |     (|arg: S| { arg.mutate() })(s);
-   |       ---       ^^^^^^^^^^^^ cannot borrow as mutable
-   |       |
-   |       help: consider changing this to be mutable: `mut arg`
+   |                 ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     (|mut arg: S| { arg.mutate() })(s);
+   |       +++
 
 error: aborting due to 4 previous errors
 
index 186ecddd6d61df3ff01e052cd5349897980860c9..19ef0301a2d76b3b5b8d560caf6d0ccce2d276d5 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-auto-mut-ref-to-immut-var.rs:15:5
    |
-LL |     let x = Foo { x: 3 };
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     x.printme();
    |     ^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = Foo { x: 3 };
+   |         +++
 
 error: aborting due to previous error
 
index e00d69f89d36eefea364e61d44bf7c330b1469b8..c2351aacdae62a35706b5e52a5e194f82816ed19 100644 (file)
@@ -105,10 +105,13 @@ LL |     *bar1;
 error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable
   --> $DIR/borrowck-borrow-from-owned-ptr.rs:122:16
    |
-LL |     let foo = make_foo();
-   |         --- help: consider changing this to be mutable: `mut foo`
 LL |     let bar1 = &mut foo.bar1;
    |                ^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut foo = make_foo();
+   |         +++
 
 error: aborting due to 11 previous errors
 
index ce5ce56dea27fe85e2962e2f4173a08c485662ac..8fcaaa883b22c6520869d9a7e757a64ac28578ca 100644 (file)
@@ -105,10 +105,13 @@ LL |     *bar1;
 error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable
   --> $DIR/borrowck-borrow-from-stack-variable.rs:120:16
    |
-LL |     let foo = make_foo();
-   |         --- help: consider changing this to be mutable: `mut foo`
 LL |     let bar1 = &mut foo.bar1;
    |                ^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut foo = make_foo();
+   |         +++
 
 error: aborting due to 11 previous errors
 
index 237071e16fc669b0f0e27414cc5ba5ccce10e115..3c28ff56e4196158358496cfc3f7953744f97e28 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `*a` as mutable, as `a` is not declared as mutable
   --> $DIR/borrowck-borrow-immut-deref-of-box-as-mut.rs:12:5
    |
-LL |     let a: Box<_> = Box::new(A);
-   |         - help: consider changing this to be mutable: `mut a`
 LL |     a.foo();
    |     ^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut a: Box<_> = Box::new(A);
+   |         +++
 
 error: aborting due to previous error
 
index 4995029a70f7e2696abf82883acf3c2369d4cdf8..0f320af2657603bf20d82a7ab4f7e300974633ae 100644 (file)
@@ -1,3 +1,5 @@
+#![feature(if_let_guard)]
+
 fn foo(_:String) {}
 
 fn main()
@@ -8,4 +10,11 @@ fn main()
         Some(_) => {}
         None => { foo(my_str); } //~ ERROR [E0382]
     }
+
+    let my_str = "hello".to_owned();
+    match Some(42) {
+        Some(_) if let Some(()) = { drop(my_str); None } => {}
+        Some(_) => {}
+        None => { foo(my_str); } //~ ERROR [E0382]
+    }
 }
index eaf4bb38bc5905532ba39d0081673df2cd6e3107..9fa28efd8554daeeb8344a7a91d0d25b03d88978 100644 (file)
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `my_str`
-  --> $DIR/borrowck-drop-from-guard.rs:9:23
+  --> $DIR/borrowck-drop-from-guard.rs:11:23
    |
 LL |     let my_str = "hello".to_owned();
    |         ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
@@ -15,6 +15,23 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         Some(_) if { drop(my_str.clone()); false } => {}
    |                                 ++++++++
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `my_str`
+  --> $DIR/borrowck-drop-from-guard.rs:18:23
+   |
+LL |     let my_str = "hello".to_owned();
+   |         ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
+LL |     match Some(42) {
+LL |         Some(_) if let Some(()) = { drop(my_str); None } => {}
+   |                                          ------ value moved here
+LL |         Some(_) => {}
+LL |         None => { foo(my_str); }
+   |                       ^^^^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if let Some(()) = { drop(my_str.clone()); None } => {}
+   |                                                ++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
index d58548f22049a683748c72511b0c967e3c39db60..20528e3f0ee089d6fb949b186a0d66b15a1f6002 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-mut-addr-of-imm-var.rs:3:25
    |
-LL |     let x: isize = 3;
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     let y: &mut isize = &mut x;
    |                         ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x: isize = 3;
+   |         +++
 
 error: aborting due to previous error
 
index 8e7ffdc6819a5c679ced357abdb9db3b76d7a76e..8ab472e64c7a929093691ef97102d71092900d89 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-mut-slice-of-imm-vec.rs:7:11
    |
-LL |     let v = vec![1, 2, 3];
-   |         - help: consider changing this to be mutable: `mut v`
 LL |     write(&mut v);
    |           ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut v = vec![1, 2, 3];
+   |         +++
 
 error: aborting due to previous error
 
index 9cbceeb945ccc631f4f6fca7c8afa5d9ca5de926..d80a9e81576f49227034b0a895b192e823691067 100644 (file)
@@ -1,9 +1,11 @@
+#![feature(if_let_guard)]
+
 enum Enum<'a> {
     A(&'a isize),
     B(bool),
 }
 
-fn foo() -> isize {
+fn if_guard() -> isize {
     let mut n = 42;
     let mut x = Enum::A(&mut n);
     match x {
@@ -16,6 +18,17 @@ fn foo() -> isize {
     }
 }
 
-fn main() {
-    foo();
+fn if_let_guard() -> isize {
+    let mut n = 42;
+    let mut x = Enum::A(&mut n);
+    match x {
+        Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
+        //~^ ERROR cannot assign `x` in match guard
+        Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
+        //~^ ERROR cannot mutably borrow `x` in match guard
+        Enum::A(p) => *p,
+        Enum::B(_) => 2,
+    }
 }
+
+fn main() {}
index 6d05e97252d928df4fdb633518281dbc61331833..dbb3272fdc351242b4de455ec9d086c38ea6ac33 100644 (file)
@@ -1,5 +1,5 @@
 error[E0510]: cannot assign `x` in match guard
-  --> $DIR/borrowck-mutate-in-guard.rs:10:25
+  --> $DIR/borrowck-mutate-in-guard.rs:12:25
    |
 LL |     match x {
    |           - value is immutable in match guard
@@ -7,7 +7,7 @@ LL |         Enum::A(_) if { x = Enum::B(false); false } => 1,
    |                         ^^^^^^^^^^^^^^^^^^ cannot assign
 
 error[E0510]: cannot mutably borrow `x` in match guard
-  --> $DIR/borrowck-mutate-in-guard.rs:12:33
+  --> $DIR/borrowck-mutate-in-guard.rs:14:33
    |
 LL |     match x {
    |           - value is immutable in match guard
@@ -15,6 +15,23 @@ LL |     match x {
 LL |         Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
    |                                 ^^^^^^ cannot mutably borrow
 
-error: aborting due to 2 previous errors
+error[E0510]: cannot assign `x` in match guard
+  --> $DIR/borrowck-mutate-in-guard.rs:25:40
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+LL |         Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
+   |                                        ^^^^^^^^^^^^^^^^^^ cannot assign
+
+error[E0510]: cannot mutably borrow `x` in match guard
+  --> $DIR/borrowck-mutate-in-guard.rs:27:48
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+...
+LL |         Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
+   |                                                ^^^^^^ cannot mutably borrow
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0510`.
index ddb63b5ec0fbec2d0a8a39e291fb0f8d0ab7b91f..723b19f4124ac10b6877486bd215d201fa6107bf 100644 (file)
@@ -11,11 +11,13 @@ LL |     use_mut(sp);
 error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-overloaded-call.rs:67:5
    |
-LL |     let s = SFnMut {
-   |         - help: consider changing this to be mutable: `mut s`
-...
 LL |     s(3);
    |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut s = SFnMut {
+   |         +++
 
 error[E0382]: use of moved value: `s`
   --> $DIR/borrowck-overloaded-call.rs:75:5
index e744fc6b54b1a4fccb6f4e48f7a052948ab283b9..5cfd81bd00428e1644e215476b8e76656a204398 100644 (file)
@@ -1,11 +1,13 @@
 error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
   --> $DIR/borrowck-ref-mut-of-imm.rs:4:12
    |
-LL | fn destructure(x: Option<isize>) -> isize {
-   |                - help: consider changing this to be mutable: `mut x`
-...
 LL |       Some(ref mut v) => *v
    |            ^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn destructure(mut x: Option<isize>) -> isize {
+   |                +++
 
 error: aborting due to previous error
 
index d46ef126da481a9c0ecc8606efd727d2349db5f8..3634676463c62f516be4f82a4da52570b14778b4 100644 (file)
@@ -11,10 +11,13 @@ LL |     use_mut(g);
 error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-unboxed-closures.rs:7:5
    |
-LL | fn b<F:FnMut(isize, isize) -> isize>(f: F) {
-   |                                      - help: consider changing this to be mutable: `mut f`
 LL |     f(1, 2);
    |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn b<F:FnMut(isize, isize) -> isize>(mut f: F) {
+   |                                      +++
 
 error[E0382]: use of moved value: `f`
   --> $DIR/borrowck-unboxed-closures.rs:12:5
index 7238dd14433ce888cfba8b7b303acd6cec186471..d5392e7d66fa4cbbe8e27adef49c5799599c4a2f 100644 (file)
@@ -1,18 +1,24 @@
 error[E0594]: cannot assign to `*y`, as `y` is not declared as mutable
   --> $DIR/immut-function-arguments.rs:2:5
    |
-LL | fn f(y: Box<isize>) {
-   |      - help: consider changing this to be mutable: `mut y`
 LL |     *y = 5;
    |     ^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn f(mut y: Box<isize>) {
+   |      +++
 
 error[E0594]: cannot assign to `*q`, as `q` is not declared as mutable
   --> $DIR/immut-function-arguments.rs:6:35
    |
 LL |     let _frob = |q: Box<isize>| { *q = 2; };
-   |                  -                ^^^^^^ cannot assign
-   |                  |
-   |                  help: consider changing this to be mutable: `mut q`
+   |                                   ^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let _frob = |mut q: Box<isize>| { *q = 2; };
+   |                  +++
 
 error: aborting due to 2 previous errors
 
index 07125b98a1f7d10ad744d63da681b0cdd2738a9a..5b824adc6e2737647f4f739fb87ac8e8088baa93 100644 (file)
@@ -1,8 +1,15 @@
+#![feature(if_let_guard)]
+
 fn main() {
     let a = Some("...".to_owned());
     let b = match a {
         Some(_) if { drop(a); false } => None,
         x => x, //~ ERROR use of moved value: `a`
     };
-    println!("{:?}", b);
+
+    let a = Some("...".to_owned());
+    let b = match a {
+        Some(_) if let Some(()) = { drop(a); None } => None,
+        x => x, //~ ERROR use of moved value: `a`
+    };
 }
index ad898fcabd9dbfab6df5fb1b94e7b02585f10aad..18f371c20735a909dbbcbfa2a85baae1ba33b533 100644 (file)
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `a`
-  --> $DIR/issue-31287-drop-in-guard.rs:5:9
+  --> $DIR/issue-31287-drop-in-guard.rs:7:9
    |
 LL |     let a = Some("...".to_owned());
    |         - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
@@ -14,6 +14,22 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         Some(_) if { drop(a.clone()); false } => None,
    |                            ++++++++
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `a`
+  --> $DIR/issue-31287-drop-in-guard.rs:13:9
+   |
+LL |     let a = Some("...".to_owned());
+   |         - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
+LL |     let b = match a {
+LL |         Some(_) if let Some(()) = { drop(a); None } => None,
+   |                                          - value moved here
+LL |         x => x,
+   |         ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if let Some(()) = { drop(a.clone()); None } => None,
+   |                                           ++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
index b7623a54056d809321115d790a204aa8c2aac4ba..774b6cf0ea6d23277ba9824bfe379c00d32b5f72 100644 (file)
@@ -1,11 +1,13 @@
 error[E0594]: cannot assign to `t.0`, as `t` is not declared as mutable
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:13:9
    |
-LL |         let t: Tuple = (S(0), 0);
-   |             - help: consider changing this to be mutable: `mut t`
-LL |         drop(t);
 LL |         t.0 = S(1);
    |         ^^^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut t: Tuple = (S(0), 0);
+   |             +++
 
 error[E0382]: assign to part of moved value: `t`
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:13:9
@@ -20,20 +22,24 @@ LL |         t.0 = S(1);
 error[E0594]: cannot assign to `t.1`, as `t` is not declared as mutable
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:16:9
    |
-LL |         let t: Tuple = (S(0), 0);
-   |             - help: consider changing this to be mutable: `mut t`
-...
 LL |         t.1 = 2;
    |         ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut t: Tuple = (S(0), 0);
+   |             +++
 
 error[E0594]: cannot assign to `u.0`, as `u` is not declared as mutable
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:24:9
    |
-LL |         let u: Tpair = Tpair(S(0), 0);
-   |             - help: consider changing this to be mutable: `mut u`
-LL |         drop(u);
 LL |         u.0 = S(1);
    |         ^^^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut u: Tpair = Tpair(S(0), 0);
+   |             +++
 
 error[E0382]: assign to part of moved value: `u`
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:24:9
@@ -48,20 +54,24 @@ LL |         u.0 = S(1);
 error[E0594]: cannot assign to `u.1`, as `u` is not declared as mutable
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9
    |
-LL |         let u: Tpair = Tpair(S(0), 0);
-   |             - help: consider changing this to be mutable: `mut u`
-...
 LL |         u.1 = 2;
    |         ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut u: Tpair = Tpair(S(0), 0);
+   |             +++
 
 error[E0594]: cannot assign to `v.x`, as `v` is not declared as mutable
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:35:9
    |
-LL |         let v: Spair = Spair { x: S(0), y: 0 };
-   |             - help: consider changing this to be mutable: `mut v`
-LL |         drop(v);
 LL |         v.x = S(1);
    |         ^^^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut v: Spair = Spair { x: S(0), y: 0 };
+   |             +++
 
 error[E0382]: assign to part of moved value: `v`
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:35:9
@@ -76,11 +86,13 @@ LL |         v.x = S(1);
 error[E0594]: cannot assign to `v.y`, as `v` is not declared as mutable
   --> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9
    |
-LL |         let v: Spair = Spair { x: S(0), y: 0 };
-   |             - help: consider changing this to be mutable: `mut v`
-...
 LL |         v.y = 2;
    |         ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |         let mut v: Spair = Spair { x: S(0), y: 0 };
+   |             +++
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/borrowck/many-mutable-borrows.rs b/src/test/ui/borrowck/many-mutable-borrows.rs
new file mode 100644 (file)
index 0000000..3e6ea9d
--- /dev/null
@@ -0,0 +1,18 @@
+fn main() {
+    let v = Vec::new(); //~ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+    v.push(0);
+}
diff --git a/src/test/ui/borrowck/many-mutable-borrows.stderr b/src/test/ui/borrowck/many-mutable-borrows.stderr
new file mode 100644 (file)
index 0000000..aa0cbcf
--- /dev/null
@@ -0,0 +1,33 @@
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+  --> $DIR/many-mutable-borrows.rs:2:9
+   |
+LL |     let v = Vec::new();
+   |         ^ not mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+LL |     v.push(0);
+   |     --------- cannot borrow as mutable
+   |
+   = note: ...and 5 other attempted mutable borrows
+help: consider changing this to be mutable
+   |
+LL |     let mut v = Vec::new();
+   |         +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
index 7cdb16b282d540253dd756071d02611639dc3ef5..477a2aa48d5dcb42e3eab13b0ab0f5562327dab9 100644 (file)
@@ -2,15 +2,14 @@
 #![crate_type = "rlib"]
 
 pub fn f(b: &mut i32) {
-    //~^ NOTE the binding is already a mutable borrow
+    //~^ ERROR cannot borrow
+    //~| NOTE not mutable
     //~| NOTE the binding is already a mutable borrow
     h(&mut b);
-    //~^ ERROR cannot borrow
-    //~| NOTE cannot borrow as mutable
+    //~^ NOTE cannot borrow as mutable
     //~| HELP try removing `&mut` here
     g(&mut &mut b);
-    //~^ ERROR cannot borrow
-    //~| NOTE cannot borrow as mutable
+    //~^ NOTE cannot borrow as mutable
     //~| HELP try removing `&mut` here
 }
 
index 7782047574ce8e7b6b8ba9b6180c280fdf66d8bc..c6f75b1c0d022f5b7fb83d38a382a7fb4e3efc7a 100644 (file)
@@ -1,8 +1,14 @@
 error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
-  --> $DIR/mut-borrow-of-mut-ref.rs:7:7
+  --> $DIR/mut-borrow-of-mut-ref.rs:4:10
    |
+LL | pub fn f(b: &mut i32) {
+   |          ^ not mutable
+...
 LL |     h(&mut b);
-   |       ^^^^^^ cannot borrow as mutable
+   |       ------ cannot borrow as mutable
+...
+LL |     g(&mut &mut b);
+   |            ------ cannot borrow as mutable
    |
 note: the binding is already a mutable borrow
   --> $DIR/mut-borrow-of-mut-ref.rs:4:13
@@ -14,18 +20,6 @@ help: try removing `&mut` here
 LL -     h(&mut b);
 LL +     h(b);
    |
-
-error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
-  --> $DIR/mut-borrow-of-mut-ref.rs:11:12
-   |
-LL |     g(&mut &mut b);
-   |            ^^^^^^ cannot borrow as mutable
-   |
-note: the binding is already a mutable borrow
-  --> $DIR/mut-borrow-of-mut-ref.rs:4:13
-   |
-LL | pub fn f(b: &mut i32) {
-   |             ^^^^^^^^
 help: try removing `&mut` here
    |
 LL -     g(&mut &mut b);
@@ -33,13 +27,13 @@ LL +     g(&mut b);
    |
 
 error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
-  --> $DIR/mut-borrow-of-mut-ref.rs:18:12
+  --> $DIR/mut-borrow-of-mut-ref.rs:17:12
    |
 LL |     h(&mut &mut b);
    |            ^^^^^^ cannot borrow as mutable
    |
 note: the binding is already a mutable borrow
-  --> $DIR/mut-borrow-of-mut-ref.rs:17:13
+  --> $DIR/mut-borrow-of-mut-ref.rs:16:13
    |
 LL | pub fn g(b: &mut i32) {
    |             ^^^^^^^^
@@ -50,7 +44,7 @@ LL +     h(&mut b);
    |
 
 error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
-  --> $DIR/mut-borrow-of-mut-ref.rs:35:5
+  --> $DIR/mut-borrow-of-mut-ref.rs:34:5
    |
 LL |     f.bar();
    |     ^^^^^^^ cannot borrow as mutable
@@ -60,6 +54,6 @@ help: consider making the binding mutable
 LL | pub fn baz(mut f: &mut String) {
    |            +++
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0596`.
index 5be0df1376135b91c11276ff0836b04878894188..82116425f06ca478b24ae570c54fd6287b8402bb 100644 (file)
@@ -50,9 +50,9 @@ fn ref_closure(mut x: (i32,)) {
     });
 }
 
-fn imm_local(x: (i32,)) {
-    &mut x; //~ ERROR
-    &mut x.0; //~ ERROR
+fn imm_local(x: (i32,)) { //~ ERROR
+    &mut x;
+    &mut x.0;
 }
 
 fn imm_capture(x: (i32,)) {
index 7a00ace3bb220331d78982298c826e2fc3f4e100..d7c602718f1736ccf54fa451f4d2aff9e8d0f1e3 100644 (file)
@@ -245,21 +245,19 @@ LL |         &mut x.0;
    |         ^^^^^^^^ cannot borrow as mutable
 
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
-  --> $DIR/mutability-errors.rs:54:5
+  --> $DIR/mutability-errors.rs:53:14
    |
 LL | fn imm_local(x: (i32,)) {
-   |              - help: consider changing this to be mutable: `mut x`
-LL |     &mut x;
-   |     ^^^^^^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
-  --> $DIR/mutability-errors.rs:55:5
-   |
-LL | fn imm_local(x: (i32,)) {
-   |              - help: consider changing this to be mutable: `mut x`
+   |              ^ not mutable
 LL |     &mut x;
+   |     ------ cannot borrow as mutable
 LL |     &mut x.0;
-   |     ^^^^^^^^ cannot borrow as mutable
+   |     -------- cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn imm_local(mut x: (i32,)) {
+   |              +++
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/mutability-errors.rs:60:9
@@ -357,7 +355,7 @@ error[E0596]: cannot borrow `X.0` as mutable, as `X` is an immutable static item
 LL |     &mut X.0;
    |     ^^^^^^^^ cannot borrow as mutable
 
-error: aborting due to 38 previous errors
+error: aborting due to 37 previous errors
 
 Some errors have detailed explanations: E0594, E0596.
 For more information about an error, try `rustc --explain E0594`.
index a3885b5f5caea4593bcaf8df52d32a95cf7dd63d..81e5bc45d4d38bbadc11c530131be0f0888ec90b 100644 (file)
@@ -11,11 +11,13 @@ LL |     x.a = 1;
 error[E0594]: cannot assign to `x.b`, as `x` is not declared as mutable
   --> $DIR/reassignment_immutable_fields_overlapping.rs:13:5
    |
-LL |     let x: Foo;
-   |         - help: consider changing this to be mutable: `mut x`
-LL |     x.a = 1;
 LL |     x.b = 22;
    |     ^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x: Foo;
+   |         +++
 
 error: aborting due to 2 previous errors
 
index 49c81adad49373c788f0e80ad693b131490c3954..ba0457809ad43b591c49f2227ea852dcf2344e6a 100644 (file)
@@ -1,11 +1,13 @@
 error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
   --> $DIR/reassignment_immutable_fields_twice.rs:7:5
    |
-LL |     let x: (u32, u32);
-   |         - help: consider changing this to be mutable: `mut x`
-LL |     x = (22, 44);
 LL |     x.0 = 1;
    |     ^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x: (u32, u32);
+   |         +++
 
 error[E0381]: partially assigned binding `x` isn't fully initialized
   --> $DIR/reassignment_immutable_fields_twice.rs:12:5
index bf9e1febdbba40a55ba062b64b82a824dd8bde40..239f071ca92b3152f60c86e011ce4b22fc74106f 100644 (file)
@@ -1,13 +1,16 @@
 error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
   --> $DIR/issue-80313-mutable-borrow-in-closure.rs:6:5
    |
-LL |     let callback = || {
-   |         -------- help: consider changing this to be mutable: `mut callback`
 LL |         &mut my_var;
    |              ------ calling `callback` requires mutable binding due to mutable borrow of `my_var`
 LL |     };
 LL |     callback();
    |     ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut callback = || {
+   |         +++
 
 error: aborting due to previous error
 
index b67cec6a609f0857eaa8e6a63e0839aa7ba29941..1ec279f03eff5ff24369ea55dd03769424d0b889 100644 (file)
@@ -1,13 +1,16 @@
 error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
   --> $DIR/issue-80313-mutable-borrow-in-move-closure.rs:6:5
    |
-LL |     let callback = move || {
-   |         -------- help: consider changing this to be mutable: `mut callback`
 LL |         &mut my_var;
    |              ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
 LL |     };
 LL |     callback();
    |     ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut callback = move || {
+   |         +++
 
 error: aborting due to previous error
 
index 6e98549f6b84f8cbf1c0252e8c14cb6e5b77bdf1..22a62ce735053f2596b6ea0860e0b8f2a56792ae 100644 (file)
@@ -1,13 +1,16 @@
 error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
   --> $DIR/issue-80313-mutation-in-closure.rs:6:5
    |
-LL |     let callback = || {
-   |         -------- help: consider changing this to be mutable: `mut callback`
 LL |         my_var = true;
    |         ------ calling `callback` requires mutable binding due to mutable borrow of `my_var`
 LL |     };
 LL |     callback();
    |     ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut callback = || {
+   |         +++
 
 error: aborting due to previous error
 
index edd55422a0bd490350d671b9b1b82bcaa31e6614..a2222f8cc9570bd21d1afa21cdcee4f15e926af6 100644 (file)
@@ -1,13 +1,16 @@
 error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
   --> $DIR/issue-80313-mutation-in-move-closure.rs:6:5
    |
-LL |     let callback = move || {
-   |         -------- help: consider changing this to be mutable: `mut callback`
 LL |         my_var = true;
    |         ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
 LL |     };
 LL |     callback();
    |     ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut callback = move || {
+   |         +++
 
 error: aborting due to previous error
 
index 3f564afff58e2df73a1424e327fc0bc8551c7ed2..03b18c3f70c63ae59dfb5b938b2dbcf69d1fed8b 100644 (file)
@@ -2,11 +2,14 @@ error[E0596]: cannot borrow `bar` as mutable, as it is not declared as mutable
   --> $DIR/issue-81700-mut-borrow.rs:3:5
    |
 LL |     let bar = || { foo(x); };
-   |         ---            - calling `bar` requires mutable binding due to mutable borrow of `x`
-   |         |
-   |         help: consider changing this to be mutable: `mut bar`
+   |                        - calling `bar` requires mutable binding due to mutable borrow of `x`
 LL |     bar();
    |     ^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut bar = || { foo(x); };
+   |         +++
 
 error: aborting due to previous error
 
index 802284b265821121fcb6fc5fa6bd7b2dbaf811d7..f0951b7d10873e73ec31645f30ba598707bdacdf 100644 (file)
@@ -1,11 +1,13 @@
 error[E0596]: cannot borrow `c` as mutable, as it is not declared as mutable
   --> $DIR/issue-82438-mut-without-upvar.rs:27:27
    |
-LL |     let c = |a, b, c, d| {};
-   |         - help: consider changing this to be mutable: `mut c`
-LL |
 LL |     A.f(participant_name, &mut c);
    |                           ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut c = |a, b, c, d| {};
+   |         +++
 
 error: aborting due to previous error
 
index c0bfad263f1785723fcf547ab3d1923a51904a90..5335a056cd89f16042846c102149823fdd159453 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
   --> $DIR/issue-84044-drop-non-mut.rs:5:10
    |
-LL |     let f = || {};
-   |         - help: consider changing this to be mutable: `mut f`
 LL |     drop(&mut f);
    |          ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut f = || {};
+   |         +++
 
 error: aborting due to previous error
 
index a60f1c77a586317ce2f1681444daef840cb6e94d..9f8ce3b6183f2c7f2f37e77c9308a6789085d8ff 100644 (file)
@@ -1,11 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/huge_multispan_highlight.rs:90:13
    |
-LL |     let x = "foo";
-   |         - help: consider changing this to be mutable: `mut x`
-...
 LL |     let y = &mut x;
    |             ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = "foo";
+   |         +++
 
 error: aborting due to previous error
 
index 9562d94509ea8f479e44caaf578337b9a78aae1f..1670da55957d073097397d628acc8f0225dea82d 100644 (file)
@@ -1,26 +1,35 @@
 error[E0596]: cannot borrow `f.v` as mutable, as `f` is not declared as mutable
   --> $DIR/issue-35937.rs:7:5
    |
-LL |     let f = Foo { v: Vec::new() };
-   |         - help: consider changing this to be mutable: `mut f`
 LL |     f.v.push("cat".to_string());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut f = Foo { v: Vec::new() };
+   |         +++
 
 error[E0594]: cannot assign to `s.x`, as `s` is not declared as mutable
   --> $DIR/issue-35937.rs:16:5
    |
-LL |     let s = S { x: 42 };
-   |         - help: consider changing this to be mutable: `mut s`
 LL |     s.x += 1;
    |     ^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut s = S { x: 42 };
+   |         +++
 
 error[E0594]: cannot assign to `s.x`, as `s` is not declared as mutable
   --> $DIR/issue-35937.rs:20:5
    |
-LL | fn bar(s: S) {
-   |        - help: consider changing this to be mutable: `mut s`
 LL |     s.x += 1;
    |     ^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL | fn bar(mut s: S) {
+   |        +++
 
 error: aborting due to 3 previous errors
 
index b16309af0418d8a48e4853183a1146944924b9f9..8dc0512a9453dbafd54f2d28c73803ba9abcee84 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable
   --> $DIR/issue-39544.rs:11:13
    |
-LL |     let z = Z { x: X::Y };
-   |         - help: consider changing this to be mutable: `mut z`
 LL |     let _ = &mut z.x;
    |             ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut z = Z { x: X::Y };
+   |         +++
 
 error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:16:17
@@ -97,10 +100,13 @@ LL |     fn foo4(other: &mut Z) {
 error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable
   --> $DIR/issue-39544.rs:41:13
    |
-LL | pub fn with_arg(z: Z, w: &Z) {
-   |                 - help: consider changing this to be mutable: `mut z`
 LL |     let _ = &mut z.x;
    |             ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | pub fn with_arg(mut z: Z, w: &Z) {
+   |                 +++
 
 error[E0596]: cannot borrow `w.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:42:13
index 983d7bf6e7e9cdc7e3d7053534651ca41b95180b..53c2cbeac3269a4958578d8240d86469be19110b 100644 (file)
@@ -4,7 +4,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or
 LL | #![feature(dyn_star)]
    |            ^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
 warning: 1 warning emitted
index 6b6fc55d8053eb71861505f62c24082816a29b02..62e28efab5820f73b90931e1041d45264a839d0a 100644 (file)
@@ -4,7 +4,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or
 LL | #![feature(dyn_star)]
    |            ^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0277]: `AlignedUsize` needs to be a pointer-sized type
index fdf74aa7efe08de048a8cec8aff22e234b9e4e30..cb9c78158146156d3cd37a972c51b046534d21bd 100644 (file)
@@ -4,7 +4,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or
 LL | #![feature(dyn_star)]
    |            ^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
 warning: 1 warning emitted
index 933c133831ad330412c96bead9ea040debbbcabc..bcd014f8dc32d842823d960f24ef9a1e10c57a41 100644 (file)
@@ -4,7 +4,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or
 LL | #![feature(dyn_star)]
    |            ^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
 warning: 1 warning emitted
index 2767e9478e2e8df8df4d0ed7e1ea8d96d0b92853..c3449b6278bac5b4a0b1ea90641dd8c38854c46c 100644 (file)
@@ -4,7 +4,7 @@ error[E0658]: dyn* trait objects are unstable
 LL | pub fn dyn_star_parameter(_: &dyn* Send) {
    |                               ^^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = help: add `#![feature(dyn_star)]` to the crate attributes to enable
 
 error: aborting due to previous error
index 687d7db046478b5d0b551ae3754a712ca704b812..eb9c933055abc190d054fcc52740cd592fbd224e 100644 (file)
@@ -4,7 +4,7 @@ error[E0658]: dyn* trait objects are unstable
 LL |     let dyn_i: dyn* Debug = i as dyn* Debug;
    |                ^^^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = help: add `#![feature(dyn_star)]` to the crate attributes to enable
 
 error[E0658]: dyn* trait objects are unstable
@@ -13,7 +13,7 @@ error[E0658]: dyn* trait objects are unstable
 LL |     let dyn_i: dyn* Debug = i as dyn* Debug;
    |                                  ^^^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = help: add `#![feature(dyn_star)]` to the crate attributes to enable
 
 error[E0606]: casting `usize` as `dyn* Debug` is invalid
index 2fc751b3b4a1efbff854a2355448c7922ac284fc..c7f1a4b9ae11366bc78566a390ae7c24cf1b9475 100644 (file)
@@ -4,7 +4,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or
 LL | #![feature(dyn_star, trait_upcasting)]
    |            ^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0308]: mismatched types
index e000351a68f541d7057fbb4bc49708ef5722b0e2..9c265682904438ed928fe0cb2d2767b7bdf6c872 100644 (file)
@@ -4,7 +4,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or
 LL | #![feature(dyn_star)]
    |            ^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
 warning: 1 warning emitted
index 6a95f7754e68548d8abb417105c7bb88d2e62dbd..74ccd6a1889cd22c7028bb3f260b0f3c412f1bfd 100644 (file)
@@ -4,7 +4,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or
 LL | #![feature(dyn_star, trait_upcasting)]
    |            ^^^^^^^^
    |
-   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0277]: `dyn* Foo` needs to be a pointer-sized type
index 79bc258f1fae7a7605430fbfa344818374166b47..3f9aebcc8aeadca8739d4114b0956d42616beb6f 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/E0596.rs:3:13
    |
-LL |     let x = 1;
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     let y = &mut x;
    |             ^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = 1;
+   |         +++
 
 error: aborting due to previous error
 
index a8a2a47fe46e1f6ed7a478b9f99d3e9d1167dddf..c2619d6df58b31d0007903e5f1cf9ad600454a78 100644 (file)
@@ -170,7 +170,7 @@ LL |     format!("foo %s baz", "bar");
    |                  |
    |                  help: format specifiers use curly braces: `{}`
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: invalid format string: expected `'}'`, found `'t'`
   --> $DIR/ifmt-bad-arg.rs:75:1
index 96277d4d0d9d7861d7fd4885773d1ea8da27db0e..fc99af40859215a8b86ebf8dee42a0b14ff0634a 100644 (file)
@@ -10,5 +10,5 @@ fn main() {
     //~| NOTE: argument never used
     //~| NOTE: argument never used
     //~| NOTE: format specifiers use curly braces, and you have to use a positional or named parameter for the width
-    //~| NOTE: printf formatting not supported
+    //~| NOTE: printf formatting is not supported
 }
index 7b21e0a4fc8965f22278dddfb0ed80eee150c412..ddeb769eadc525ca951ff47ac5d00b5ff6979635 100644 (file)
@@ -12,7 +12,7 @@ note: format specifiers use curly braces, and you have to use a positional or na
    |
 LL |     print!("%0*x", width, num);
    |             ^^^^
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: aborting due to previous error
 
index ce91022f093d4461749b58f3316cc31b18c6949a..399e9ba0df73053982325f68abd8e5e324012092 100644 (file)
@@ -1,5 +1,7 @@
 // test for https://github.com/rust-lang/rust/issues/29723
 
+#![feature(if_let_guard)]
+
 fn main() {
     let s = String::new();
     let _s = match 0 {
@@ -11,4 +13,10 @@ fn main() {
             //~^ ERROR use of moved value: `s`
         }
     };
+
+    let s = String::new();
+    let _s = match 0 {
+        0 if let Some(()) = { drop(s); None } => String::from("oops"),
+        _ => s //~ ERROR use of moved value: `s`
+    };
 }
index 92ee5cf22b719a7fa8a5e573fbbf073443be0f7e..044d8a9b5dd1d6a33b99033963cbf40162b18aed 100644 (file)
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `s`
-  --> $DIR/issue-29723.rs:10:13
+  --> $DIR/issue-29723.rs:12:13
    |
 LL |     let s = String::new();
    |         - move occurs because `s` has type `String`, which does not implement the `Copy` trait
@@ -15,6 +15,22 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         0 if { drop(s.clone()); false } => String::from("oops"),
    |                      ++++++++
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `s`
+  --> $DIR/issue-29723.rs:20:14
+   |
+LL |     let s = String::new();
+   |         - move occurs because `s` has type `String`, which does not implement the `Copy` trait
+LL |     let _s = match 0 {
+LL |         0 if let Some(()) = { drop(s); None } => String::from("oops"),
+   |                                    - value moved here
+LL |         _ => s
+   |              ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         0 if let Some(()) = { drop(s.clone()); None } => String::from("oops"),
+   |                                     ++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
index 3b37578f3c4551497c0a7a523839b32b548da32e..5b753c69d5d10a419e720d44054f263f3e032558 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable
   --> $DIR/issue-36400.rs:5:7
    |
-LL |     let x = Box::new(3);
-   |         - help: consider changing this to be mutable: `mut x`
 LL |     f(&mut *x);
    |       ^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut x = Box::new(3);
+   |         +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-67535.rs b/src/test/ui/issues/issue-67535.rs
new file mode 100644 (file)
index 0000000..24f5062
--- /dev/null
@@ -0,0 +1,22 @@
+fn main() {}
+
+impl std::ops::AddAssign for () {
+    //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
+    fn add_assign(&self, other: ()) -> () {
+        ()
+    }
+}
+
+impl std::ops::AddAssign for [(); 1] {
+    //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
+    fn add_assign(&self, other: [(); 1]) -> [(); 1] {
+        [()]
+    }
+}
+
+impl std::ops::AddAssign for &[u8] {
+    //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
+    fn add_assign(&self, other: &[u8]) -> &[u8] {
+        self
+    }
+}
diff --git a/src/test/ui/issues/issue-67535.stderr b/src/test/ui/issues/issue-67535.stderr
new file mode 100644 (file)
index 0000000..4d7a02a
--- /dev/null
@@ -0,0 +1,39 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/issue-67535.rs:3:1
+   |
+LL | impl std::ops::AddAssign for () {
+   | ^^^^^-------------------^^^^^--
+   | |    |                       |
+   | |    |                       this is not defined in the current crate because tuples are always foreign
+   | |    this is not defined in the current crate because this is a foreign trait
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/issue-67535.rs:10:1
+   |
+LL | impl std::ops::AddAssign for [(); 1] {
+   | ^^^^^-------------------^^^^^-------
+   | |    |                       |
+   | |    |                       this is not defined in the current crate because arrays are always foreign
+   | |    this is not defined in the current crate because this is a foreign trait
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/issue-67535.rs:17:1
+   |
+LL | impl std::ops::AddAssign for &[u8] {
+   | ^^^^^-------------------^^^^^-----
+   | |    |                       |
+   | |    |                       this is not defined in the current crate because slices are always foreign
+   | |    this is not defined in the current crate because this is a foreign trait
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0117`.
index a909c5fa82351ddb2d59dfc4aaf49b5cfc032b8b..cc2447b1877500969643db39e02dd8cec7dae309 100644 (file)
@@ -16,10 +16,13 @@ LL | fn foo<'a>(x:fn(&u8, &u8), y: Vec<&'a u8>, z: &'a u8) {
 error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
   --> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3
    |
-LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
-   |                        - help: consider changing this to be mutable: `mut y`
 LL |   y.push(z);
    |   ^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn foo(x:fn(&u8, &u8), mut y: Vec<&u8>, z: &u8) {
+   |                        +++
 
 error: aborting due to 2 previous errors
 
index d85ea6529f628e08ea4272e961a378d99a8315bb..2ba5afa808d734af4f66474b92e25d291d6f62b3 100644 (file)
@@ -16,10 +16,13 @@ LL | fn foo<'a>(x:Box<dyn Fn(&u8, &u8)> , y: Vec<&'a u8>, z: &'a u8) {
 error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
   --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3
    |
-LL | fn foo(x:Box<dyn Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) {
-   |                                  - help: consider changing this to be mutable: `mut y`
 LL |   y.push(z);
    |   ^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn foo(x:Box<dyn Fn(&u8, &u8)> , mut y: Vec<&u8>, z: &u8) {
+   |                                  +++
 
 error: aborting due to 2 previous errors
 
index ff5236dc949b2f09bf471bc0a195889031ed9257..7971c2ab2b9b285357c957b1bd93d64ee04ce5c8 100644 (file)
@@ -8,7 +8,7 @@ LL |     println!("%.*3$s %s!\n", "Hello,", "World", 4);
    |              |               argument never used
    |              multiple missing formatting specifiers
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 help: format specifiers use curly braces
    |
 LL |     println!("{:.2$} {}!\n", "Hello,", "World", 4);
@@ -22,7 +22,7 @@ LL |     println!("%1$*2$.*3$f", 123.456);
    |               |
    |               help: format specifiers use curly braces: `{0:1$.2$}`
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: multiple unused formatting arguments
   --> $DIR/format-foreign.rs:6:7
@@ -37,7 +37,7 @@ LL | | "###, "Hello,", "World", 4);
    | |____|  argument never used
    |      multiple missing formatting specifiers
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 help: format specifiers use curly braces
    |
 LL ~     println!(r###"{:.2$}
@@ -60,7 +60,7 @@ LL |     println!("Hi there, $NAME.", NAME="Tim");
    |                         |
    |                         help: format specifiers use curly braces: `{NAME}`
    |
-   = note: shell formatting not supported; see the documentation for `std::fmt`
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
 
 error: multiple unused formatting arguments
   --> $DIR/format-foreign.rs:15:32
@@ -72,7 +72,7 @@ LL |     println!("$1 $0 $$ $NAME", 1, 2, NAME=3);
    |              |                 argument never used
    |              multiple missing formatting specifiers
    |
-   = note: shell formatting not supported; see the documentation for `std::fmt`
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
 help: format specifiers use curly braces
    |
 LL |     println!("{1} {0} $$ {NAME}", 1, 2, NAME=3);
index 7423c7b7c8b4736bfcc2860dd92c94b4ffa02b3d..fad87fa2aeea8e4af81c4a66092fdc716811bd34 100644 (file)
@@ -44,7 +44,7 @@ LL |        "things"
 LL |              , UNUSED="args");
    |                       ^^^^^^ named argument never used
    |
-   = note: shell formatting not supported; see the documentation for `std::fmt`
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
 
 error: aborting due to 4 previous errors
 
index d2d66c81198ec71d429632c4ebb0d3e690cf7f86..5359f68cd5517637140140913258401dba6cfed0 100644 (file)
@@ -10,7 +10,7 @@ note: format specifiers use curly braces, and the conversion specifier `
    |
 LL | pub fn main() { println!("🦀%%%", 0) }
    |                               ^^
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: aborting due to previous error
 
index ce3424a8b15f07f8eb09aa870f29cdeb6e19c03a..e57347b362dd4faaea384624031cca90310ad816 100644 (file)
@@ -1,8 +1,6 @@
 error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable
   --> $DIR/span-covering-argument-1.rs:5:14
    |
-LL |             let $s = 0;
-   |                 -- help: consider changing this to be mutable: `mut foo`
 LL |             *&mut $s = 0;
    |              ^^^^^^^ cannot borrow as mutable
 ...
@@ -10,6 +8,10 @@ LL |     bad!(foo whatever);
    |     ------------------ in this macro invocation
    |
    = note: this error originates in the macro `bad` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider changing this to be mutable
+   |
+LL |             let mut $s = 0;
+   |                 +++
 
 error: aborting due to previous error
 
index 3104b20aca4e6428bdb75035eed5e9ef7681934e..8c269d1e727643e96a43a28f115014bfa30a1c00 100644 (file)
@@ -8,7 +8,7 @@ fn mutate(&mut self) {
 
 fn func(arg: S) {
     //~^ HELP consider changing this to be mutable
-    //~| SUGGESTION mut arg
+    //~| SUGGESTION mut
     arg.mutate();
     //~^ ERROR cannot borrow `arg` as mutable, as it is not declared as mutable
 }
@@ -16,7 +16,7 @@ fn func(arg: S) {
 fn main() {
     let local = S;
     //~^ HELP consider changing this to be mutable
-    //~| SUGGESTION mut local
+    //~| SUGGESTION mut
     local.mutate();
     //~^ ERROR cannot borrow `local` as mutable, as it is not declared as mutable
 }
index cba284550b95a3cb818dd5ad8c693a3006c78669..d89c8b41304af7ed3a7d370da726771e46e954d6 100644 (file)
@@ -1,20 +1,24 @@
 error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
   --> $DIR/mut-suggestion.rs:12:5
    |
-LL | fn func(arg: S) {
-   |         --- help: consider changing this to be mutable: `mut arg`
-...
 LL |     arg.mutate();
    |     ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn func(mut arg: S) {
+   |         +++
 
 error[E0596]: cannot borrow `local` as mutable, as it is not declared as mutable
   --> $DIR/mut-suggestion.rs:20:5
    |
-LL |     let local = S;
-   |         ----- help: consider changing this to be mutable: `mut local`
-...
 LL |     local.mutate();
    |     ^^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut local = S;
+   |         +++
 
 error: aborting due to 2 previous errors
 
index 40a0dc9b29c238223d00e8aab5b98582d59eef48..1d731be8a855db5d550d23c0bbab88869abdbbc1 100644 (file)
@@ -1,10 +1,13 @@
 error[E0594]: cannot assign to `nyan.how_hungry`, as `nyan` is not declared as mutable
   --> $DIR/mutable-class-fields.rs:15:3
    |
-LL |   let nyan : Cat = cat(52, 99);
-   |       ---- help: consider changing this to be mutable: `mut nyan`
 LL |   nyan.how_hungry = 0;
    |   ^^^^^^^^^^^^^^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |   let mut nyan : Cat = cat(52, 99);
+   |       +++
 
 error: aborting due to previous error
 
index 7253d35ed2d4fe9e6c04157057e19c3821a0f2a3..ccfc8937fd72e531002dcf3b673628348a917dc7 100644 (file)
@@ -5,6 +5,8 @@
 // See further discussion on rust-lang/rust#24535,
 // rust-lang/rfcs#1006, and rust-lang/rfcs#107
 
+#![feature(if_let_guard)]
+
 fn main() {
     rust_issue_24535();
     rfcs_issue_1006_1();
@@ -23,6 +25,12 @@ fn compare(a: &u8, b: &mut u8) -> bool {
         3 if compare(&a, &mut 3) => (),
         _ => panic!("nope"),
     }
+
+    match a {
+        0 => panic!("nope"),
+        3 if let true = compare(&a, &mut 3) => (),
+        _ => panic!("nope"),
+    }
 }
 
 fn rfcs_issue_1006_1() {
index 4109c10e2e46bf6bb9a17a05ca048b65f4b1c641..85feda5824b408420932a7cd33e64f4d9075db59 100644 (file)
@@ -7,6 +7,8 @@
 // reaches the panic code when executed, despite the compiler warning
 // about that match arm being unreachable.
 
+#![feature(if_let_guard)]
+
 fn main() {
     let b = &mut true;
     match b {
@@ -17,4 +19,16 @@ fn main() {
         &mut true => { println!("You might think we should get here"); },
         _ => panic!("surely we could never get here, since rustc warns it is unreachable."),
     }
+
+    let b = &mut true;
+    match b {
+        //~^ ERROR use of moved value: `b` [E0382]
+        &mut false => {}
+        _ if let Some(()) = {
+            (|| { let bar = b; *bar = false; })();
+            None
+        } => {}
+        &mut true => {}
+        _ => {}
+    }
 }
index 9be1a9279992b813037fe28e38d492df4694d09f..ae7978004576b886be6cdad5b065fe2d5d307f2b 100644 (file)
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `b`
-  --> $DIR/issue-27282-move-match-input-into-guard.rs:12:5
+  --> $DIR/issue-27282-move-match-input-into-guard.rs:14:5
    |
 LL |     let b = &mut true;
    |         - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
@@ -11,6 +11,19 @@ LL |         _ if { (|| { let bar = b; *bar = false; })();
    |                 |
    |                 value moved into closure here
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `b`
+  --> $DIR/issue-27282-move-match-input-into-guard.rs:24:5
+   |
+LL |     let b = &mut true;
+   |         - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
+LL |     match b {
+   |     ^^^^^^^ value used here after move
+...
+LL |             (|| { let bar = b; *bar = false; })();
+   |              --             - variable moved due to use in closure
+   |              |
+   |              value moved into closure here
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
index afa0ba780de46e1826d713ab3c981e8ad244d66b..833ca8afd618e1e88815baa82589a87128bceb0f 100644 (file)
@@ -2,6 +2,8 @@
 // mutable borrows in match guards by hiding the mutable borrow in a
 // guard behind a move (of the ref mut pattern id) within a closure.
 
+#![feature(if_let_guard)]
+
 fn main() {
     match Some(&4) {
         None => {},
@@ -10,4 +12,12 @@ fn main() {
         //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
         Some(s) => std::process::exit(*s),
     }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo
+            if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+        //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+        Some(s) => std::process::exit(*s),
+    }
 }
index a0d32616f83b74f2dad691636171476b1d40cc59..45119018d4e60570243a455dc0129f584db68403 100644 (file)
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `foo` in pattern guard
-  --> $DIR/issue-27282-move-ref-mut-into-guard.rs:9:19
+  --> $DIR/issue-27282-move-ref-mut-into-guard.rs:11:19
    |
 LL |             if { (|| { let bar = foo; bar.take() })(); false } => {},
    |                   ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
@@ -8,6 +8,16 @@ LL |             if { (|| { let bar = foo; bar.take() })(); false } => {},
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+  --> $DIR/issue-27282-move-ref-mut-into-guard.rs:19:34
+   |
+LL |             if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+   |                                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                                  |
+   |                                  move out of `foo` occurs here
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
index 395c7d214d0ce03b356b6b36b59472ab71e49df6..4f41fc23fc34be2632abef60f9734e03a71b39b4 100644 (file)
@@ -1,3 +1,5 @@
+#![feature(if_let_guard)]
+
 fn main() {
     match Some(&4) {
         None => {},
@@ -10,4 +12,15 @@ fn main() {
         Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."),
         _ => println!("Here is some supposedly unreachable code."),
     }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo
+            if let Some(()) = {
+                (|| { let bar = foo; bar.take() })();
+                //~^ ERROR cannot move out of `foo` in pattern guard
+                None
+            } => {},
+        Some(_) => {},
+    }
 }
index c4ce7e62fda82bc24bb45d8b3f90b7afb8f9664b..1ba696593afffe4adafbac72bb0e1055fa4b4d71 100644 (file)
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `foo` in pattern guard
-  --> $DIR/issue-27282-mutation-in-guard.rs:6:18
+  --> $DIR/issue-27282-mutation-in-guard.rs:8:18
    |
 LL |                 (|| { let bar = foo; bar.take() })();
    |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
@@ -8,6 +8,16 @@ LL |                 (|| { let bar = foo; bar.take() })();
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+  --> $DIR/issue-27282-mutation-in-guard.rs:20:18
+   |
+LL |                 (|| { let bar = foo; bar.take() })();
+   |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                  |
+   |                  move out of `foo` occurs here
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
index 82d8b9e9ed977d9b28f558d4b894a4ecd9bba6aa..ac06b2b01028f925fea29944249ebd79cf2a71db 100644 (file)
@@ -3,7 +3,9 @@
 // It reborrows instead of moving the `ref mut` pattern borrow. This
 // means that our conservative check for mutation in guards will
 // reject it. But I want to make sure that we continue to reject it
-// (under NLL) even when that conservaive check goes away.
+// (under NLL) even when that conservative check goes away.
+
+#![feature(if_let_guard)]
 
 fn main() {
     let mut b = &mut true;
@@ -15,4 +17,14 @@ fn main() {
         &mut true => { println!("You might think we should get here"); },
         _ => panic!("surely we could never get here, since rustc warns it is unreachable."),
     }
+
+    let mut b = &mut true;
+    match b {
+        &mut false => {},
+        ref mut r if let Some(()) = { (|| { let bar = &mut *r; **bar = false; })();
+        //~^ ERROR cannot borrow `r` as mutable, as it is immutable for the pattern guard
+                             None } => { &mut *r; },
+        &mut true => {},
+        _ => {},
+    }
 }
index 48433432de1bd7ccccf307f0230a603257778528..5eb7a25bf9f507357225d7cf9677648f6af26105 100644 (file)
@@ -1,5 +1,5 @@
 error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
-  --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:12:25
+  --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:14:25
    |
 LL |         ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
    |                         ^^                  -- mutable borrow occurs due to use of `r` in closure
@@ -8,6 +8,16 @@ LL |         ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
    |
    = note: variables bound in patterns are immutable until the end of the pattern guard
 
-error: aborting due to previous error
+error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
+  --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:24:40
+   |
+LL |         ref mut r if let Some(()) = { (|| { let bar = &mut *r; **bar = false; })();
+   |                                        ^^                  -- mutable borrow occurs due to use of `r` in closure
+   |                                        |
+   |                                        cannot borrow as mutable
+   |
+   = note: variables bound in patterns are immutable until the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0596`.
index 63ca6ae5c284164a641021957fcc03a54d37b309..27b1f8705ff1c163840726f7b110d80e730b0012 100644 (file)
@@ -30,10 +30,13 @@ LL |         (&mut self).bar();
 error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
   --> $DIR/issue-51191.rs:13:9
    |
-LL |     fn imm(self) {
-   |            ---- help: consider changing this to be mutable: `mut self`
 LL |         (&mut self).bar();
    |         ^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     fn imm(mut self) {
+   |            +++
 
 error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
   --> $DIR/issue-51191.rs:22:9
index 252f7f8ba07cff05e8bbc6f3aed6e2779e001640..1afc7931a6b629732476a78077c816040ba2e477 100644 (file)
@@ -1,6 +1,8 @@
 // Test that we have enough false edges to avoid exposing the exact matching
 // algorithm in borrow checking.
 
+#![feature(if_let_guard)]
+
 fn guard_always_precedes_arm(y: i32) {
     let mut x;
     // x should always be initialized, as the only way to reach the arm is
@@ -9,6 +11,12 @@ fn guard_always_precedes_arm(y: i32) {
         0 | 2 if { x = 2; true } => x,
         _ => 2,
     };
+
+    let mut x;
+    match y {
+        0 | 2 if let Some(()) = { x = 2; Some(()) } => x,
+        _ => 2,
+    };
 }
 
 fn guard_may_be_skipped(y: i32) {
@@ -23,6 +31,16 @@ fn guard_may_be_skipped(y: i32) {
         } => 2,
         _ => 3,
     };
+
+    let x;
+    match y {
+        _ if let Some(()) = { x = 2; Some(()) } => 1,
+        _ if let Some(()) = {
+            x; //~ ERROR E0381
+            None
+        } => 2,
+        _ => 3,
+    };
 }
 
 fn guard_may_be_taken(y: bool) {
@@ -37,6 +55,16 @@ fn guard_may_be_taken(y: bool) {
         }
         false => 3,
     };
+
+    let x = String::new();
+    match y {
+        false if let Some(()) = { drop(x); Some(()) } => 1,
+        true => {
+            x; //~ ERROR use of moved value: `x`
+            2
+        }
+        false => 3,
+    };
 }
 
 fn main() {}
index f72ed3af71823de592dba52b3fe33f787507c125..a6261345ceac7bc7fbcd92a666f98d0a506fa2f8 100644 (file)
@@ -1,5 +1,5 @@
 error[E0381]: used binding `x` isn't initialized
-  --> $DIR/match-cfg-fake-edges.rs:21:13
+  --> $DIR/match-cfg-fake-edges.rs:29:13
    |
 LL |     let x;
    |         - binding declared here but left uninitialized
@@ -15,8 +15,25 @@ help: consider assigning a value
 LL |     let x = 0;
    |           +++
 
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/match-cfg-fake-edges.rs:39:13
+   |
+LL |     let x;
+   |         - binding declared here but left uninitialized
+LL |     match y {
+LL |         _ if let Some(()) = { x = 2; Some(()) } => 1,
+   |                               ----- binding initialized here in some conditions
+LL |         _ if let Some(()) = {
+LL |             x;
+   |             ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x = 0;
+   |           +++
+
 error[E0382]: use of moved value: `x`
-  --> $DIR/match-cfg-fake-edges.rs:35:13
+  --> $DIR/match-cfg-fake-edges.rs:53:13
    |
 LL |     let x = String::new();
    |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
@@ -32,7 +49,24 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         false if { drop(x.clone()); true } => 1,
    |                          ++++++++
 
-error: aborting due to 2 previous errors
+error[E0382]: use of moved value: `x`
+  --> $DIR/match-cfg-fake-edges.rs:63:13
+   |
+LL |     let x = String::new();
+   |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+LL |     match y {
+LL |         false if let Some(()) = { drop(x); Some(()) } => 1,
+   |                                        - value moved here
+LL |         true => {
+LL |             x;
+   |             ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         false if let Some(()) = { drop(x.clone()); Some(()) } => 1,
+   |                                         ++++++++
+
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0381, E0382.
 For more information about an error, try `rustc --explain E0381`.
index 87dba187ba2c2ed4ba4f343f3c4df8588306403b..ff63cc092734a0211af6825597610f4bd921c42c 100644 (file)
@@ -1,3 +1,5 @@
+#![feature(if_let_guard)]
+
 // Here is arielb1's basic example from rust-lang/rust#27282
 // that AST borrowck is flummoxed by:
 
@@ -10,6 +12,15 @@ fn should_reject_destructive_mutate_in_guard() {
             false } => { },
         Some(s) => std::process::exit(*s),
     }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo if let Some(()) = {
+            (|| { let bar = foo; bar.take() })();
+            //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+            None } => { },
+        Some(s) => std::process::exit(*s),
+    }
 }
 
 // Here below is a case that needs to keep working: we only use the
@@ -18,7 +29,13 @@ fn should_reject_destructive_mutate_in_guard() {
 fn allow_mutate_in_arm_body() {
     match Some(&4) {
         None => {},
-        ref mut foo if foo.is_some() && false => { foo.take(); () }
+        ref mut foo if foo.is_some() => { foo.take(); () }
+        Some(s) => std::process::exit(*s),
+    }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo if let Some(_) = foo => { foo.take(); () }
         Some(s) => std::process::exit(*s),
     }
 }
@@ -29,7 +46,13 @@ fn allow_mutate_in_arm_body() {
 fn allow_move_into_arm_body() {
     match Some(&4) {
         None => {},
-        mut foo if foo.is_some() && false => { foo.take(); () }
+        mut foo if foo.is_some() => { foo.unwrap(); () }
+        Some(s) => std::process::exit(*s),
+    }
+
+    match Some(&4) {
+        None => {},
+        mut foo if let Some(_) = foo => { foo.unwrap(); () }
         Some(s) => std::process::exit(*s),
     }
 }
index c0fb5f65382dce4eccdd3be95cecabd71085d28b..fa01d3a6fd1e0092a95e40c270c4f7b681626f97 100644 (file)
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `foo` in pattern guard
-  --> $DIR/match-guards-always-borrow.rs:8:14
+  --> $DIR/match-guards-always-borrow.rs:10:14
    |
 LL |             (|| { let bar = foo; bar.take() })();
    |              ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
@@ -8,6 +8,16 @@ LL |             (|| { let bar = foo; bar.take() })();
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+  --> $DIR/match-guards-always-borrow.rs:19:14
+   |
+LL |             (|| { let bar = foo; bar.take() })();
+   |              ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |              |
+   |              move out of `foo` occurs here
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
index 81ae19ebf8a7210106c7403635ce3a5e8d9bfa5c..3a9e1654b1c2d985aa491f467ece89f0629ad422 100644 (file)
@@ -5,7 +5,9 @@
 // Test that we don't allow mutating the value being matched on in a way that
 // changes which patterns it matches, until we have chosen an arm.
 
-fn ok_mutation_in_guard(mut q: i32) {
+#![feature(if_let_guard)]
+
+fn ok_mutation_in_if_guard(mut q: i32) {
     match q {
         // OK, mutation doesn't change which patterns g matches
         _ if { q = 1; false } => (),
@@ -13,7 +15,15 @@ fn ok_mutation_in_guard(mut q: i32) {
     }
 }
 
-fn ok_mutation_in_guard2(mut u: bool) {
+fn ok_mutation_in_if_let_guard(mut q: i32) {
+    match q {
+        // OK, mutation doesn't change which patterns g matches
+        _ if let Some(()) = { q = 1; None } => (),
+        _ => (),
+    }
+}
+
+fn ok_mutation_in_if_guard2(mut u: bool) {
     // OK value of u is unused before modification
     match u {
         _ => (),
@@ -25,7 +35,19 @@ fn ok_mutation_in_guard2(mut u: bool) {
     }
 }
 
-fn ok_mutation_in_guard4(mut w: (&mut bool,)) {
+fn ok_mutation_in_if_let_guard2(mut u: bool) {
+    // OK value of u is unused before modification
+    match u {
+        _ => (),
+        _ if let Some(()) = {
+            u = true;
+            None
+        } => (),
+        x => (),
+    }
+}
+
+fn ok_mutation_in_if_guard4(mut w: (&mut bool,)) {
     // OK value of u is unused before modification
     match w {
         _ => (),
@@ -37,7 +59,19 @@ fn ok_mutation_in_guard4(mut w: (&mut bool,)) {
     }
 }
 
-fn ok_indirect_mutation_in_guard(mut p: &bool) {
+fn ok_mutation_in_if_let_guard4(mut w: (&mut bool,)) {
+    // OK value of u is unused before modification
+    match w {
+        _ => (),
+        _ if let Some(()) = {
+            *w.0 = true;
+            None
+        } => (),
+        x => (),
+    }
+}
+
+fn ok_indirect_mutation_in_if_guard(mut p: &bool) {
     match *p {
         // OK, mutation doesn't change which patterns s matches
         _ if {
@@ -48,7 +82,18 @@ fn ok_indirect_mutation_in_guard(mut p: &bool) {
     }
 }
 
-fn mutation_invalidates_pattern_in_guard(mut q: bool) {
+fn ok_indirect_mutation_in_if_let_guard(mut p: &bool) {
+    match *p {
+        // OK, mutation doesn't change which patterns s matches
+        _ if let Some(()) = {
+            p = &true;
+            None
+        } => (),
+        _ => (),
+    }
+}
+
+fn mutation_invalidates_pattern_in_if_guard(mut q: bool) {
     match q {
         // q doesn't match the pattern with the guard by the end of the guard.
         false if {
@@ -59,7 +104,18 @@ fn mutation_invalidates_pattern_in_guard(mut q: bool) {
     }
 }
 
-fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
+fn mutation_invalidates_pattern_in_if_let_guard(mut q: bool) {
+    match q {
+        // q doesn't match the pattern with the guard by the end of the guard.
+        false if let Some(()) = {
+            q = true; //~ ERROR
+            Some(())
+        } => (),
+        _ => (),
+    }
+}
+
+fn mutation_invalidates_previous_pattern_in_if_guard(mut r: bool) {
     match r {
         // r matches a previous pattern by the end of the guard.
         true => (),
@@ -71,7 +127,19 @@ fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
     }
 }
 
-fn match_on_borrowed_early_end(mut s: bool) {
+fn mutation_invalidates_previous_pattern_in_if_let_guard(mut r: bool) {
+    match r {
+        // r matches a previous pattern by the end of the guard.
+        true => (),
+        _ if let Some(()) = {
+            r = true; //~ ERROR
+            Some(())
+        } => (),
+        _ => (),
+    }
+}
+
+fn match_on_borrowed_early_end_if_guard(mut s: bool) {
     let h = &mut s;
     // OK value of s is unused before modification.
     match s {
@@ -84,7 +152,20 @@ fn match_on_borrowed_early_end(mut s: bool) {
     }
 }
 
-fn bad_mutation_in_guard(mut t: bool) {
+fn match_on_borrowed_early_end_if_let_guard(mut s: bool) {
+    let h = &mut s;
+    // OK value of s is unused before modification.
+    match s {
+        _ if let Some(()) = {
+            *h = !*h;
+            None
+        } => (),
+        true => (),
+        false => (),
+    }
+}
+
+fn bad_mutation_in_if_guard(mut t: bool) {
     match t {
         true => (),
         false if {
@@ -95,7 +176,18 @@ fn bad_mutation_in_guard(mut t: bool) {
     }
 }
 
-fn bad_mutation_in_guard2(mut x: Option<Option<&i32>>) {
+fn bad_mutation_in_if_let_guard(mut t: bool) {
+    match t {
+        true => (),
+        false if let Some(()) = {
+            t = true; //~ ERROR
+            None
+        } => (),
+        false => (),
+    }
+}
+
+fn bad_mutation_in_if_guard2(mut x: Option<Option<&i32>>) {
     // Check that nested patterns are checked.
     match x {
         None => (),
@@ -111,7 +203,23 @@ fn bad_mutation_in_guard2(mut x: Option<Option<&i32>>) {
     }
 }
 
-fn bad_mutation_in_guard3(mut t: bool) {
+fn bad_mutation_in_if_let_guard2(mut x: Option<Option<&i32>>) {
+    // Check that nested patterns are checked.
+    match x {
+        None => (),
+        Some(None) => (),
+        _ if let Some(()) = {
+            match x {
+                Some(ref mut r) => *r = None, //~ ERROR
+                _ => return,
+            };
+            None
+        } => (),
+        Some(Some(r)) => println!("{}", r),
+    }
+}
+
+fn bad_mutation_in_if_guard3(mut t: bool) {
     match t {
         s if {
             t = !t; //~ ERROR
@@ -121,7 +229,17 @@ fn bad_mutation_in_guard3(mut t: bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard(mut y: &bool) {
+fn bad_mutation_in_if_let_guard3(mut t: bool) {
+    match t {
+        s if let Some(()) = {
+            t = !t; //~ ERROR
+            None
+        } => (), // What value should `s` have in the arm?
+        _ => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard(mut y: &bool) {
     match *y {
         true => (),
         false if {
@@ -132,7 +250,18 @@ fn bad_indirect_mutation_in_guard(mut y: &bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard2(mut z: &bool) {
+fn bad_indirect_mutation_in_if_let_guard(mut y: &bool) {
+    match *y {
+        true => (),
+        false if let Some(()) = {
+            y = &true; //~ ERROR
+            None
+        } => (),
+        false => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard2(mut z: &bool) {
     match z {
         &true => (),
         &false if {
@@ -143,8 +272,19 @@ fn bad_indirect_mutation_in_guard2(mut z: &bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard3(mut a: &bool) {
-    // Same as bad_indirect_mutation_in_guard2, but using match ergonomics
+fn bad_indirect_mutation_in_if_let_guard2(mut z: &bool) {
+    match z {
+        &true => (),
+        &false if let Some(()) = {
+            z = &true; //~ ERROR
+            None
+        } => (),
+        &false => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard3(mut a: &bool) {
+    // Same as bad_indirect_mutation_in_if_guard2, but using match ergonomics
     match a {
         true => (),
         false if {
@@ -155,7 +295,19 @@ fn bad_indirect_mutation_in_guard3(mut a: &bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard4(mut b: &bool) {
+fn bad_indirect_mutation_in_if_let_guard3(mut a: &bool) {
+    // Same as bad_indirect_mutation_in_if_guard2, but using match ergonomics
+    match a {
+        true => (),
+        false if let Some(()) = {
+            a = &true; //~ ERROR
+            None
+        } => (),
+        false => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard4(mut b: &bool) {
     match b {
         &_ => (),
         &_ if {
@@ -166,4 +318,15 @@ fn bad_indirect_mutation_in_guard4(mut b: &bool) {
     }
 }
 
+fn bad_indirect_mutation_in_if_let_guard4(mut b: &bool) {
+    match b {
+        &_ => (),
+        &_ if let Some(()) = {
+            b = &true; //~ ERROR
+            None
+        } => (),
+        &b => (),
+    }
+}
+
 fn main() {}
index 48e3a7c6993182bf890740347a800a93b8ff71f3..60b8dee71a8632e2866abc43561c1b0dd36bd25c 100644 (file)
@@ -1,5 +1,5 @@
 error[E0510]: cannot assign `q` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:55:13
+  --> $DIR/match-guards-partially-borrow.rs:100:13
    |
 LL |     match q {
    |           - value is immutable in match guard
@@ -7,8 +7,26 @@ LL |     match q {
 LL |             q = true;
    |             ^^^^^^^^ cannot assign
 
+error[E0510]: cannot assign `q` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:111:13
+   |
+LL |     match q {
+   |           - value is immutable in match guard
+...
+LL |             q = true;
+   |             ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `r` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:123:13
+   |
+LL |     match r {
+   |           - value is immutable in match guard
+...
+LL |             r = true;
+   |             ^^^^^^^^ cannot assign
+
 error[E0510]: cannot assign `r` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:67:13
+  --> $DIR/match-guards-partially-borrow.rs:135:13
    |
 LL |     match r {
    |           - value is immutable in match guard
@@ -17,7 +35,16 @@ LL |             r = true;
    |             ^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `t` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:91:13
+  --> $DIR/match-guards-partially-borrow.rs:172:13
+   |
+LL |     match t {
+   |           - value is immutable in match guard
+...
+LL |             t = true;
+   |             ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `t` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:183:13
    |
 LL |     match t {
    |           - value is immutable in match guard
@@ -26,7 +53,16 @@ LL |             t = true;
    |             ^^^^^^^^ cannot assign
 
 error[E0510]: cannot mutably borrow `x.0` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:105:22
+  --> $DIR/match-guards-partially-borrow.rs:197:22
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+...
+LL |                 Some(ref mut r) => *r = None,
+   |                      ^^^^^^^^^ cannot mutably borrow
+
+error[E0510]: cannot mutably borrow `x.0` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:213:22
    |
 LL |     match x {
    |           - value is immutable in match guard
@@ -35,7 +71,7 @@ LL |                 Some(ref mut r) => *r = None,
    |                      ^^^^^^^^^ cannot mutably borrow
 
 error[E0506]: cannot assign to `t` because it is borrowed
-  --> $DIR/match-guards-partially-borrow.rs:117:13
+  --> $DIR/match-guards-partially-borrow.rs:225:13
    |
 LL |         s if {
    |         - borrow of `t` occurs here
@@ -45,8 +81,28 @@ LL |             false
 LL |         } => (), // What value should `s` have in the arm?
    |         - borrow later used here
 
+error[E0506]: cannot assign to `t` because it is borrowed
+  --> $DIR/match-guards-partially-borrow.rs:235:13
+   |
+LL |         s if let Some(()) = {
+   |         - borrow of `t` occurs here
+LL |             t = !t;
+   |             ^^^^^^ assignment to borrowed `t` occurs here
+LL |             None
+LL |         } => (), // What value should `s` have in the arm?
+   |         - borrow later used here
+
+error[E0510]: cannot assign `y` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:246:13
+   |
+LL |     match *y {
+   |           -- value is immutable in match guard
+...
+LL |             y = &true;
+   |             ^^^^^^^^^ cannot assign
+
 error[E0510]: cannot assign `y` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:128:13
+  --> $DIR/match-guards-partially-borrow.rs:257:13
    |
 LL |     match *y {
    |           -- value is immutable in match guard
@@ -55,7 +111,16 @@ LL |             y = &true;
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `z` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:139:13
+  --> $DIR/match-guards-partially-borrow.rs:268:13
+   |
+LL |     match z {
+   |           - value is immutable in match guard
+...
+LL |             z = &true;
+   |             ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `z` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:279:13
    |
 LL |     match z {
    |           - value is immutable in match guard
@@ -64,7 +129,16 @@ LL |             z = &true;
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `a` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:151:13
+  --> $DIR/match-guards-partially-borrow.rs:291:13
+   |
+LL |     match a {
+   |           - value is immutable in match guard
+...
+LL |             a = &true;
+   |             ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `a` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:303:13
    |
 LL |     match a {
    |           - value is immutable in match guard
@@ -73,7 +147,16 @@ LL |             a = &true;
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `b` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:162:13
+  --> $DIR/match-guards-partially-borrow.rs:314:13
+   |
+LL |     match b {
+   |           - value is immutable in match guard
+...
+LL |             b = &true;
+   |             ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `b` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:325:13
    |
 LL |     match b {
    |           - value is immutable in match guard
@@ -81,7 +164,7 @@ LL |     match b {
 LL |             b = &true;
    |             ^^^^^^^^^ cannot assign
 
-error: aborting due to 9 previous errors
+error: aborting due to 18 previous errors
 
 Some errors have detailed explanations: E0506, E0510.
 For more information about an error, try `rustc --explain E0506`.
index 70beb5d423223888072bf6072c552320a1d5c96b..54118dc367770cc90c2a71bbcbd40c9499045594 100644 (file)
@@ -1,20 +1,24 @@
 error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable
   --> $DIR/nested-binding-modes-mut.rs:4:5
    |
-LL |     let mut is_mut @ not_mut = 42;
-   |                      ------- help: consider changing this to be mutable: `mut not_mut`
-LL |     &mut is_mut;
 LL |     &mut not_mut;
    |     ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut is_mut @ mut not_mut = 42;
+   |                      +++
 
 error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable
   --> $DIR/nested-binding-modes-mut.rs:9:5
    |
-LL |     let not_mut @ mut is_mut = 42;
-   |         ------- help: consider changing this to be mutable: `mut not_mut`
-LL |     &mut is_mut;
 LL |     &mut not_mut;
    |     ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut not_mut @ mut is_mut = 42;
+   |         +++
 
 error: aborting due to 2 previous errors
 
index d1f685f3e7a6da77d23bba0ba9d913d387fd6f70..6f0d2b045918d6007ac206369c6f52724a4151cf 100644 (file)
@@ -1,6 +1,8 @@
+#![feature(if_let_guard)]
+
 enum VecWrapper { A(Vec<i32>) }
 
-fn foo(x: VecWrapper) -> usize {
+fn if_guard(x: VecWrapper) -> usize {
     match x {
         VecWrapper::A(v) if { drop(v); false } => 1,
         //~^ ERROR cannot move out of `v` in pattern guard
@@ -8,6 +10,15 @@ fn foo(x: VecWrapper) -> usize {
     }
 }
 
+fn if_let_guard(x: VecWrapper) -> usize {
+    match x {
+        VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1,
+        //~^ ERROR cannot move out of `v` in pattern guard
+        VecWrapper::A(v) => v.len()
+    }
+}
+
 fn main() {
-    foo(VecWrapper::A(vec![107]));
+    if_guard(VecWrapper::A(vec![107]));
+    if_let_guard(VecWrapper::A(vec![107]));
 }
index 6c3d1caf80715d2ad42ecdde2801183a1b87f877..a749361bf30ee10847d64615248d83dbc8332b6c 100644 (file)
@@ -1,11 +1,19 @@
 error[E0507]: cannot move out of `v` in pattern guard
-  --> $DIR/rfc-reject-double-move-across-arms.rs:5:36
+  --> $DIR/rfc-reject-double-move-across-arms.rs:7:36
    |
 LL |         VecWrapper::A(v) if { drop(v); false } => 1,
    |                                    ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `v` in pattern guard
+  --> $DIR/rfc-reject-double-move-across-arms.rs:15:51
+   |
+LL |         VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1,
+   |                                                   ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
index 571f51c9001202ad99efdfd95832249f635d0dab..827335f6a8494395fbea18f5f8d39c275cf49b78 100644 (file)
@@ -1,6 +1,8 @@
+#![feature(if_let_guard)]
+
 struct A { a: Box<i32> }
 
-fn foo(n: i32) {
+fn if_guard(n: i32) {
     let x = A { a: Box::new(n) };
     let _y = match x {
         A { a: v } if { drop(v); true } => v,
@@ -9,6 +11,16 @@ fn foo(n: i32) {
     };
 }
 
+fn if_let_guard(n: i32) {
+    let x = A { a: Box::new(n) };
+    let _y = match x {
+        A { a: v } if let Some(()) = { drop(v); Some(()) } => v,
+        //~^ ERROR cannot move out of `v` in pattern guard
+        _ => Box::new(0),
+    };
+}
+
 fn main() {
-    foo(107);
+    if_guard(107);
+    if_let_guard(107);
 }
index d1204bc26011f815c82e31ea442ca07a5eb81436..9285492b224503305299266bc8cbac4ca2d692dd 100644 (file)
@@ -1,11 +1,19 @@
 error[E0507]: cannot move out of `v` in pattern guard
-  --> $DIR/rfc-reject-double-move-in-first-arm.rs:6:30
+  --> $DIR/rfc-reject-double-move-in-first-arm.rs:8:30
    |
 LL |         A { a: v } if { drop(v); true } => v,
    |                              ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `v` in pattern guard
+  --> $DIR/rfc-reject-double-move-in-first-arm.rs:17:45
+   |
+LL |         A { a: v } if let Some(()) = { drop(v); Some(()) } => v,
+   |                                             ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
index 20330c92325e4f15516311658ebf2cee121005d9..570328fc211f98b052a9ae7185d053312fb2fbcd 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:53:24
    |
-LL | fn deref_mut_field1(x: Own<Point>) {
-   |                     - help: consider changing this to be mutable: `mut x`
 LL |     let __isize = &mut x.y;
    |                        ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn deref_mut_field1(mut x: Own<Point>) {
+   |                     +++
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:65:10
@@ -30,10 +33,13 @@ LL |     use_mut(_x);
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:88:5
    |
-LL | fn assign_field1<'a>(x: Own<Point>) {
-   |                      - help: consider changing this to be mutable: `mut x`
 LL |     x.y = 3;
    |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn assign_field1<'a>(mut x: Own<Point>) {
+   |                      +++
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:92:5
@@ -59,10 +65,13 @@ LL |     use_mut(_p);
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:109:5
    |
-LL | fn deref_mut_method1(x: Own<Point>) {
-   |                      - help: consider changing this to be mutable: `mut x`
 LL |     x.set(0, 0);
    |     ^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn deref_mut_method1(mut x: Own<Point>) {
+   |                      +++
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:121:5
@@ -78,10 +87,13 @@ LL | fn deref_extend_mut_method1(x: &mut Own<Point>) -> &mut isize {
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:129:6
    |
-LL | fn assign_method1<'a>(x: Own<Point>) {
-   |                       - help: consider changing this to be mutable: `mut x`
 LL |     *x.y_mut() = 3;
    |      ^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn assign_method1<'a>(mut x: Own<Point>) {
+   |                       +++
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:133:6
index 6d34909e43b965d84d37b7cb6c7aaedf1d63c548..3fed7b3f4dcf3afd2da5944de1cc0278429df860 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:29:25
    |
-LL | fn deref_mut1(x: Own<isize>) {
-   |               - help: consider changing this to be mutable: `mut x`
 LL |     let __isize = &mut *x;
    |                         ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn deref_mut1(mut x: Own<isize>) {
+   |               +++
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:41:11
@@ -20,10 +23,13 @@ LL | fn deref_extend_mut1<'a>(x: &'a mut Own<isize>) -> &'a mut isize {
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:49:6
    |
-LL | fn assign1<'a>(x: Own<isize>) {
-   |                - help: consider changing this to be mutable: `mut x`
 LL |     *x = 3;
    |      ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn assign1<'a>(mut x: Own<isize>) {
+   |                +++
 
 error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
   --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:53:6
index e63ca95eff01d6160c78d12ee8cbdfd37ca270a6..b6517e0b3095dc3430306bf7aa3373d544cc234a 100644 (file)
@@ -12,11 +12,13 @@ LL | fn borrowed_receiver(x: &mut dyn Foo) {
 error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable
   --> $DIR/borrowck-object-mutability.rs:18:5
    |
-LL | fn owned_receiver(x: Box<dyn Foo>) {
-   |                   - help: consider changing this to be mutable: `mut x`
-LL |     x.borrowed();
 LL |     x.borrowed_mut();
    |     ^^^^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL | fn owned_receiver(mut x: Box<dyn Foo>) {
+   |                   +++
 
 error: aborting due to 2 previous errors
 
index 7fb90581f8a8fdf43115d1a0b92683e853f24af2..4b6915f77152678f063ffca2141578bf963acfa8 100644 (file)
@@ -32,12 +32,7 @@ Thir {
             kind: Scope {
                 region_scope: Node(2),
                 lint_level: Explicit(
-                    HirId {
-                        owner: OwnerId {
-                            def_id: DefId(0:3 ~ thir_tree[8f1d]::main),
-                        },
-                        local_id: 2,
-                    },
+                    HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2),
                 ),
                 value: e0,
             },
index a0ed56d4bcf7bf20ff20ce696debf0734bb9d5aa..5c93ed6d7f70f471ae74f2b826bc6279745baea6 100644 (file)
@@ -12,13 +12,16 @@ LL |         tick1();
 error[E0596]: cannot borrow `tick2` as mutable, as it is not declared as mutable
   --> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:19:5
    |
-LL |     let tick2 = || {
-   |         ----- help: consider changing this to be mutable: `mut tick2`
 LL |         tick1();
    |         ----- calling `tick2` requires mutable binding due to mutable borrow of `tick1`
 ...
 LL |     tick2();
    |     ^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut tick2 = || {
+   |         +++
 
 error: aborting due to 2 previous errors
 
index 27d23e3fa044bb5f261478c435f44f0971da4639..3f539c42d9b311150db5ba0f4305132cb14853c3 100644 (file)
@@ -2,11 +2,14 @@ error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable
   --> $DIR/unboxed-closures-infer-fnmut-missing-mut.rs:7:5
    |
 LL |     let tick = || counter += 1;
-   |         ----      ------- calling `tick` requires mutable binding due to mutable borrow of `counter`
-   |         |
-   |         help: consider changing this to be mutable: `mut tick`
+   |                   ------- calling `tick` requires mutable binding due to mutable borrow of `counter`
 LL |     tick();
    |     ^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut tick = || counter += 1;
+   |         +++
 
 error: aborting due to previous error
 
index c00f986c397a7240012490b0823521d9a8c82d3e..e3b19297b9c18d086b25f99c19d8de856bfa9986 100644 (file)
@@ -2,11 +2,14 @@ error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable
   --> $DIR/unboxed-closures-infer-fnmut-move-missing-mut.rs:7:5
    |
 LL |     let tick = move || counter += 1;
-   |         ----           ------- calling `tick` requires mutable binding due to possible mutation of `counter`
-   |         |
-   |         help: consider changing this to be mutable: `mut tick`
+   |                        ------- calling `tick` requires mutable binding due to possible mutation of `counter`
 LL |     tick();
    |     ^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut tick = move || counter += 1;
+   |         +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsafe/auxiliary/issue-106126.rs b/src/test/ui/unsafe/auxiliary/issue-106126.rs
new file mode 100644 (file)
index 0000000..091a3ed
--- /dev/null
@@ -0,0 +1,9 @@
+#[macro_export]
+macro_rules! foo {
+    () => {
+        unsafe fn __unsf() {}
+        unsafe fn __foo() {
+            __unsf();
+        }
+    };
+}
diff --git a/src/test/ui/unsafe/issue-106126-good-path-bug.rs b/src/test/ui/unsafe/issue-106126-good-path-bug.rs
new file mode 100644 (file)
index 0000000..93f478e
--- /dev/null
@@ -0,0 +1,12 @@
+// Regression test for #106126.
+// check-pass
+// aux-build:issue-106126.rs
+
+#![deny(unsafe_op_in_unsafe_fn)]
+
+#[macro_use]
+extern crate issue_106126;
+
+foo!();
+
+fn main() {}
index a65765c86c8b72956532f957a56087d128e5eb4f..286267c3834abc3b5e5f3fe7ea61fb23b74ba549 100644 (file)
@@ -1,10 +1,13 @@
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/writing-to-immutable-vec.rs:3:5
    |
-LL |     let v: Vec<isize> = vec![1, 2, 3];
-   |         - help: consider changing this to be mutable: `mut v`
 LL |     v[1] = 4;
    |     ^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut v: Vec<isize> = vec![1, 2, 3];
+   |         +++
 
 error: aborting due to previous error
 
index e15f5fe3ccc968d46d295534015c3831d0ebff85..291d02d67bd626afa78205c86d432c6d41adc6c2 100644 (file)
@@ -5,7 +5,7 @@
     Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs,
     GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, Module, OpaqueTy, Path,
     Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding,
-    TypeBindingKind, Typedef, Union, Variant, WherePredicate,
+    TypeBindingKind, Typedef, Union, Variant, VariantKind, WherePredicate,
 };
 
 use crate::{item_kind::Kind, Error, ErrorKind};
@@ -140,24 +140,24 @@ fn check_enum(&mut self, x: &'a Enum) {
     }
 
     fn check_variant(&mut self, x: &'a Variant, id: &'a Id) {
-        match x {
-            Variant::Plain(discr) => {
-                if let Some(discr) = discr {
-                    if let (Err(_), Err(_)) =
-                        (discr.value.parse::<i128>(), discr.value.parse::<u128>())
-                    {
-                        self.fail(
-                            id,
-                            ErrorKind::Custom(format!(
-                                "Failed to parse discriminant value `{}`",
-                                discr.value
-                            )),
-                        );
-                    }
-                }
+        let Variant { kind, discriminant } = x;
+
+        if let Some(discr) = discriminant {
+            if let (Err(_), Err(_)) = (discr.value.parse::<i128>(), discr.value.parse::<u128>()) {
+                self.fail(
+                    id,
+                    ErrorKind::Custom(format!(
+                        "Failed to parse discriminant value `{}`",
+                        discr.value
+                    )),
+                );
             }
-            Variant::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
-            Variant::Struct { fields, fields_stripped: _ } => {
+        }
+
+        match kind {
+            VariantKind::Plain => {}
+            VariantKind::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
+            VariantKind::Struct { fields, fields_stripped: _ } => {
                 fields.iter().for_each(|f| self.add_field_id(f))
             }
         }
index 97750cb78cdcb9ae19fea8ce13521c081aa3c519..7024927b20561e81f78a432107f579afa683474c 100644 (file)
 extern crate rustc_span;
 extern crate rustc_target;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 mod borrow_tracker;
 mod clock;
 mod concurrency;
index 1d1ef525f23fa38ba259bdd45ea0e0e6e86a8549..0c27bcacfb83ca73c77744e4ff02b6d640f63215 100644 (file)
 extern crate rustc_session;
 extern crate rustc_span;
 
+// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
+// files.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::fmt;
index fff83a1d097b3f6364c180781b8bfdb6ec886dc6..5f5ae3a65efa81c34498c40c6de57fd59ddd81af 100644 (file)
@@ -11,6 +11,7 @@ miropt-test-tools = { path = "../miropt-test-tools" }
 lazy_static = "1"
 walkdir = "2"
 ignore = "0.4.18"
+semver = "1.0.14"
 termcolor = "1.1.3"
 
 [[bin]]
index ce7e7ac5cd4caad70a7754c6b02054352ee3eb06..4075f2616b0fd726739410a0cc1ac9fcffb47f72 100644 (file)
@@ -69,3 +69,4 @@ fn tidy_error(bad: &mut bool, args: impl Display) -> std::io::Result<()> {
 pub mod unit_tests;
 pub mod unstable_book;
 pub mod walk;
+pub mod x_version;
index 6714c63ee62a143a923f84088101cc99ec1142d1..7bb8ddc6949ef9f61254d2a0dcd065a26443ed02 100644 (file)
@@ -58,7 +58,7 @@ macro_rules! check {
 
                 let handle = s.spawn(|| {
                     let mut flag = false;
-                    $p::check($($args),* , &mut flag);
+                    $p::check($($args, )* &mut flag);
                     if (flag) {
                         bad.store(true, Ordering::Relaxed);
                     }
@@ -107,6 +107,8 @@ macro_rules! check {
         check!(alphabetical, &compiler_path);
         check!(alphabetical, &library_path);
 
+        check!(x_version, &root_path, &cargo);
+
         let collected = {
             drain_handles(&mut handles);
 
index f746bdeffd7ca18b5c731506086a87d15645bc1a..070e72437be80d037dac237e4420e509e4146150 100644 (file)
@@ -10,7 +10,7 @@
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
 const ROOT_ENTRY_LIMIT: usize = 939;
-const ISSUES_ENTRY_LIMIT: usize = 2020;
+const ISSUES_ENTRY_LIMIT: usize = 2050;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     for dir in Walk::new(&path.join("test/ui")) {
diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
new file mode 100644 (file)
index 0000000..5dc6a05
--- /dev/null
@@ -0,0 +1,65 @@
+use semver::Version;
+use std::io::ErrorKind;
+use std::path::Path;
+use std::process::{Command, Stdio};
+
+pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
+    let result = Command::new("x").arg("--wrapper-version").stdout(Stdio::piped()).spawn();
+    // This runs the command inside a temporary directory.
+    // This allows us to compare output of result to see if `--wrapper-version` is not a recognized argument to x.
+    let temp_result = Command::new("x")
+        .arg("--wrapper-version")
+        .current_dir(std::env::temp_dir())
+        .stdout(Stdio::piped())
+        .spawn();
+
+    let (child, temp_child) = match (result, temp_result) {
+        (Ok(child), Ok(temp_child)) => (child, temp_child),
+        (Err(e), _) | (_, Err(e)) => match e.kind() {
+            ErrorKind::NotFound => return,
+            _ => return tidy_error!(bad, "failed to run `x`: {}", e),
+        },
+    };
+
+    let output = child.wait_with_output().unwrap();
+    let temp_output = temp_child.wait_with_output().unwrap();
+
+    if output != temp_output {
+        return tidy_error!(
+            bad,
+            "Current version of x does not support the `--wrapper-version` argument\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+        );
+    }
+
+    if output.status.success() {
+        let version = String::from_utf8_lossy(&output.stdout);
+        let version = Version::parse(version.trim_end()).unwrap();
+
+        if let Some(expected) = get_x_wrapper_version(root, cargo) {
+            if version < expected {
+                return tidy_error!(
+                    bad,
+                    "Current version of x is {version}, but the latest version is {expected}\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+                );
+            }
+        } else {
+            return tidy_error!(
+                bad,
+                "Unable to parse the latest version of `x` at `src/tools/x/Cargo.toml`"
+            );
+        }
+    } else {
+        return tidy_error!(bad, "failed to check version of `x`: {}", output.status);
+    }
+}
+
+// Parse latest version out of `x` Cargo.toml
+fn get_x_wrapper_version(root: &Path, cargo: &Path) -> Option<Version> {
+    let mut cmd = cargo_metadata::MetadataCommand::new();
+    cmd.cargo_path(cargo)
+        .manifest_path(root.join("src/tools/x/Cargo.toml"))
+        .no_deps()
+        .features(cargo_metadata::CargoOpt::AllFeatures);
+    let mut metadata = t!(cmd.exec());
+    metadata.packages.pop().map(|x| x.version)
+}
index f07ff43efe987fec445e76d8102f6c2bbdcabd4a..01f7187851e38d646d097b78a19f05c6564cc746 100644 (file)
@@ -52,6 +52,14 @@ fn exec_or_status(command: &mut Command) -> io::Result<ExitStatus> {
 }
 
 fn main() {
+    match env::args().skip(1).next().as_deref() {
+        Some("--wrapper-version") => {
+            let version = env!("CARGO_PKG_VERSION");
+            println!("{}", version);
+            return;
+        }
+        _ => {}
+    }
     let current = match env::current_dir() {
         Ok(dir) => dir,
         Err(err) => {