]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #107777 - compiler-errors:derive_const-actually-derive-const, r=fee1...
authorMatthias Krüger <matthias.krueger@famsik.de>
Wed, 8 Feb 2023 17:32:43 +0000 (18:32 +0100)
committerGitHub <noreply@github.com>
Wed, 8 Feb 2023 17:32:43 +0000 (18:32 +0100)
Make `derive_const` derive properly const-if-const impls

Fixes #107774
Fixes #107666

Also fixes rendering of const-if-const bounds in pretty printing.

r? ```@oli-obk``` or ```@fee1-dead```

151 files changed:
.github/ISSUE_TEMPLATE/ice.yaml
.github/workflows/ci.yml
Cargo.lock
compiler/rustc_abi/src/lib.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
compiler/rustc_const_eval/src/interpret/cast.rs
compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
compiler/rustc_const_eval/src/interpret/machine.rs
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/transform/check_consts/ops.rs
compiler/rustc_data_structures/src/lib.rs
compiler/rustc_data_structures/src/profiling.rs
compiler/rustc_driver_impl/src/lib.rs
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0464.md
compiler/rustc_error_codes/src/error_codes/E0523.md [new file with mode: 0644]
compiler/rustc_errors/src/emitter.rs
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_hir_analysis/src/coherence/builtin.rs
compiler/rustc_hir_typeck/src/coercion.rs
compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
compiler/rustc_infer/src/infer/canonical/query_response.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
compiler/rustc_metadata/src/creader.rs
compiler/rustc_metadata/src/errors.rs
compiler/rustc_metadata/src/locator.rs
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_metadata/src/rmeta/table.rs
compiler/rustc_middle/src/infer/canonical.rs
compiler/rustc_middle/src/mir/interpret/error.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/ty/diagnostics.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/query.rs
compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
compiler/rustc_mir_dataflow/src/move_paths/builder.rs
compiler/rustc_mir_dataflow/src/value_analysis.rs
compiler/rustc_mir_transform/src/copy_prop.rs
compiler/rustc_mir_transform/src/elaborate_drops.rs
compiler/rustc_query_system/src/dep_graph/graph.rs
compiler/rustc_query_system/src/query/plumbing.rs
compiler/rustc_span/src/def_id.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_trait_selection/src/solve/assembly.rs
compiler/rustc_trait_selection/src/solve/project_goals.rs
compiler/rustc_trait_selection/src/solve/trait_goals.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
compiler/rustc_ty_utils/src/abi.rs
compiler/rustc_ty_utils/src/assoc.rs
compiler/rustc_type_ir/src/lib.rs
library/alloc/src/collections/btree/borrow.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/map/entry.rs
library/alloc/src/collections/btree/map/tests.rs
library/alloc/src/collections/btree/navigate.rs
library/alloc/src/collections/btree/node.rs
library/alloc/src/string.rs
library/core/src/marker.rs
library/core/src/sync/atomic.rs
src/bootstrap/setup.rs
src/bootstrap/setup/tests.rs [new file with mode: 0644]
src/bootstrap/test.rs
src/ci/github-actions/ci.yml
src/ci/scripts/should-skip-this.sh
src/doc/rustc/book.toml
src/doc/rustc/src/codegen-options/index.md
src/etc/vscode_settings.json [new file with mode: 0644]
src/librustdoc/html/format.rs
src/librustdoc/html/templates/page.html
src/tools/cargo
src/tools/expand-yaml-anchors/src/main.rs
src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
src/tools/miri/src/intptrcast.rs
src/tools/miri/src/machine.rs
src/tools/miri/src/shims/backtrace.rs
src/tools/miri/src/shims/panic.rs
src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector2.rs [deleted file]
src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector2.stderr [deleted file]
src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs
src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs
src/tools/rust-installer
src/tools/tidy/src/error_codes.rs
src/tools/tidy/src/ui_tests.rs
tests/codegen/function-arguments-noopt.rs
tests/codegen/function-arguments.rs
tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff [new file with mode: 0644]
tests/mir-opt/copy-prop/move_projection.rs [new file with mode: 0644]
tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir
tests/rustdoc/async-fn.rs
tests/rustdoc/const-generics/const-generics-docs.rs
tests/rustdoc/decl-trailing-whitespace.declaration.html
tests/rustdoc/generic-associated-types/gats.rs
tests/rustdoc/inline_cross/impl_trait.rs
tests/rustdoc/issue-34928.rs
tests/rustdoc/reexports-priv.rs
tests/rustdoc/where.SWhere_Simd_item-decl.html
tests/rustdoc/where.SWhere_TraitWhere_item-decl.html
tests/rustdoc/where.rs
tests/rustdoc/whitespace-after-where-clause.enum.html
tests/rustdoc/whitespace-after-where-clause.struct.html
tests/rustdoc/whitespace-after-where-clause.trait.html
tests/rustdoc/whitespace-after-where-clause.union.html
tests/ui/associated-types/hr-associated-type-projection-1.stderr
tests/ui/async-await/future-sizes/async-awaiting-fut.rs [new file with mode: 0644]
tests/ui/async-await/future-sizes/async-awaiting-fut.stdout [new file with mode: 0644]
tests/ui/consts/const-eval/const-eval-query-stack.rs
tests/ui/consts/const-eval/const-eval-query-stack.stderr
tests/ui/dyn-star/align.over_aligned.stderr
tests/ui/dyn-star/align.rs
tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.rs
tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.stderr
tests/ui/dyn-star/check-size-at-cast.rs
tests/ui/dyn-star/check-size-at-cast.stderr
tests/ui/dyn-star/upcast.stderr
tests/ui/error-codes/E0523.rs [new file with mode: 0644]
tests/ui/error-codes/E0523.stderr [new file with mode: 0644]
tests/ui/fmt/respanned-literal-issue-106191.rs
tests/ui/generic-associated-types/issue-68656-unsized-values.stderr
tests/ui/generic-associated-types/missing-bounds.fixed
tests/ui/generic-associated-types/missing-bounds.stderr
tests/ui/impl-trait/issues/issue-86800.stderr
tests/ui/issues/issue-92741.fixed [new file with mode: 0644]
tests/ui/issues/issue-92741.rs [new file with mode: 0644]
tests/ui/issues/issue-92741.stderr [new file with mode: 0644]
tests/ui/layout/valid_range_oob.stderr
tests/ui/mir/issue-107678-projection-with-lifetime.rs [new file with mode: 0644]
tests/ui/mir/issue-107691.rs [new file with mode: 0644]
tests/ui/panics/default-backtrace-ice.stderr
tests/ui/recursion/issue-83150.stderr
tests/ui/suggestions/restrict-existing-type-bounds.rs [new file with mode: 0644]
tests/ui/suggestions/restrict-existing-type-bounds.stderr [new file with mode: 0644]
tests/ui/suggestions/type-mismatch-byte-literal.rs
tests/ui/suggestions/type-mismatch-byte-literal.stderr
tests/ui/traits/new-solver/pointer-like.rs [new file with mode: 0644]
tests/ui/traits/new-solver/pointer-like.stderr [new file with mode: 0644]
tests/ui/traits/new-solver/pointer-sized.rs [deleted file]
tests/ui/traits/new-solver/pointer-sized.stderr [deleted file]
tests/ui/treat-err-as-bug/delay_span_bug.stderr
tests/ui/treat-err-as-bug/err.stderr
tests/ui/typeck/issue-107775.rs [new file with mode: 0644]
tests/ui/typeck/issue-107775.stderr [new file with mode: 0644]

index 8d25bb41c08066fcf5d2d99cc18d9393c2377093..7bec05cc575a875239d1ba10cc269c7827e68ada 100644 (file)
@@ -1,4 +1,4 @@
-name: Internal Compiler Error (Structured form)
+name: Internal Compiler Error (for use by automated tooling)
 description: For now, you'll want to use the other ICE template, as GitHub forms have strict limits on the size of fields so backtraces cannot be pasted directly.
 labels: ["C-bug", "I-ICE", "T-compiler"]
 title: "[ICE]: "
index a992129773e2967f8f411fdf7fb33e58620a467f..b51105750c82cc9aa428298d520959ab20071409 100644 (file)
@@ -60,9 +60,8 @@ jobs:
             env: {}
           - name: x86_64-gnu-tools
             tidy: false
-            env:
-              CI_ONLY_WHEN_SUBMODULES_CHANGED: 1
             os: ubuntu-20.04-xl
+            env: {}
     timeout-minutes: 600
     runs-on: "${{ matrix.os }}"
     steps:
index b2948fb38959e8df8c256f68ade4377609037f7f..ad01ef5e41f162a918ad976df5ec3beb88a80c13 100644 (file)
@@ -127,6 +127,12 @@ version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8f8cb5d814eb646a863c4f24978cff2880c4be96ad8cde2c0f0678732902e271"
 
+[[package]]
+name = "arrayvec"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
+
 [[package]]
 name = "arrayvec"
 version = "0.7.0"
@@ -407,7 +413,7 @@ dependencies = [
  "unicode-xid",
  "url",
  "walkdir",
- "winapi",
+ "windows-sys 0.45.0",
 ]
 
 [[package]]
@@ -436,7 +442,7 @@ name = "cargo-credential-wincred"
 version = "0.2.0"
 dependencies = [
  "cargo-credential",
- "winapi",
+ "windows-sys 0.45.0",
 ]
 
 [[package]]
@@ -496,7 +502,7 @@ dependencies = [
  "time 0.3.17",
  "toml_edit",
  "url",
- "winapi",
+ "windows-sys 0.45.0",
 ]
 
 [[package]]
@@ -516,7 +522,7 @@ dependencies = [
  "shell-escape",
  "tempfile",
  "walkdir",
- "winapi",
+ "windows-sys 0.45.0",
 ]
 
 [[package]]
@@ -791,7 +797,7 @@ dependencies = [
 name = "clippy_utils"
 version = "0.1.69"
 dependencies = [
- "arrayvec",
+ "arrayvec 0.7.0",
  "if_chain",
  "itertools",
  "rustc-semver",
@@ -2217,7 +2223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
 dependencies = [
  "libc",
- "windows-sys",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -2229,7 +2235,7 @@ dependencies = [
  "hermit-abi 0.2.6",
  "io-lifetimes",
  "rustix",
- "windows-sys",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -2670,7 +2676,7 @@ version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123"
 dependencies = [
- "windows-sys",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -2987,7 +2993,7 @@ dependencies = [
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-sys",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -3912,7 +3918,7 @@ dependencies = [
 name = "rustc_data_structures"
 version = "0.0.0"
 dependencies = [
- "arrayvec",
+ "arrayvec 0.7.0",
  "bitflags",
  "cfg-if",
  "ena",
@@ -4169,7 +4175,7 @@ dependencies = [
 name = "rustc_index"
 version = "0.0.0"
 dependencies = [
- "arrayvec",
+ "arrayvec 0.7.0",
  "rustc_macros",
  "rustc_serialize",
  "smallvec",
@@ -4866,7 +4872,7 @@ dependencies = [
 name = "rustdoc"
 version = "0.0.0"
 dependencies = [
- "arrayvec",
+ "arrayvec 0.7.0",
  "askama",
  "expect-test",
  "itertools",
@@ -4969,7 +4975,7 @@ dependencies = [
  "io-lifetimes",
  "libc",
  "linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -5375,9 +5381,9 @@ dependencies = [
 
 [[package]]
 name = "strip-ansi-escapes"
-version = "0.1.0"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d63676e2abafa709460982ddc02a3bb586b6d15a49b75c212e06edd3933acee"
+checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8"
 dependencies = [
  "vte",
 ]
@@ -5499,7 +5505,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
 dependencies = [
  "rustix",
- "windows-sys",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -6089,9 +6095,9 @@ checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7"
 
 [[package]]
 name = "utf8parse"
-version = "0.1.1"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
+checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
 
 [[package]]
 name = "uuid"
@@ -6122,11 +6128,23 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
 [[package]]
 name = "vte"
-version = "0.3.3"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf"
+checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983"
 dependencies = [
+ "arrayvec 0.5.2",
  "utf8parse",
+ "vte_generate_state_changes",
+]
+
+[[package]]
+name = "vte_generate_state_changes"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff"
+dependencies = [
+ "proc-macro2",
+ "quote",
 ]
 
 [[package]]
@@ -6251,47 +6269,71 @@ dependencies = [
  "windows_x86_64_msvc",
 ]
 
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.42.0"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
 
 [[package]]
 name = "writeable"
index 5af6206c0bb80dcabec6169f2ec00aabfd3ca146..0306cb5ce6abd7615d068c093cff045333e2e26b 100644 (file)
@@ -1439,21 +1439,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum PointerKind {
-    /// Most general case, we know no restrictions to tell LLVM.
-    SharedMutable,
-
-    /// `&T` where `T` contains no `UnsafeCell`, is `dereferenceable`, `noalias` and `readonly`.
-    Frozen,
-
-    /// `&mut T` which is `dereferenceable` and `noalias` but not `readonly`.
-    UniqueBorrowed,
-
-    /// `&mut !Unpin`, which is `dereferenceable` but neither `noalias` nor `readonly`.
-    UniqueBorrowedPinned,
-
-    /// `Box<T>`, which is `noalias` (even on return types, unlike the above) but neither `readonly`
-    /// nor `dereferenceable`.
-    UniqueOwned,
+    /// Shared reference. `frozen` indicates the absence of any `UnsafeCell`.
+    SharedRef { frozen: bool },
+    /// Mutable reference. `unpin` indicates the absence of any pinned data.
+    MutableRef { unpin: bool },
+    /// Box. `unpin` indicates the absence of any pinned data.
+    Box { unpin: bool },
 }
 
 /// Note that this information is advisory only, and backends are free to ignore it.
index b0a8188e5e04d92e085ccf1a5a5bbed0a52a87ca..7b07c2a463371d531fa5ee6c3569492cacd2cd49 100644 (file)
@@ -803,6 +803,7 @@ fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: S
                 predicates
                     .iter()
                     .map(|(param, constraint)| (param.name.as_str(), &**constraint, None)),
+                None,
             );
         }
     }
index e15d1b99ad205229e2d7b901e101da1bcc5614b5..1dc6c42fbf78ea3a4b60f27ec9370de3bcad73d2 100644 (file)
@@ -83,16 +83,8 @@ pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<
         }
         self.constraints.member_constraints = tmp;
 
-        for (predicate, constraint_category) in outlives {
-            // At the moment, we never generate any "higher-ranked"
-            // region constraints like `for<'a> 'a: 'b`. At some point
-            // when we move to universes, we will, and this assertion
-            // will start to fail.
-            let predicate = predicate.no_bound_vars().unwrap_or_else(|| {
-                bug!("query_constraint {:?} contained bound vars", predicate,);
-            });
-
-            self.convert(predicate, *constraint_category);
+        for &(predicate, constraint_category) in outlives {
+            self.convert(predicate, constraint_category);
         }
     }
 
index b2c847d3fd8dd6fca2403ecd5d9216ae4c5e63f4..fc8e0c67ae09a0ec4b8d22aa8c9d5c9608a27854 100644 (file)
@@ -126,7 +126,7 @@ pub fn cast(
                     let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?;
                     let vtable = Scalar::from_maybe_pointer(vtable, self);
                     let data = self.read_immediate(src)?.to_scalar();
-                    let _assert_pointer_sized = data.to_pointer(self)?;
+                    let _assert_pointer_like = data.to_pointer(self)?;
                     let val = Immediate::ScalarPair(data, vtable);
                     self.write_immediate(val, dest)?;
                 } else {
index 77c7b4bacb8c8a96d68b42704478166e754d0772..5042c6bac9932dcfd4821aa3e273c14fab373b7d 100644 (file)
@@ -78,13 +78,16 @@ pub(crate) fn alloc_caller_location(
         col: u32,
     ) -> MPlaceTy<'tcx, M::Provenance> {
         let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail;
+        // This can fail if rustc runs out of memory right here. Trying to emit an error would be
+        // pointless, since that would require allocating more memory than these short strings.
         let file = if loc_details.file {
             self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
+                .unwrap()
         } else {
             // FIXME: This creates a new allocation each time. It might be preferable to
             // perform this allocation only once, and re-use the `MPlaceTy`.
             // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
-            self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not)
+            self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not).unwrap()
         };
         let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
         let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
@@ -95,8 +98,6 @@ pub(crate) fn alloc_caller_location(
             .bound_type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None))
             .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter()));
         let loc_layout = self.layout_of(loc_ty).unwrap();
-        // This can fail if rustc runs out of memory right here. Trying to emit an error would be
-        // pointless, since that would require allocating more memory than a Location.
         let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
 
         // Initialize fields.
index 76ed7b80f8d81b7a69c553a2597450cd5710572a..d8087a36a7c6abfb48240319148c8e68e2bf3917 100644 (file)
@@ -291,7 +291,7 @@ fn extern_static_base_pointer(
     fn adjust_alloc_base_pointer(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         ptr: Pointer,
-    ) -> Pointer<Self::Provenance>;
+    ) -> InterpResult<'tcx, Pointer<Self::Provenance>>;
 
     /// "Int-to-pointer cast"
     fn ptr_from_addr_cast(
@@ -505,8 +505,8 @@ fn extern_static_base_pointer(
     fn adjust_alloc_base_pointer(
         _ecx: &InterpCx<$mir, $tcx, Self>,
         ptr: Pointer<AllocId>,
-    ) -> Pointer<AllocId> {
-        ptr
+    ) -> InterpResult<$tcx, Pointer<AllocId>> {
+        Ok(ptr)
     }
 
     #[inline(always)]
index a87ce0053e8a038932d7f71b711ce741094de771..cfad930b1e52ec6ca1174e7700b5e3135fbcdf80 100644 (file)
@@ -171,7 +171,7 @@ pub fn global_base_pointer(
             _ => {}
         }
         // And we need to get the provenance.
-        Ok(M::adjust_alloc_base_pointer(self, ptr))
+        M::adjust_alloc_base_pointer(self, ptr)
     }
 
     pub fn create_fn_alloc_ptr(
@@ -200,8 +200,7 @@ pub fn allocate_ptr(
         kind: MemoryKind<M::MemoryKind>,
     ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
         let alloc = Allocation::uninit(size, align, M::PANIC_ON_ALLOC_FAIL)?;
-        // We can `unwrap` since `alloc` contains no pointers.
-        Ok(self.allocate_raw_ptr(alloc, kind).unwrap())
+        self.allocate_raw_ptr(alloc, kind)
     }
 
     pub fn allocate_bytes_ptr(
@@ -210,10 +209,9 @@ pub fn allocate_bytes_ptr(
         align: Align,
         kind: MemoryKind<M::MemoryKind>,
         mutability: Mutability,
-    ) -> Pointer<M::Provenance> {
+    ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
         let alloc = Allocation::from_bytes(bytes, align, mutability);
-        // We can `unwrap` since `alloc` contains no pointers.
-        self.allocate_raw_ptr(alloc, kind).unwrap()
+        self.allocate_raw_ptr(alloc, kind)
     }
 
     /// This can fail only of `alloc` contains provenance.
@@ -230,7 +228,7 @@ pub fn allocate_raw_ptr(
         );
         let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?;
         self.memory.alloc_map.insert(id, (kind, alloc.into_owned()));
-        Ok(M::adjust_alloc_base_pointer(self, Pointer::from(id)))
+        M::adjust_alloc_base_pointer(self, Pointer::from(id))
     }
 
     pub fn reallocate_ptr(
index f82a41078d153a4485c9585ef1b85257568e3c63..038282e2161e6637891d2cde59fe2e766e40b189 100644 (file)
@@ -754,8 +754,8 @@ pub fn allocate_str(
         str: &str,
         kind: MemoryKind<M::MemoryKind>,
         mutbl: Mutability,
-    ) -> MPlaceTy<'tcx, M::Provenance> {
-        let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl);
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
+        let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?;
         let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self);
         let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) };
 
@@ -764,7 +764,7 @@ pub fn allocate_str(
             ty::TypeAndMut { ty: self.tcx.types.str_, mutbl },
         );
         let layout = self.layout_of(ty).unwrap();
-        MPlaceTy { mplace, layout, align: layout.align.abi }
+        Ok(MPlaceTy { mplace, layout, align: layout.align.abi })
     }
 
     /// Writes the aggregate to the destination.
index 782a62accad9e984479cc4c1bd98d351dd6cb75b..3e416b89ca6ea5a417821cc3468ef09eb4155b57 100644 (file)
@@ -136,6 +136,7 @@ fn build_error(
                             &param_ty.name.as_str(),
                             &constraint,
                             None,
+                            None,
                         );
                     }
                 }
index 954e84c303b83d031cc4b2be76c56b4e90e1cea1..7fab8954cb19f1911ff8654061770315bbf0e0a7 100644 (file)
@@ -11,6 +11,7 @@
 #![feature(associated_type_bounds)]
 #![feature(auto_traits)]
 #![feature(cell_leak)]
+#![feature(core_intrinsics)]
 #![feature(extend_one)]
 #![feature(hash_raw_entry)]
 #![feature(hasher_prefixfree_extras)]
index 393f173908128457c7f70f01c8eddbbc8240c7cf..3aca03f6e5c63cbae99bda4e58c09b05cddcf065 100644 (file)
@@ -88,6 +88,7 @@
 use std::collections::hash_map::Entry;
 use std::error::Error;
 use std::fs;
+use std::intrinsics::unlikely;
 use std::path::Path;
 use std::process;
 use std::sync::Arc;
@@ -395,11 +396,18 @@ pub fn query_provider(&self) -> TimingGuard<'_> {
     /// Record a query in-memory cache hit.
     #[inline(always)]
     pub fn query_cache_hit(&self, query_invocation_id: QueryInvocationId) {
-        self.instant_query_event(
-            |profiler| profiler.query_cache_hit_event_kind,
-            query_invocation_id,
-            EventFilter::QUERY_CACHE_HITS,
-        );
+        #[inline(never)]
+        #[cold]
+        fn cold_call(profiler_ref: &SelfProfilerRef, query_invocation_id: QueryInvocationId) {
+            profiler_ref.instant_query_event(
+                |profiler| profiler.query_cache_hit_event_kind,
+                query_invocation_id,
+            );
+        }
+
+        if unlikely(self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS)) {
+            cold_call(self, query_invocation_id);
+        }
     }
 
     /// Start profiling a query being blocked on a concurrent execution.
@@ -444,20 +452,15 @@ fn instant_query_event(
         &self,
         event_kind: fn(&SelfProfiler) -> StringId,
         query_invocation_id: QueryInvocationId,
-        event_filter: EventFilter,
     ) {
-        drop(self.exec(event_filter, |profiler| {
-            let event_id = StringId::new_virtual(query_invocation_id.0);
-            let thread_id = get_thread_id();
-
-            profiler.profiler.record_instant_event(
-                event_kind(profiler),
-                EventId::from_virtual(event_id),
-                thread_id,
-            );
-
-            TimingGuard::none()
-        }));
+        let event_id = StringId::new_virtual(query_invocation_id.0);
+        let thread_id = get_thread_id();
+        let profiler = self.profiler.as_ref().unwrap();
+        profiler.profiler.record_instant_event(
+            event_kind(profiler),
+            EventId::from_virtual(event_id),
+            thread_id,
+        );
     }
 
     pub fn with_profiler(&self, f: impl FnOnce(&SelfProfiler)) {
index 02e0b042ad2631eadad94771b4a2dfab2c2defd4..a392d70f100a4826ddc9e6227c7c20bcabbdbccc 100644 (file)
@@ -326,14 +326,16 @@ fn run_compiler(
                 }
             }
 
-            let mut gctxt = queries.global_ctxt()?;
+            // Make sure name resolution and macro expansion is run.
+            queries.global_ctxt()?;
+
             if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
 
             // Make sure the `output_filenames` query is run for its side
             // effects of writing the dep-info and reporting errors.
-            gctxt.enter(|tcx| tcx.output_filenames(()));
+            queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(()));
 
             if sess.opts.output_types.contains_key(&OutputType::DepInfo)
                 && sess.opts.output_types.len() == 1
@@ -345,7 +347,7 @@ fn run_compiler(
                 return early_exit();
             }
 
-            gctxt.enter(|tcx| {
+            queries.global_ctxt()?.enter(|tcx| {
                 let result = tcx.analysis(());
                 if sess.opts.unstable_opts.save_analysis {
                     let crate_name = tcx.crate_name(LOCAL_CRATE);
@@ -362,8 +364,6 @@ fn run_compiler(
                 result
             })?;
 
-            drop(gctxt);
-
             if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
@@ -1200,11 +1200,9 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
     if !info.payload().is::<rustc_errors::ExplicitBug>()
         && !info.payload().is::<rustc_errors::DelayedBugPanic>()
     {
-        let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
-        handler.emit_diagnostic(&mut d);
+        handler.emit_err(session_diagnostics::Ice);
     }
 
-    handler.emit_note(session_diagnostics::Ice);
     handler.emit_note(session_diagnostics::IceBugReport { bug_report_url });
     handler.emit_note(session_diagnostics::IceVersion {
         version: util::version_str!().unwrap_or("unknown_version"),
index 072b0f2fcceab7e4e357b10fe6f61f85358a66e0..800f3c521778d756f86b6c5e08f00dc76b2f1ada 100644 (file)
 E0520: include_str!("./error_codes/E0520.md"),
 E0521: include_str!("./error_codes/E0521.md"),
 E0522: include_str!("./error_codes/E0522.md"),
+E0523: include_str!("./error_codes/E0523.md"),
 E0524: include_str!("./error_codes/E0524.md"),
 E0525: include_str!("./error_codes/E0525.md"),
 E0527: include_str!("./error_codes/E0527.md"),
 //  E0488, // lifetime of variable does not enclose its declaration
 //  E0489, // type/lifetime parameter not in scope here
 //  E0490, // removed: unreachable
-    E0523, // two dependencies have same (crate-name, disambiguator) but different SVH
 //  E0526, // shuffle indices are not constant
 //  E0540, // multiple rustc_deprecated attributes
 //  E0548, // replaced with a generic attribute input check
index 9108d856c9d7724f557b243130917c9bcca19cc5..209cbb00db562f3daa36e38d79b58e70c938828f 100644 (file)
@@ -1,6 +1,21 @@
 The compiler found multiple library files with the requested crate name.
 
+```compile_fail
+// aux-build:crateresolve-1.rs
+// aux-build:crateresolve-2.rs
+// aux-build:crateresolve-3.rs
+
+extern crate crateresolve;
+//~^ ERROR multiple candidates for `rlib` dependency `crateresolve` found
+
+fn main() {}
+```
+
 This error can occur in several different cases -- for example, when using
 `extern crate` or passing `--extern` options without crate paths. It can also be
 caused by caching issues with the build directory, in which case `cargo clean`
 may help.
+
+In the above example, there are three different library files, all of which
+define the same crate name. Without providing a full path, there is no way for
+the compiler to know which crate it should use.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0523.md b/compiler/rustc_error_codes/src/error_codes/E0523.md
new file mode 100644 (file)
index 0000000..0ddf703
--- /dev/null
@@ -0,0 +1,25 @@
+#### Note: this error code is no longer emitted by the compiler.
+
+The compiler found multiple library files with the requested crate name.
+
+```compile_fail
+// aux-build:crateresolve-1.rs
+// aux-build:crateresolve-2.rs
+// aux-build:crateresolve-3.rs
+
+extern crate crateresolve;
+//~^ ERROR multiple candidates for `rlib` dependency `crateresolve` found
+
+fn main() {}
+```
+
+This error can occur in several different cases -- for example, when using
+`extern crate` or passing `--extern` options without crate paths. It can also be
+caused by caching issues with the build directory, in which case `cargo clean`
+may help.
+
+In the above example, there are three different library files, all of which
+define the same crate name. Without providing a full path, there is no way for
+the compiler to know which crate it should use.
+
+*Note that E0523 has been merged into E0464.*
index faeaa548619708f5c2c0621f27ac25073b68b715..9768526a2f47d52088fc500e6643b7efad8eca8e 100644 (file)
@@ -1882,9 +1882,8 @@ fn emit_suggestion_default(
                             &mut buffer,
                             &mut row_num,
                             &Vec::new(),
-                            p,
+                            p + line_start,
                             l,
-                            line_start,
                             show_code_change,
                             max_line_num_len,
                             &file_lines,
@@ -1907,9 +1906,8 @@ fn emit_suggestion_default(
                                 &mut buffer,
                                 &mut row_num,
                                 &Vec::new(),
-                                p,
+                                p + line_start,
                                 l,
-                                line_start,
                                 show_code_change,
                                 max_line_num_len,
                                 &file_lines,
@@ -1925,9 +1923,8 @@ fn emit_suggestion_default(
                                 &mut buffer,
                                 &mut row_num,
                                 &Vec::new(),
-                                p,
+                                p + line_start,
                                 l,
-                                line_start,
                                 show_code_change,
                                 max_line_num_len,
                                 &file_lines,
@@ -1941,9 +1938,8 @@ fn emit_suggestion_default(
                     &mut buffer,
                     &mut row_num,
                     highlight_parts,
-                    line_pos,
+                    line_pos + line_start,
                     line,
-                    line_start,
                     show_code_change,
                     max_line_num_len,
                     &file_lines,
@@ -2167,40 +2163,63 @@ fn draw_code_line(
         buffer: &mut StyledBuffer,
         row_num: &mut usize,
         highlight_parts: &Vec<SubstitutionHighlight>,
-        line_pos: usize,
-        line: &str,
-        line_start: usize,
+        line_num: usize,
+        line_to_add: &str,
         show_code_change: DisplaySuggestion,
         max_line_num_len: usize,
         file_lines: &FileLines,
         is_multiline: bool,
     ) {
-        // Print the span column to avoid confusion
-        buffer.puts(*row_num, 0, &self.maybe_anonymized(line_start + line_pos), Style::LineNumber);
         if let DisplaySuggestion::Diff = show_code_change {
-            // Add the line number for both addition and removal to drive the point home.
-            //
-            // N - fn foo<A: T>(bar: A) {
-            // N + fn foo(bar: impl T) {
-            buffer.puts(
-                *row_num - 1,
-                0,
-                &self.maybe_anonymized(line_start + line_pos),
-                Style::LineNumber,
-            );
-            buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
-            buffer.puts(
-                *row_num - 1,
-                max_line_num_len + 3,
-                &normalize_whitespace(
-                    &file_lines.file.get_line(file_lines.lines[line_pos].line_index).unwrap(),
-                ),
-                Style::NoStyle,
-            );
-            buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
+            // We need to print more than one line if the span we need to remove is multiline.
+            // For more info: https://github.com/rust-lang/rust/issues/92741
+            let lines_to_remove = file_lines.lines.iter().take(file_lines.lines.len() - 1);
+            for (index, line_to_remove) in lines_to_remove.enumerate() {
+                buffer.puts(
+                    *row_num - 1,
+                    0,
+                    &self.maybe_anonymized(line_num + index),
+                    Style::LineNumber,
+                );
+                buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
+                let line = normalize_whitespace(
+                    &file_lines.file.get_line(line_to_remove.line_index).unwrap(),
+                );
+                buffer.puts(*row_num - 1, max_line_num_len + 3, &line, Style::NoStyle);
+                *row_num += 1;
+            }
+            // If the last line is exactly equal to the line we need to add, we can skip both of them.
+            // This allows us to avoid output like the following:
+            // 2 - &
+            // 2 + if true { true } else { false }
+            // 3 - if true { true } else { false }
+            // If those lines aren't equal, we print their diff
+            let last_line_index = file_lines.lines[file_lines.lines.len() - 1].line_index;
+            let last_line = &file_lines.file.get_line(last_line_index).unwrap();
+            if last_line != line_to_add {
+                buffer.puts(
+                    *row_num - 1,
+                    0,
+                    &self.maybe_anonymized(line_num + file_lines.lines.len() - 1),
+                    Style::LineNumber,
+                );
+                buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
+                buffer.puts(
+                    *row_num - 1,
+                    max_line_num_len + 3,
+                    &normalize_whitespace(last_line),
+                    Style::NoStyle,
+                );
+                buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
+                buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
+                buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
+            } else {
+                *row_num -= 2;
+            }
         } else if is_multiline {
+            buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
             match &highlight_parts[..] {
-                [SubstitutionHighlight { start: 0, end }] if *end == line.len() => {
+                [SubstitutionHighlight { start: 0, end }] if *end == line_to_add.len() => {
                     buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
                 }
                 [] => {
@@ -2210,17 +2229,17 @@ fn draw_code_line(
                     buffer.puts(*row_num, max_line_num_len + 1, "~ ", Style::Addition);
                 }
             }
+            buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
         } else {
+            buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
             draw_col_separator(buffer, *row_num, max_line_num_len + 1);
+            buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
         }
 
-        // print the suggestion
-        buffer.append(*row_num, &normalize_whitespace(line), Style::NoStyle);
-
         // Colorize addition/replacements with green.
         for &SubstitutionHighlight { start, end } in highlight_parts {
             // Account for tabs when highlighting (#87972).
-            let tabs: usize = line
+            let tabs: usize = line_to_add
                 .chars()
                 .take(start)
                 .map(|ch| match ch {
index 9158fc082471f8fbedaf7e915fa998d83243215d..0454633091568ea61c5de649f85d8b206d79b019 100644 (file)
@@ -287,7 +287,7 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     TryTraitBranch,          sym::branch,              branch_fn,                  Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
     TryTraitFromYeet,        sym::from_yeet,           from_yeet_fn,               Target::Fn,             GenericRequirement::None;
 
-    PointerSized,            sym::pointer_sized,       pointer_sized,              Target::Trait,          GenericRequirement::Exact(0);
+    PointerLike,             sym::pointer_like,        pointer_like,               Target::Trait,          GenericRequirement::Exact(0);
 
     Poll,                    sym::Poll,                poll,                       Target::Enum,           GenericRequirement::None;
     PollReady,               sym::Ready,               poll_ready_variant,         Target::Variant,        GenericRequirement::None;
index 6600e4216bd1f4a54304af6e41bc128ff22d4670..8c2423e3ca0d1f78f9c8847a73171c6fe7b1a207 100644 (file)
@@ -176,6 +176,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
                 bounds.iter().map(|(param, constraint, def_id)| {
                     (param.as_str(), constraint.as_str(), *def_id)
                 }),
+                None,
             );
             err.emit();
         }
index ade9c037c519405d04470edbf8c5741f8e9cba07..7173239ba619a849b0e71a46e49ed3395dde162e 100644 (file)
@@ -765,7 +765,7 @@ fn coerce_dyn_star(
             self.cause.clone(),
             self.param_env,
             ty::Binder::dummy(
-                self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerSized, [a]),
+                self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerLike, [a]),
             ),
         ));
 
index 2eab68050d43043d6395205cbb863cb908445677..db1acb599271696008ec0143c1f68a587ddf173f 100644 (file)
 use crate::FnCtxt;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
-use rustc_middle::ty::{self, DefIdTree, Ty};
+use rustc_hir::def_id::DefId;
+use rustc_infer::traits::ObligationCauseCode;
+use rustc_middle::ty::{self, DefIdTree, Ty, TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_span::{self, Span};
 use rustc_trait_selection::traits;
 
+use std::ops::ControlFlow;
+
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub fn adjust_fulfillment_error_for_expr_obligation(
+        &self,
+        error: &mut traits::FulfillmentError<'tcx>,
+    ) -> bool {
+        let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx))
+            = *error.obligation.cause.code().peel_derives() else { return false; };
+        let hir = self.tcx.hir();
+        let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; };
+
+        let Some(unsubstituted_pred) =
+            self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx)
+            else { return false; };
+
+        let generics = self.tcx.generics_of(def_id);
+        let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
+            ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs,
+            ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs,
+            _ => ty::List::empty(),
+        };
+
+        let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| {
+            predicate_substs.types().find_map(|ty| {
+                ty.walk().find_map(|arg| {
+                    if let ty::GenericArgKind::Type(ty) = arg.unpack()
+                        && let ty::Param(param_ty) = ty.kind()
+                        && matches(param_ty)
+                    {
+                        Some(arg)
+                    } else {
+                        None
+                    }
+                })
+            })
+        };
+
+        // Prefer generics that are local to the fn item, since these are likely
+        // to be the cause of the unsatisfied predicate.
+        let mut param_to_point_at = find_param_matching(&|param_ty| {
+            self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id
+        });
+        // Fall back to generic that isn't local to the fn item. This will come
+        // from a trait or impl, for example.
+        let mut fallback_param_to_point_at = find_param_matching(&|param_ty| {
+            self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id
+                && param_ty.name != rustc_span::symbol::kw::SelfUpper
+        });
+        // Finally, the `Self` parameter is possibly the reason that the predicate
+        // is unsatisfied. This is less likely to be true for methods, because
+        // method probe means that we already kinda check that the predicates due
+        // to the `Self` type are true.
+        let mut self_param_to_point_at =
+            find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper);
+
+        // Finally, for ambiguity-related errors, we actually want to look
+        // for a parameter that is the source of the inference type left
+        // over in this predicate.
+        if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code {
+            fallback_param_to_point_at = None;
+            self_param_to_point_at = None;
+            param_to_point_at =
+                self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
+        }
+
+        if self.closure_span_overlaps_error(error, expr.span) {
+            return false;
+        }
+
+        match &expr.kind {
+            hir::ExprKind::Path(qpath) => {
+                if let hir::Node::Expr(hir::Expr {
+                    kind: hir::ExprKind::Call(callee, args),
+                    hir_id: call_hir_id,
+                    span: call_span,
+                    ..
+                }) = hir.get_parent(expr.hir_id)
+                    && callee.hir_id == expr.hir_id
+                {
+                    if self.closure_span_overlaps_error(error, *call_span) {
+                        return false;
+                    }
+
+                    for param in
+                        [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
+                        .into_iter()
+                        .flatten()
+                    {
+                        if self.blame_specific_arg_if_possible(
+                                error,
+                                def_id,
+                                param,
+                                *call_hir_id,
+                                callee.span,
+                                None,
+                                args,
+                            )
+                        {
+                            return true;
+                        }
+                    }
+                }
+                // Notably, we only point to params that are local to the
+                // item we're checking, since those are the ones we are able
+                // to look in the final `hir::PathSegment` for. Everything else
+                // would require a deeper search into the `qpath` than I think
+                // is worthwhile.
+                if let Some(param_to_point_at) = param_to_point_at
+                    && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
+                {
+                    return true;
+                }
+            }
+            hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
+                for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
+                    .into_iter()
+                    .flatten()
+                {
+                    if self.blame_specific_arg_if_possible(
+                        error,
+                        def_id,
+                        param,
+                        hir_id,
+                        segment.ident.span,
+                        Some(receiver),
+                        args,
+                    ) {
+                        return true;
+                    }
+                }
+                if let Some(param_to_point_at) = param_to_point_at
+                    && self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment)
+                {
+                    return true;
+                }
+            }
+            hir::ExprKind::Struct(qpath, fields, ..) => {
+                if let Res::Def(
+                    hir::def::DefKind::Struct | hir::def::DefKind::Variant,
+                    variant_def_id,
+                ) = self.typeck_results.borrow().qpath_res(qpath, hir_id)
+                {
+                    for param in
+                        [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
+                    {
+                        if let Some(param) = param {
+                            let refined_expr = self.point_at_field_if_possible(
+                                def_id,
+                                param,
+                                variant_def_id,
+                                fields,
+                            );
+
+                            match refined_expr {
+                                None => {}
+                                Some((refined_expr, _)) => {
+                                    error.obligation.cause.span = refined_expr
+                                        .span
+                                        .find_ancestor_in_same_ctxt(error.obligation.cause.span)
+                                        .unwrap_or(refined_expr.span);
+                                    return true;
+                                }
+                            }
+                        }
+                    }
+                }
+                if let Some(param_to_point_at) = param_to_point_at
+                    && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
+                {
+                    return true;
+                }
+            }
+            _ => {}
+        }
+
+        false
+    }
+
+    fn point_at_path_if_possible(
+        &self,
+        error: &mut traits::FulfillmentError<'tcx>,
+        def_id: DefId,
+        param: ty::GenericArg<'tcx>,
+        qpath: &hir::QPath<'tcx>,
+    ) -> bool {
+        match qpath {
+            hir::QPath::Resolved(_, path) => {
+                if let Some(segment) = path.segments.last()
+                    && self.point_at_generic_if_possible(error, def_id, param, segment)
+                {
+                    return true;
+                }
+            }
+            hir::QPath::TypeRelative(_, segment) => {
+                if self.point_at_generic_if_possible(error, def_id, param, segment) {
+                    return true;
+                }
+            }
+            _ => {}
+        }
+
+        false
+    }
+
+    fn point_at_generic_if_possible(
+        &self,
+        error: &mut traits::FulfillmentError<'tcx>,
+        def_id: DefId,
+        param_to_point_at: ty::GenericArg<'tcx>,
+        segment: &hir::PathSegment<'tcx>,
+    ) -> bool {
+        let own_substs = self
+            .tcx
+            .generics_of(def_id)
+            .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id));
+        let Some((index, _)) = own_substs
+            .iter()
+            .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
+            .enumerate()
+            .find(|(_, arg)| **arg == param_to_point_at) else { return false };
+        let Some(arg) = segment
+            .args()
+            .args
+            .iter()
+            .filter(|arg| matches!(arg, hir::GenericArg::Type(_)))
+            .nth(index) else { return false; };
+        error.obligation.cause.span = arg
+            .span()
+            .find_ancestor_in_same_ctxt(error.obligation.cause.span)
+            .unwrap_or(arg.span());
+        true
+    }
+
+    fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>(
+        &self,
+        item_def_id: DefId,
+        t: T,
+    ) -> Option<ty::GenericArg<'tcx>> {
+        struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId);
+        impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> {
+            type BreakTy = ty::GenericArg<'tcx>;
+            fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
+                if let Some(origin) = self.0.type_var_origin(ty)
+                    && let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) =
+                        origin.kind
+                    && let generics = self.0.tcx.generics_of(self.1)
+                    && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
+                    && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1)
+                        .get(index as usize)
+                {
+                    ControlFlow::Break(*subst)
+                } else {
+                    ty.super_visit_with(self)
+                }
+            }
+        }
+        t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value()
+    }
+
+    fn closure_span_overlaps_error(
+        &self,
+        error: &traits::FulfillmentError<'tcx>,
+        span: Span,
+    ) -> bool {
+        if let traits::FulfillmentErrorCode::CodeSelectionError(
+            traits::SelectionError::OutputTypeParameterMismatch(_, expected, _),
+        ) = error.code
+            && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind()
+            && span.overlaps(self.tcx.def_span(*def_id))
+        {
+            true
+        } else {
+            false
+        }
+    }
+
+    fn point_at_field_if_possible(
+        &self,
+        def_id: DefId,
+        param_to_point_at: ty::GenericArg<'tcx>,
+        variant_def_id: DefId,
+        expr_fields: &[hir::ExprField<'tcx>],
+    ) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> {
+        let def = self.tcx.adt_def(def_id);
+
+        let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id);
+        let fields_referencing_param: Vec<_> = def
+            .variant_with_id(variant_def_id)
+            .fields
+            .iter()
+            .filter(|field| {
+                let field_ty = field.ty(self.tcx, identity_substs);
+                Self::find_param_in_ty(field_ty.into(), param_to_point_at)
+            })
+            .collect();
+
+        if let [field] = fields_referencing_param.as_slice() {
+            for expr_field in expr_fields {
+                // Look for the ExprField that matches the field, using the
+                // same rules that check_expr_struct uses for macro hygiene.
+                if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
+                {
+                    return Some((expr_field.expr, self.tcx.type_of(field.did)));
+                }
+            }
+        }
+
+        None
+    }
+
+    /// - `blame_specific_*` means that the function will recursively traverse the expression,
+    /// looking for the most-specific-possible span to blame.
+    ///
+    /// - `point_at_*` means that the function will only go "one level", pointing at the specific
+    /// expression mentioned.
+    ///
+    /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside
+    /// the provided function call expression, and mark it as responsible for the fullfillment
+    /// error.
+    fn blame_specific_arg_if_possible(
+        &self,
+        error: &mut traits::FulfillmentError<'tcx>,
+        def_id: DefId,
+        param_to_point_at: ty::GenericArg<'tcx>,
+        call_hir_id: hir::HirId,
+        callee_span: Span,
+        receiver: Option<&'tcx hir::Expr<'tcx>>,
+        args: &'tcx [hir::Expr<'tcx>],
+    ) -> bool {
+        let ty = self.tcx.type_of(def_id);
+        if !ty.is_fn() {
+            return false;
+        }
+        let sig = ty.fn_sig(self.tcx).skip_binder();
+        let args_referencing_param: Vec<_> = sig
+            .inputs()
+            .iter()
+            .enumerate()
+            .filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at))
+            .collect();
+        // If there's one field that references the given generic, great!
+        if let [(idx, _)] = args_referencing_param.as_slice()
+            && let Some(arg) = receiver
+                .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
+
+            error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
+
+            if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) {
+                // This is more specific than pointing at the entire argument.
+                self.blame_specific_expr_if_possible(error, arg_expr)
+            }
+
+            error.obligation.cause.map_code(|parent_code| {
+                ObligationCauseCode::FunctionArgumentObligation {
+                    arg_hir_id: arg.hir_id,
+                    call_hir_id,
+                    parent_code,
+                }
+            });
+            return true;
+        } else if args_referencing_param.len() > 0 {
+            // If more than one argument applies, then point to the callee span at least...
+            // We have chance to fix this up further in `point_at_generics_if_possible`
+            error.obligation.cause.span = callee_span;
+        }
+
+        false
+    }
+
     /**
      * Recursively searches for the most-specific blamable expression.
      * For example, if you have a chain of constraints like:
index 1055ee953eae6f554036ddd90007e0813e7f312a..2a1265600de8b32738e227b6670768c98af19401 100644 (file)
@@ -26,7 +26,7 @@
 use rustc_infer::infer::TypeTrace;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor};
+use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty};
 use rustc_session::Session;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{self, sym, Span};
@@ -36,8 +36,6 @@
 use std::mem;
 use std::slice;
 
-use std::ops::ControlFlow;
-
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn check_casts(&mut self) {
         // don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors
@@ -1758,372 +1756,6 @@ pub(super) fn adjust_fulfillment_errors_for_expr_obligation(
         }
     }
 
-    fn adjust_fulfillment_error_for_expr_obligation(
-        &self,
-        error: &mut traits::FulfillmentError<'tcx>,
-    ) -> bool {
-        let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx))
-            = *error.obligation.cause.code().peel_derives() else { return false; };
-        let hir = self.tcx.hir();
-        let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; };
-
-        let Some(unsubstituted_pred) =
-            self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx)
-            else { return false; };
-
-        let generics = self.tcx.generics_of(def_id);
-        let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
-            ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs,
-            ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs,
-            _ => ty::List::empty(),
-        };
-
-        let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| {
-            predicate_substs.types().find_map(|ty| {
-                ty.walk().find_map(|arg| {
-                    if let ty::GenericArgKind::Type(ty) = arg.unpack()
-                        && let ty::Param(param_ty) = ty.kind()
-                        && matches(param_ty)
-                    {
-                        Some(arg)
-                    } else {
-                        None
-                    }
-                })
-            })
-        };
-
-        // Prefer generics that are local to the fn item, since these are likely
-        // to be the cause of the unsatisfied predicate.
-        let mut param_to_point_at = find_param_matching(&|param_ty| {
-            self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id
-        });
-        // Fall back to generic that isn't local to the fn item. This will come
-        // from a trait or impl, for example.
-        let mut fallback_param_to_point_at = find_param_matching(&|param_ty| {
-            self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id
-                && param_ty.name != rustc_span::symbol::kw::SelfUpper
-        });
-        // Finally, the `Self` parameter is possibly the reason that the predicate
-        // is unsatisfied. This is less likely to be true for methods, because
-        // method probe means that we already kinda check that the predicates due
-        // to the `Self` type are true.
-        let mut self_param_to_point_at =
-            find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper);
-
-        // Finally, for ambiguity-related errors, we actually want to look
-        // for a parameter that is the source of the inference type left
-        // over in this predicate.
-        if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code {
-            fallback_param_to_point_at = None;
-            self_param_to_point_at = None;
-            param_to_point_at =
-                self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
-        }
-
-        if self.closure_span_overlaps_error(error, expr.span) {
-            return false;
-        }
-
-        match &expr.kind {
-            hir::ExprKind::Path(qpath) => {
-                if let hir::Node::Expr(hir::Expr {
-                    kind: hir::ExprKind::Call(callee, args),
-                    hir_id: call_hir_id,
-                    span: call_span,
-                    ..
-                }) = hir.get_parent(expr.hir_id)
-                    && callee.hir_id == expr.hir_id
-                {
-                    if self.closure_span_overlaps_error(error, *call_span) {
-                        return false;
-                    }
-
-                    for param in
-                        [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
-                        .into_iter()
-                        .flatten()
-                    {
-                        if self.blame_specific_arg_if_possible(
-                                error,
-                                def_id,
-                                param,
-                                *call_hir_id,
-                                callee.span,
-                                None,
-                                args,
-                            )
-                        {
-                            return true;
-                        }
-                    }
-                }
-                // Notably, we only point to params that are local to the
-                // item we're checking, since those are the ones we are able
-                // to look in the final `hir::PathSegment` for. Everything else
-                // would require a deeper search into the `qpath` than I think
-                // is worthwhile.
-                if let Some(param_to_point_at) = param_to_point_at
-                    && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
-                {
-                    return true;
-                }
-            }
-            hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
-                for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
-                    .into_iter()
-                    .flatten()
-                {
-                    if self.blame_specific_arg_if_possible(
-                        error,
-                        def_id,
-                        param,
-                        hir_id,
-                        segment.ident.span,
-                        Some(receiver),
-                        args,
-                    ) {
-                        return true;
-                    }
-                }
-                if let Some(param_to_point_at) = param_to_point_at
-                    && self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment)
-                {
-                    return true;
-                }
-            }
-            hir::ExprKind::Struct(qpath, fields, ..) => {
-                if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) =
-                    self.typeck_results.borrow().qpath_res(qpath, hir_id)
-                {
-                    for param in
-                        [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
-                    {
-                        if let Some(param) = param {
-                            let refined_expr = self.point_at_field_if_possible(
-                                def_id,
-                                param,
-                                variant_def_id,
-                                fields,
-                            );
-
-                            match refined_expr {
-                                None => {}
-                                Some((refined_expr, _)) => {
-                                    error.obligation.cause.span = refined_expr
-                                        .span
-                                        .find_ancestor_in_same_ctxt(error.obligation.cause.span)
-                                        .unwrap_or(refined_expr.span);
-                                    return true;
-                                }
-                            }
-                        }
-                    }
-                }
-                if let Some(param_to_point_at) = param_to_point_at
-                    && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
-                {
-                    return true;
-                }
-            }
-            _ => {}
-        }
-
-        false
-    }
-
-    fn closure_span_overlaps_error(
-        &self,
-        error: &traits::FulfillmentError<'tcx>,
-        span: Span,
-    ) -> bool {
-        if let traits::FulfillmentErrorCode::CodeSelectionError(
-            traits::SelectionError::OutputTypeParameterMismatch(_, expected, _),
-        ) = error.code
-            && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind()
-            && span.overlaps(self.tcx.def_span(*def_id))
-        {
-            true
-        } else {
-            false
-        }
-    }
-
-    /// - `blame_specific_*` means that the function will recursively traverse the expression,
-    /// looking for the most-specific-possible span to blame.
-    ///
-    /// - `point_at_*` means that the function will only go "one level", pointing at the specific
-    /// expression mentioned.
-    ///
-    /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside
-    /// the provided function call expression, and mark it as responsible for the fullfillment
-    /// error.
-    fn blame_specific_arg_if_possible(
-        &self,
-        error: &mut traits::FulfillmentError<'tcx>,
-        def_id: DefId,
-        param_to_point_at: ty::GenericArg<'tcx>,
-        call_hir_id: hir::HirId,
-        callee_span: Span,
-        receiver: Option<&'tcx hir::Expr<'tcx>>,
-        args: &'tcx [hir::Expr<'tcx>],
-    ) -> bool {
-        let ty = self.tcx.type_of(def_id);
-        if !ty.is_fn() {
-            return false;
-        }
-        let sig = ty.fn_sig(self.tcx).skip_binder();
-        let args_referencing_param: Vec<_> = sig
-            .inputs()
-            .iter()
-            .enumerate()
-            .filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at))
-            .collect();
-        // If there's one field that references the given generic, great!
-        if let [(idx, _)] = args_referencing_param.as_slice()
-            && let Some(arg) = receiver
-                .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
-
-            error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
-
-            if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) {
-                // This is more specific than pointing at the entire argument.
-                self.blame_specific_expr_if_possible(error, arg_expr)
-            }
-
-            error.obligation.cause.map_code(|parent_code| {
-                ObligationCauseCode::FunctionArgumentObligation {
-                    arg_hir_id: arg.hir_id,
-                    call_hir_id,
-                    parent_code,
-                }
-            });
-            return true;
-        } else if args_referencing_param.len() > 0 {
-            // If more than one argument applies, then point to the callee span at least...
-            // We have chance to fix this up further in `point_at_generics_if_possible`
-            error.obligation.cause.span = callee_span;
-        }
-
-        false
-    }
-
-    // FIXME: Make this private and move to mod adjust_fulfillment_errors
-    pub fn point_at_field_if_possible(
-        &self,
-        def_id: DefId,
-        param_to_point_at: ty::GenericArg<'tcx>,
-        variant_def_id: DefId,
-        expr_fields: &[hir::ExprField<'tcx>],
-    ) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> {
-        let def = self.tcx.adt_def(def_id);
-
-        let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id);
-        let fields_referencing_param: Vec<_> = def
-            .variant_with_id(variant_def_id)
-            .fields
-            .iter()
-            .filter(|field| {
-                let field_ty = field.ty(self.tcx, identity_substs);
-                Self::find_param_in_ty(field_ty.into(), param_to_point_at)
-            })
-            .collect();
-
-        if let [field] = fields_referencing_param.as_slice() {
-            for expr_field in expr_fields {
-                // Look for the ExprField that matches the field, using the
-                // same rules that check_expr_struct uses for macro hygiene.
-                if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
-                {
-                    return Some((expr_field.expr, self.tcx.type_of(field.did)));
-                }
-            }
-        }
-
-        None
-    }
-
-    fn point_at_path_if_possible(
-        &self,
-        error: &mut traits::FulfillmentError<'tcx>,
-        def_id: DefId,
-        param: ty::GenericArg<'tcx>,
-        qpath: &QPath<'tcx>,
-    ) -> bool {
-        match qpath {
-            hir::QPath::Resolved(_, path) => {
-                if let Some(segment) = path.segments.last()
-                    && self.point_at_generic_if_possible(error, def_id, param, segment)
-                {
-                    return true;
-                }
-            }
-            hir::QPath::TypeRelative(_, segment) => {
-                if self.point_at_generic_if_possible(error, def_id, param, segment) {
-                    return true;
-                }
-            }
-            _ => {}
-        }
-
-        false
-    }
-
-    fn point_at_generic_if_possible(
-        &self,
-        error: &mut traits::FulfillmentError<'tcx>,
-        def_id: DefId,
-        param_to_point_at: ty::GenericArg<'tcx>,
-        segment: &hir::PathSegment<'tcx>,
-    ) -> bool {
-        let own_substs = self
-            .tcx
-            .generics_of(def_id)
-            .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id));
-        let Some((index, _)) = own_substs
-            .iter()
-            .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
-            .enumerate()
-            .find(|(_, arg)| **arg == param_to_point_at) else { return false };
-        let Some(arg) = segment
-            .args()
-            .args
-            .iter()
-            .filter(|arg| matches!(arg, hir::GenericArg::Type(_)))
-            .nth(index) else { return false; };
-        error.obligation.cause.span = arg
-            .span()
-            .find_ancestor_in_same_ctxt(error.obligation.cause.span)
-            .unwrap_or(arg.span());
-        true
-    }
-
-    fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>(
-        &self,
-        item_def_id: DefId,
-        t: T,
-    ) -> Option<ty::GenericArg<'tcx>> {
-        struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId);
-        impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> {
-            type BreakTy = ty::GenericArg<'tcx>;
-            fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
-                if let Some(origin) = self.0.type_var_origin(ty)
-                    && let TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) =
-                        origin.kind
-                    && let generics = self.0.tcx.generics_of(self.1)
-                    && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
-                    && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1)
-                        .get(index as usize)
-                {
-                    ControlFlow::Break(*subst)
-                } else {
-                    ty.super_visit_with(self)
-                }
-            }
-        }
-        t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value()
-    }
-
     fn label_fn_like(
         &self,
         err: &mut Diagnostic,
index 51e3e3ec73db9d994a84c512645bd2ffbc2abca2..eaad57d8c2e9f1088ab839e4e266d62b302ea743 100644 (file)
@@ -1336,16 +1336,17 @@ pub(crate) fn suggest_associated_const(
                 hir::Path { segments: [segment], .. },
             ))
             | hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) => {
-                let self_ty = self.astconv().ast_ty_to_ty(ty);
-                if let Ok(pick) = self.probe_for_name(
-                    Mode::Path,
-                    Ident::new(capitalized_name, segment.ident.span),
-                    Some(expected_ty),
-                    IsSuggestion(true),
-                    self_ty,
-                    expr.hir_id,
-                    ProbeScope::TraitsInScope,
-                ) {
+                if let Some(self_ty) = self.typeck_results.borrow().node_type_opt(ty.hir_id)
+                    && let Ok(pick) = self.probe_for_name(
+                        Mode::Path,
+                        Ident::new(capitalized_name, segment.ident.span),
+                        Some(expected_ty),
+                        IsSuggestion(true),
+                        self_ty,
+                        expr.hir_id,
+                        ProbeScope::TraitsInScope,
+                    )
+                {
                     (pick.item, segment)
                 } else {
                     return false;
@@ -1457,6 +1458,7 @@ pub(crate) fn note_type_is_not_clone(
                     generics,
                     diag,
                     vec![(param.name.as_str(), "Clone", Some(clone_trait_did))].into_iter(),
+                    None,
                 );
             } else {
                 self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]);
index 3e8e7734a5a5de61d34fefba70cf674f0be512d7..7cc9e49b1b62adf66597091e683e21525347ca8f 100644 (file)
@@ -268,14 +268,12 @@ pub fn instantiate_nll_query_response_and_region_obligations<R>(
                 (GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => {
                     // To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
                     if v_o != v_r {
-                        output_query_region_constraints.outlives.push((
-                            ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)),
-                            constraint_category,
-                        ));
-                        output_query_region_constraints.outlives.push((
-                            ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)),
-                            constraint_category,
-                        ));
+                        output_query_region_constraints
+                            .outlives
+                            .push((ty::OutlivesPredicate(v_o.into(), v_r), constraint_category));
+                        output_query_region_constraints
+                            .outlives
+                            .push((ty::OutlivesPredicate(v_r.into(), v_o), constraint_category));
                     }
                 }
 
@@ -318,10 +316,8 @@ pub fn instantiate_nll_query_response_and_region_obligations<R>(
             query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| {
                 let r_c = substitute_value(self.tcx, &result_subst, r_c);
 
-                // Screen out `'a: 'a` cases -- we skip the binder here but
-                // only compare the inner values to one another, so they are still at
-                // consistent binding levels.
-                let ty::OutlivesPredicate(k1, r2) = r_c.0.skip_binder();
+                // Screen out `'a: 'a` cases.
+                let ty::OutlivesPredicate(k1, r2) = r_c.0;
                 if k1 != r2.into() { Some(r_c) } else { None }
             }),
         );
@@ -559,11 +555,11 @@ fn query_outlives_constraints_into_obligations<'a>(
 
     pub fn query_outlives_constraint_to_obligation(
         &self,
-        predicate: QueryOutlivesConstraint<'tcx>,
+        (predicate, _): QueryOutlivesConstraint<'tcx>,
         cause: ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> Obligation<'tcx, ty::Predicate<'tcx>> {
-        let ty::OutlivesPredicate(k1, r2) = predicate.0.skip_binder();
+        let ty::OutlivesPredicate(k1, r2) = predicate;
 
         let atom = match k1.unpack() {
             GenericArgKind::Lifetime(r1) => {
@@ -578,7 +574,7 @@ pub fn query_outlives_constraint_to_obligation(
                 span_bug!(cause.span, "unexpected const outlives {:?}", predicate);
             }
         };
-        let predicate = predicate.0.rebind(atom);
+        let predicate = ty::Binder::dummy(atom);
 
         Obligation::new(self.tcx, cause, param_env, predicate)
     }
@@ -643,8 +639,7 @@ pub fn make_query_region_constraints<'tcx>(
     let outlives: Vec<_> = constraints
         .iter()
         .map(|(k, origin)| {
-            // no bound vars in the code above
-            let constraint = ty::Binder::dummy(match *k {
+            let constraint = match *k {
                 // Swap regions because we are going from sub (<=) to outlives
                 // (>=).
                 Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
@@ -658,16 +653,12 @@ pub fn make_query_region_constraints<'tcx>(
                     ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
                 }
                 Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
-            });
+            };
             (constraint, origin.to_constraint_category())
         })
-        .chain(
-            outlives_obligations
-                // no bound vars in the code above
-                .map(|(ty, r, constraint_category)| {
-                    (ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), r)), constraint_category)
-                }),
-        )
+        .chain(outlives_obligations.map(|(ty, r, constraint_category)| {
+            (ty::OutlivesPredicate(ty.into(), r), constraint_category)
+        }))
         .collect();
 
     QueryRegionConstraints { outlives, member_constraints: member_constraints.clone() }
index b5c2d14e8d15b05a6e7dd54eaa894e6db8ac33e7..86f3174b7b2bb25e9c82d410761a445a4a5760f9 100644 (file)
@@ -1922,7 +1922,8 @@ fn escape_literal(s: &str) -> String {
                         (ty::Uint(ty::UintTy::U8), ty::Char) => {
                             if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
                                 && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
-                                && code.chars().next().map_or(false, |c| c.is_ascii())
+                                && !code.starts_with("\\u") // forbid all Unicode escapes
+                                && code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
                             {
                                 err.span_suggestion(
                                     span,
index 39b3c98f0a5ccadd22b3e0ad79ad8c6c0472eccb..984e8cf6a0eb909f872fb50574b53c586847a349 100644 (file)
@@ -77,49 +77,86 @@ pub fn note_and_explain_type_err(
                     (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
                         if tcx.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder =>
                     {
-                        let generics = tcx.generics_of(body_owner_def_id);
-                        let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
+                        let p_def_id = tcx
+                            .generics_of(body_owner_def_id)
+                            .type_param(p, tcx)
+                            .def_id;
+                        let p_span = tcx.def_span(p_def_id);
                         if !sp.contains(p_span) {
                             diag.span_label(p_span, "this type parameter");
                         }
                         let hir = tcx.hir();
                         let mut note = true;
-                        if let Some(generics) = generics
-                            .type_param(p, tcx)
-                            .def_id
+                        let parent = p_def_id
                             .as_local()
-                            .map(|id| hir.local_def_id_to_hir_id(id))
-                            .and_then(|id| tcx.hir().find_parent(id))
-                            .as_ref()
-                            .and_then(|node| node.generics())
+                            .and_then(|id| {
+                                let local_id = hir.local_def_id_to_hir_id(id);
+                                let generics = tcx.hir().find_parent(local_id)?.generics()?;
+                                Some((id, generics))
+                            });
+                        if let Some((local_id, generics)) = parent
                         {
                             // Synthesize the associated type restriction `Add<Output = Expected>`.
                             // FIXME: extract this logic for use in other diagnostics.
                             let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(tcx);
-                            let path =
-                                tcx.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
                             let item_name = tcx.item_name(proj.def_id);
                             let item_args = self.format_generic_args(assoc_substs);
 
-                            let path = if path.ends_with('>') {
-                                format!(
-                                    "{}, {}{} = {}>",
-                                    &path[..path.len() - 1],
-                                    item_name,
-                                    item_args,
-                                    p
-                                )
+                            // Here, we try to see if there's an existing
+                            // trait implementation that matches the one that
+                            // we're suggesting to restrict. If so, find the
+                            // "end", whether it be at the end of the trait
+                            // or the end of the generic arguments.
+                            let mut matching_span = None;
+                            let mut matched_end_of_args = false;
+                            for bound in generics.bounds_for_param(local_id) {
+                                let potential_spans = bound
+                                    .bounds
+                                    .iter()
+                                    .find_map(|bound| {
+                                        let bound_trait_path = bound.trait_ref()?.path;
+                                        let def_id = bound_trait_path.res.opt_def_id()?;
+                                        let generic_args = bound_trait_path.segments.iter().last().map(|path| path.args());
+                                        (def_id == trait_ref.def_id).then_some((bound_trait_path.span, generic_args))
+                                    });
+
+                                if let Some((end_of_trait, end_of_args)) = potential_spans {
+                                    let args_span = end_of_args.and_then(|args| args.span());
+                                    matched_end_of_args = args_span.is_some();
+                                    matching_span = args_span
+                                        .or_else(|| Some(end_of_trait))
+                                        .map(|span| span.shrink_to_hi());
+                                    break;
+                                }
+                            }
+
+                            if matched_end_of_args {
+                                // Append suggestion to the end of our args
+                                let path = format!(", {}{} = {}",item_name, item_args, p);
+                                note = !suggest_constraining_type_param(
+                                    tcx,
+                                    generics,
+                                    diag,
+                                    &format!("{}", proj.self_ty()),
+                                    &path,
+                                    None,
+                                    matching_span,
+                                );
                             } else {
-                                format!("{}<{}{} = {}>", path, item_name, item_args, p)
-                            };
-                            note = !suggest_constraining_type_param(
-                                tcx,
-                                generics,
-                                diag,
-                                &format!("{}", proj.self_ty()),
-                                &path,
-                                None,
-                            );
+                                // Suggest adding a bound to an existing trait
+                                // or if the trait doesn't exist, add the trait
+                                // and the suggested bounds.
+                                let path = format!("<{}{} = {}>", item_name, item_args, p);
+                                note = !suggest_constraining_type_param(
+                                    tcx,
+                                    generics,
+                                    diag,
+                                    &format!("{}", proj.self_ty()),
+                                    &path,
+                                    None,
+                                    matching_span,
+                                );
+                            }
                         }
                         if note {
                             diag.note("you might be missing a type parameter or trait bound");
index 727cfc4416ee94889cef6eb11cc01f98e120ab45..9146a3739b2b1b76dfe30a8dd68ec355debede20 100644 (file)
@@ -4,7 +4,6 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
 #include "llvm/Analysis/Lint.h"
 #include "llvm/Analysis/Passes.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/IRPrintingPasses.h"
 #include "llvm/Linker/Linker.h"
 
+#if LLVM_VERSION_GE(16, 0)
+#include "llvm/TargetParser/Triple.h"
+#else
+#include "llvm/ADT/Triple.h"
+#endif
+
 extern "C" void LLVMRustSetLastError(const char *);
 
 enum class LLVMRustResult { Success, Failure };
index 21652063b47167585124ef8f3293cc7acf031985..bf8b8aa2ce49704e13d47567f016d7ad2535e97b 100644 (file)
@@ -356,7 +356,12 @@ fn verify_no_symbol_conflicts(&self, root: &CrateRoot) -> Result<(), CrateError>
         for (_, other) in self.cstore.iter_crate_data() {
             // Same stable crate id but different SVH
             if other.stable_crate_id() == root.stable_crate_id() && other.hash() != root.hash() {
-                return Err(CrateError::SymbolConflictsOthers(root.name()));
+                bug!(
+                    "Previously returned E0523 here. \
+                     See https://github.com/rust-lang/rust/pull/100599 for additional discussion.\
+                     root.name() = {}.",
+                    root.name()
+                );
             }
         }
 
index 02c03114eb67f637cf5b1236e0d25d1310239019..c32686779facb5be9c91f306815ceba751897316 100644 (file)
@@ -511,14 +511,6 @@ pub struct SymbolConflictsCurrent {
     pub crate_name: Symbol,
 }
 
-#[derive(Diagnostic)]
-#[diag(metadata_symbol_conflicts_others, code = "E0523")]
-pub struct SymbolConflictsOthers {
-    #[primary_span]
-    pub span: Span,
-    pub crate_name: Symbol,
-}
-
 #[derive(Diagnostic)]
 #[diag(metadata_stable_crate_id_collision)]
 pub struct StableCrateIdCollision {
index 74f91a14ea9ae742c2e93a338fa8e050b62f23d9..755a24253504ec844eb3be0225a8772db6e0bdc1 100644 (file)
@@ -945,7 +945,6 @@ pub(crate) enum CrateError {
     ExternLocationNotFile(Symbol, PathBuf),
     MultipleCandidates(Symbol, CrateFlavor, Vec<PathBuf>),
     SymbolConflictsCurrent(Symbol),
-    SymbolConflictsOthers(Symbol),
     StableCrateIdCollision(Symbol, Symbol),
     DlOpen(String),
     DlSym(String),
@@ -989,9 +988,6 @@ pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
             CrateError::SymbolConflictsCurrent(root_name) => {
                 sess.emit_err(errors::SymbolConflictsCurrent { span, crate_name: root_name });
             }
-            CrateError::SymbolConflictsOthers(root_name) => {
-                sess.emit_err(errors::SymbolConflictsOthers { span, crate_name: root_name });
-            }
             CrateError::StableCrateIdCollision(crate_name0, crate_name1) => {
                 sess.emit_err(errors::StableCrateIdCollision { span, crate_name0, crate_name1 });
             }
index bb2dd290c6d5d1edef0ef7f26ae3f0bbb1793d69..e2b07fad6e782ee24ed5e65f8889a15e1bea3516 100644 (file)
@@ -654,7 +654,7 @@ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
 impl<'a, 'tcx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyArray<T> {
     fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
         let len = decoder.read_usize();
-        if len == 0 { LazyArray::empty() } else { decoder.read_lazy_array(len) }
+        if len == 0 { LazyArray::default() } else { decoder.read_lazy_array(len) }
     }
 }
 
@@ -864,7 +864,7 @@ fn get_variant(self, kind: &DefKind, index: DefIndex, parent_did: DefId) -> ty::
                 .tables
                 .children
                 .get(self, index)
-                .unwrap_or_else(LazyArray::empty)
+                .expect("fields are not encoded for a variant")
                 .decode(self)
                 .map(|index| ty::FieldDef {
                     did: self.local_def_id(index),
@@ -896,7 +896,7 @@ fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::AdtDef<'tcx> {
                 .tables
                 .children
                 .get(self, item_id)
-                .unwrap_or_else(LazyArray::empty)
+                .expect("variants are not encoded for an enum")
                 .decode(self)
                 .filter_map(|index| {
                     let kind = self.def_kind(index);
@@ -1045,7 +1045,7 @@ fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool {
             .tables
             .fn_arg_names
             .get(self, id)
-            .unwrap_or_else(LazyArray::empty)
+            .expect("argument names not encoded for a function")
             .decode((self, sess))
             .nth(0)
             .map_or(false, |ident| ident.name == kw::SelfLower)
@@ -1060,7 +1060,7 @@ fn get_associated_item_def_ids(
             .tables
             .children
             .get(self, id)
-            .unwrap_or_else(LazyArray::empty)
+            .expect("associated items not encoded for an item")
             .decode((self, sess))
             .map(move |child_index| self.local_def_id(child_index))
     }
@@ -1068,13 +1068,12 @@ fn get_associated_item_def_ids(
     fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem {
         let name = self.item_name(id);
 
-        let kind = match self.def_kind(id) {
-            DefKind::AssocConst => ty::AssocKind::Const,
-            DefKind::AssocFn => ty::AssocKind::Fn,
-            DefKind::AssocTy => ty::AssocKind::Type,
+        let (kind, has_self) = match self.def_kind(id) {
+            DefKind::AssocConst => (ty::AssocKind::Const, false),
+            DefKind::AssocFn => (ty::AssocKind::Fn, self.get_fn_has_self_parameter(id, sess)),
+            DefKind::AssocTy => (ty::AssocKind::Type, false),
             _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)),
         };
-        let has_self = self.get_fn_has_self_parameter(id, sess);
         let container = self.root.tables.assoc_container.get(self, id).unwrap();
 
         ty::AssocItem {
@@ -1131,7 +1130,7 @@ fn get_struct_field_names(
             .tables
             .children
             .get(self, id)
-            .unwrap_or_else(LazyArray::empty)
+            .expect("fields not encoded for a struct")
             .decode(self)
             .map(move |index| respan(self.get_span(index, sess), self.item_name(index)))
     }
@@ -1144,7 +1143,7 @@ fn get_struct_field_visibilities(
             .tables
             .children
             .get(self, id)
-            .unwrap_or_else(LazyArray::empty)
+            .expect("fields not encoded for a struct")
             .decode(self)
             .map(move |field_index| self.get_visibility(field_index))
     }
@@ -1159,7 +1158,6 @@ fn get_inherent_implementations_for_type(
                 .tables
                 .inherent_impls
                 .get(self, id)
-                .unwrap_or_else(LazyArray::empty)
                 .decode(self)
                 .map(|index| self.local_def_id(index)),
         )
@@ -1174,7 +1172,6 @@ fn get_inherent_impls(self) -> impl Iterator<Item = (DefId, DefId)> + 'a {
                 .tables
                 .inherent_impls
                 .get(self, ty_index)
-                .unwrap_or_else(LazyArray::empty)
                 .decode(self)
                 .map(move |impl_index| (ty_def_id, self.local_def_id(impl_index)))
         })
@@ -1322,7 +1319,7 @@ fn def_path_hash_unlocked(
     ) -> DefPathHash {
         *def_path_hashes
             .entry(index)
-            .or_insert_with(|| self.root.tables.def_path_hashes.get(self, index).unwrap())
+            .or_insert_with(|| self.root.tables.def_path_hashes.get(self, index))
     }
 
     #[inline]
index 9b1401f4a44dfdf922120faf9bd9f165c902d3c9..07cc84ab95368480a2ec09b80fe0bad29ed63e0c 100644 (file)
@@ -1,6 +1,7 @@
 use crate::creader::{CStore, LoadedMacro};
 use crate::foreign_modules;
 use crate::native_libs;
+use crate::rmeta::table::IsDefault;
 use crate::rmeta::AttrFlags;
 
 use rustc_ast as ast;
@@ -88,6 +89,14 @@ macro_rules! provide_one {
             }
         }
     };
+    ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_defaulted_array }) => {
+        provide_one! {
+            $tcx, $def_id, $other, $cdata, $name => {
+                let lazy = $cdata.root.tables.$name.get($cdata, $def_id.index);
+                if lazy.is_default() { &[] } else { $tcx.arena.alloc_from_iter(lazy.decode(($cdata, $tcx))) }
+            }
+        }
+    };
     ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_direct }) => {
         provide_one! {
             $tcx, $def_id, $other, $cdata, $name => {
@@ -187,10 +196,10 @@ fn into_args(self) -> (DefId, SimplifiedType) {
 }
 
 provide! { tcx, def_id, other, cdata,
-    explicit_item_bounds => { table }
+    explicit_item_bounds => { table_defaulted_array }
     explicit_predicates_of => { table }
     generics_of => { table }
-    inferred_outlives_of => { table }
+    inferred_outlives_of => { table_defaulted_array }
     super_predicates_of => { table }
     type_of => { table }
     variances_of => { table }
index 9d8f14058f681203548cd2a703b3556b5d6c7129..85e9ae9a98302bb780f1866295e0768970998982 100644 (file)
@@ -76,13 +76,13 @@ pub(super) struct EncodeContext<'a, 'tcx> {
     symbol_table: FxHashMap<Symbol, usize>,
 }
 
-/// If the current crate is a proc-macro, returns early with `LazyArray::empty()`.
+/// If the current crate is a proc-macro, returns early with `LazyArray::default()`.
 /// This is useful for skipping the encoding of things that aren't needed
 /// for proc-macro crates.
 macro_rules! empty_proc_macro {
     ($self:ident) => {
         if $self.is_proc_macro {
-            return LazyArray::empty();
+            return LazyArray::default();
         }
     };
 }
@@ -365,21 +365,31 @@ fn encode_alloc_id(&mut self, alloc_id: &rustc_middle::mir::interpret::AllocId)
     }
 }
 
-// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy_value($value))`, which would
+// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_value($value))`, which would
 // normally need extra variables to avoid errors about multiple mutable borrows.
 macro_rules! record {
     ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
         {
             let value = $value;
             let lazy = $self.lazy(value);
-            $self.$tables.$table.set($def_id.index, lazy);
+            $self.$tables.$table.set_some($def_id.index, lazy);
         }
     }};
 }
 
-// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy_value($value))`, which would
+// Shorthand for `$self.$tables.$table.set_some($def_id.index, $self.lazy_value($value))`, which would
 // normally need extra variables to avoid errors about multiple mutable borrows.
 macro_rules! record_array {
+    ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
+        {
+            let value = $value;
+            let lazy = $self.lazy_array(value);
+            $self.$tables.$table.set_some($def_id.index, lazy);
+        }
+    }};
+}
+
+macro_rules! record_defaulted_array {
     ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
         {
             let value = $value;
@@ -467,13 +477,13 @@ fn encode_def_path_table(&mut self) {
             {
                 let def_key = self.lazy(table.def_key(def_index));
                 let def_path_hash = table.def_path_hash(def_index);
-                self.tables.def_keys.set(def_index, def_key);
+                self.tables.def_keys.set_some(def_index, def_key);
                 self.tables.def_path_hashes.set(def_index, def_path_hash);
             }
         } else {
             for (def_index, def_key, def_path_hash) in table.enumerated_keys_and_path_hashes() {
                 let def_key = self.lazy(def_key);
-                self.tables.def_keys.set(def_index, def_key);
+                self.tables.def_keys.set_some(def_index, def_key);
                 self.tables.def_path_hashes.set(def_index, *def_path_hash);
             }
         }
@@ -548,7 +558,7 @@ fn encode_source_map(&mut self) -> LazyTable<u32, Option<LazyValue<rustc_span::S
 
             let on_disk_index: u32 =
                 on_disk_index.try_into().expect("cannot export more than U32_MAX files");
-            adapted.set(on_disk_index, self.lazy(source_file));
+            adapted.set_some(on_disk_index, self.lazy(source_file));
         }
 
         adapted.encode(&mut self.opaque)
@@ -1147,9 +1157,7 @@ fn encode_attrs(&mut self, def_id: LocalDefId) {
         if state.is_doc_hidden {
             attr_flags |= AttrFlags::IS_DOC_HIDDEN;
         }
-        if !attr_flags.is_empty() {
-            self.tables.attr_flags.set_nullable(def_id.local_def_index, attr_flags);
-        }
+        self.tables.attr_flags.set(def_id.local_def_index, attr_flags);
     }
 
     fn encode_def_ids(&mut self) {
@@ -1161,7 +1169,7 @@ fn encode_def_ids(&mut self) {
             let def_id = local_id.to_def_id();
             let def_kind = tcx.opt_def_kind(local_id);
             let Some(def_kind) = def_kind else { continue };
-            self.tables.opt_def_kind.set(def_id.index, def_kind);
+            self.tables.opt_def_kind.set_some(def_id.index, def_kind);
             let def_span = tcx.def_span(local_id);
             record!(self.tables.def_span[def_id] <- def_span);
             self.encode_attrs(local_id);
@@ -1192,9 +1200,7 @@ fn encode_def_ids(&mut self) {
                 record!(self.tables.generics_of[def_id] <- g);
                 record!(self.tables.explicit_predicates_of[def_id] <- self.tcx.explicit_predicates_of(def_id));
                 let inferred_outlives = self.tcx.inferred_outlives_of(def_id);
-                if !inferred_outlives.is_empty() {
-                    record_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives);
-                }
+                record_defaulted_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives);
             }
             if should_encode_type(tcx, local_id, def_kind) {
                 record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id));
@@ -1215,15 +1221,12 @@ fn encode_def_ids(&mut self) {
                 record!(self.tables.trait_impl_trait_tys[def_id] <- table);
             }
         }
+
         let inherent_impls = tcx.with_stable_hashing_context(|hcx| {
             tcx.crate_inherent_impls(()).inherent_impls.to_sorted(&hcx, true)
         });
-
-        for (def_id, implementations) in inherent_impls {
-            if implementations.is_empty() {
-                continue;
-            }
-            record_array!(self.tables.inherent_impls[def_id.to_def_id()] <- implementations.iter().map(|&def_id| {
+        for (def_id, impls) in inherent_impls {
+            record_defaulted_array!(self.tables.inherent_impls[def_id.to_def_id()] <- impls.iter().map(|def_id| {
                 assert!(def_id.is_local());
                 def_id.index
             }));
@@ -1264,14 +1267,14 @@ fn encode_info_for_adt(&mut self, def_id: DefId) {
             };
             record!(self.tables.variant_data[variant.def_id] <- data);
 
-            self.tables.constness.set(variant.def_id.index, hir::Constness::Const);
+            self.tables.constness.set_some(variant.def_id.index, hir::Constness::Const);
             record_array!(self.tables.children[variant.def_id] <- variant.fields.iter().map(|f| {
                 assert!(f.did.is_local());
                 f.did.index
             }));
 
             if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor {
-                self.tables.constness.set(ctor_def_id.index, hir::Constness::Const);
+                self.tables.constness.set_some(ctor_def_id.index, hir::Constness::Const);
                 let fn_sig = tcx.fn_sig(ctor_def_id);
                 record!(self.tables.fn_sig[ctor_def_id] <- fn_sig);
                 // FIXME only encode signature for ctor_def_id
@@ -1332,9 +1335,7 @@ fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) {
     fn encode_explicit_item_bounds(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id);
         let bounds = self.tcx.explicit_item_bounds(def_id);
-        if !bounds.is_empty() {
-            record_array!(self.tables.explicit_item_bounds[def_id] <- bounds);
-        }
+        record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds);
     }
 
     fn encode_info_for_trait_item(&mut self, def_id: DefId) {
@@ -1342,16 +1343,16 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) {
         let tcx = self.tcx;
 
         let impl_defaultness = tcx.impl_defaultness(def_id.expect_local());
-        self.tables.impl_defaultness.set(def_id.index, impl_defaultness);
+        self.tables.impl_defaultness.set_some(def_id.index, impl_defaultness);
         let trait_item = tcx.associated_item(def_id);
-        self.tables.assoc_container.set(def_id.index, trait_item.container);
+        self.tables.assoc_container.set_some(def_id.index, trait_item.container);
 
         match trait_item.kind {
             ty::AssocKind::Const => {}
             ty::AssocKind::Fn => {
                 record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id));
-                self.tables.asyncness.set(def_id.index, tcx.asyncness(def_id));
-                self.tables.constness.set(def_id.index, hir::Constness::NotConst);
+                self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id));
+                self.tables.constness.set_some(def_id.index, hir::Constness::NotConst);
             }
             ty::AssocKind::Type => {
                 self.encode_explicit_item_bounds(def_id);
@@ -1367,14 +1368,14 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
         let tcx = self.tcx;
 
         let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local());
-        self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness);
+        self.tables.impl_defaultness.set_some(def_id.index, ast_item.defaultness);
         let impl_item = self.tcx.associated_item(def_id);
-        self.tables.assoc_container.set(def_id.index, impl_item.container);
+        self.tables.assoc_container.set_some(def_id.index, impl_item.container);
 
         match impl_item.kind {
             ty::AssocKind::Fn => {
                 let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
-                self.tables.asyncness.set(def_id.index, sig.header.asyncness);
+                self.tables.asyncness.set_some(def_id.index, sig.header.asyncness);
                 record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
                 // Can be inside `impl const Trait`, so using sig.header.constness is not reliable
                 let constness = if self.tcx.is_const_fn_raw(def_id) {
@@ -1382,18 +1383,16 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
                 } else {
                     hir::Constness::NotConst
                 };
-                self.tables.constness.set(def_id.index, constness);
+                self.tables.constness.set_some(def_id.index, constness);
             }
             ty::AssocKind::Const | ty::AssocKind::Type => {}
         }
         if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
-            self.tables.trait_item_def_id.set(def_id.index, trait_item_def_id.into());
+            self.tables.trait_item_def_id.set_some(def_id.index, trait_item_def_id.into());
         }
         if impl_item.kind == ty::AssocKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
-            if tcx.is_intrinsic(def_id) {
-                self.tables.is_intrinsic.set_nullable(def_id.index, true);
-            }
+            self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
         }
     }
 
@@ -1522,14 +1521,12 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
 
         match item.kind {
             hir::ItemKind::Fn(ref sig, .., body) => {
-                self.tables.asyncness.set(def_id.index, sig.header.asyncness);
+                self.tables.asyncness.set_some(def_id.index, sig.header.asyncness);
                 record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
-                self.tables.constness.set(def_id.index, sig.header.constness);
+                self.tables.constness.set_some(def_id.index, sig.header.constness);
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
-                if macro_def.macro_rules {
-                    self.tables.is_macro_rules.set_nullable(def_id.index, true);
-                }
+                self.tables.is_macro_rules.set(def_id.index, macro_def.macro_rules);
                 record!(self.tables.macro_definition[def_id] <- &*macro_def.body);
             }
             hir::ItemKind::Mod(ref m) => {
@@ -1537,20 +1534,20 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
             }
             hir::ItemKind::OpaqueTy(ref opaque) => {
                 self.encode_explicit_item_bounds(def_id);
-                if matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) {
-                    self.tables.is_type_alias_impl_trait.set_nullable(def_id.index, true);
-                }
+                self.tables
+                    .is_type_alias_impl_trait
+                    .set(def_id.index, matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias));
             }
             hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
-                self.tables.impl_defaultness.set(def_id.index, *defaultness);
-                self.tables.constness.set(def_id.index, *constness);
+                self.tables.impl_defaultness.set_some(def_id.index, *defaultness);
+                self.tables.constness.set_some(def_id.index, *constness);
 
                 let trait_ref = self.tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::skip_binder);
                 if let Some(trait_ref) = trait_ref {
                     let trait_def = self.tcx.trait_def(trait_ref.def_id);
                     if let Ok(mut an) = trait_def.ancestors(self.tcx, def_id) {
                         if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) {
-                            self.tables.impl_parent.set(def_id.index, parent.into());
+                            self.tables.impl_parent.set_some(def_id.index, parent.into());
                         }
                     }
 
@@ -1564,7 +1561,7 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
                 }
 
                 let polarity = self.tcx.impl_polarity(def_id);
-                self.tables.impl_polarity.set(def_id.index, polarity);
+                self.tables.impl_polarity.set_some(def_id.index, polarity);
             }
             hir::ItemKind::Trait(..) => {
                 let trait_def = self.tcx.trait_def(def_id);
@@ -1601,9 +1598,7 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
         }
         if let hir::ItemKind::Fn(..) = item.kind {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
-            if tcx.is_intrinsic(def_id) {
-                self.tables.is_intrinsic.set_nullable(def_id.index, true);
-            }
+            self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
         }
         if let hir::ItemKind::Impl { .. } = item.kind {
             if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) {
@@ -1650,7 +1645,7 @@ fn encode_info_for_closure(&mut self, def_id: LocalDefId) {
 
             ty::Closure(_, substs) => {
                 let constness = self.tcx.constness(def_id.to_def_id());
-                self.tables.constness.set(def_id.to_def_id().index, constness);
+                self.tables.constness.set_some(def_id.to_def_id().index, constness);
                 record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder(substs.as_closure().sig()));
             }
 
@@ -1678,12 +1673,12 @@ fn encode_hygiene(&mut self) -> (SyntaxContextTable, ExpnDataTable, ExpnHashTabl
         self.hygiene_ctxt.encode(
             &mut (&mut *self, &mut syntax_contexts, &mut expn_data_table, &mut expn_hash_table),
             |(this, syntax_contexts, _, _), index, ctxt_data| {
-                syntax_contexts.set(index, this.lazy(ctxt_data));
+                syntax_contexts.set_some(index, this.lazy(ctxt_data));
             },
             |(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| {
                 if let Some(index) = index.as_local() {
-                    expn_data_table.set(index.as_raw(), this.lazy(expn_data));
-                    expn_hash_table.set(index.as_raw(), this.lazy(hash));
+                    expn_data_table.set_some(index.as_raw(), this.lazy(expn_data));
+                    expn_hash_table.set_some(index.as_raw(), this.lazy(hash));
                 }
             },
         );
@@ -1708,10 +1703,10 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
             let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans();
             for (i, span) in spans.into_iter().enumerate() {
                 let span = self.lazy(span);
-                self.tables.proc_macro_quoted_spans.set(i, span);
+                self.tables.proc_macro_quoted_spans.set_some(i, span);
             }
 
-            self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
+            self.tables.opt_def_kind.set_some(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
             record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
             self.encode_attrs(LOCAL_CRATE.as_def_id().expect_local());
             let vis = tcx.local_visibility(CRATE_DEF_ID).map_id(|def_id| def_id.local_def_index);
@@ -1753,8 +1748,8 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
                 def_key.disambiguated_data.data = DefPathData::MacroNs(name);
 
                 let def_id = id.to_def_id();
-                self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind));
-                self.tables.proc_macro.set(def_id.index, macro_kind);
+                self.tables.opt_def_kind.set_some(def_id.index, DefKind::Macro(macro_kind));
+                self.tables.proc_macro.set_some(def_id.index, macro_kind);
                 self.encode_attrs(id);
                 record!(self.tables.def_keys[def_id] <- def_key);
                 record!(self.tables.def_ident_span[def_id] <- span);
@@ -1969,7 +1964,7 @@ fn encode_dylib_dependency_formats(&mut self) -> LazyArray<Option<LinkagePrefere
                 Linkage::Static => Some(LinkagePreference::RequireStatic),
             }));
         }
-        LazyArray::empty()
+        LazyArray::default()
     }
 
     fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignItem<'_>) {
@@ -1979,22 +1974,20 @@ fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignIt
 
         match nitem.kind {
             hir::ForeignItemKind::Fn(_, ref names, _) => {
-                self.tables.asyncness.set(def_id.index, hir::IsAsync::NotAsync);
+                self.tables.asyncness.set_some(def_id.index, hir::IsAsync::NotAsync);
                 record_array!(self.tables.fn_arg_names[def_id] <- *names);
                 let constness = if self.tcx.is_const_fn_raw(def_id) {
                     hir::Constness::Const
                 } else {
                     hir::Constness::NotConst
                 };
-                self.tables.constness.set(def_id.index, constness);
+                self.tables.constness.set_some(def_id.index, constness);
                 record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
             }
             hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => {}
         }
         if let hir::ForeignItemKind::Fn(..) = nitem.kind {
-            if tcx.is_intrinsic(def_id) {
-                self.tables.is_intrinsic.set_nullable(def_id.index, true);
-            }
+            self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
         }
     }
 }
index 37af9e64e9a3da5002ee527d5b6f655d05366506..a74aa381d9eb829097c219163db4f04750a3d098 100644 (file)
@@ -115,14 +115,16 @@ impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyArray<T> {
     type Value<'tcx> = LazyArray<T::Value<'tcx>>;
 }
 
+impl<T> Default for LazyArray<T> {
+    fn default() -> LazyArray<T> {
+        LazyArray::from_position_and_num_elems(NonZeroUsize::new(1).unwrap(), 0)
+    }
+}
+
 impl<T> LazyArray<T> {
     fn from_position_and_num_elems(position: NonZeroUsize, num_elems: usize) -> LazyArray<T> {
         LazyArray { position, num_elems, _marker: PhantomData }
     }
-
-    fn empty() -> LazyArray<T> {
-        LazyArray::from_position_and_num_elems(NonZeroUsize::new(1).unwrap(), 0)
-    }
 }
 
 /// A list of lazily-decoded values, with the added capability of random access.
@@ -316,7 +318,7 @@ pub(crate) struct IncoherentImpls {
 /// Define `LazyTables` and `TableBuilders` at the same time.
 macro_rules! define_tables {
     (
-        - nullable: $($name1:ident: Table<$IDX1:ty, $T1:ty>,)+
+        - defaulted: $($name1:ident: Table<$IDX1:ty, $T1:ty>,)+
         - optional: $($name2:ident: Table<$IDX2:ty, $T2:ty>,)+
     ) => {
         #[derive(MetadataEncodable, MetadataDecodable)]
@@ -343,11 +345,15 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
 }
 
 define_tables! {
-- nullable:
+- defaulted:
     is_intrinsic: Table<DefIndex, bool>,
     is_macro_rules: Table<DefIndex, bool>,
     is_type_alias_impl_trait: Table<DefIndex, bool>,
     attr_flags: Table<DefIndex, AttrFlags>,
+    def_path_hashes: Table<DefIndex, DefPathHash>,
+    explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
+    inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
+    inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
 
 - optional:
     attributes: Table<DefIndex, LazyArray<ast::Attribute>>,
@@ -360,12 +366,8 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>,
     lookup_default_body_stability: Table<DefIndex, LazyValue<attr::DefaultBodyStability>>,
     lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
-    // As an optimization, a missing entry indicates an empty `&[]`.
-    explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
     explicit_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>,
     generics_of: Table<DefIndex, LazyValue<ty::Generics>>,
-    // As an optimization, a missing entry indicates an empty `&[]`.
-    inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     super_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>,
     type_of: Table<DefIndex, LazyValue<Ty<'static>>>,
     variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
@@ -393,7 +395,6 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     generator_kind: Table<DefIndex, LazyValue<hir::GeneratorKind>>,
     trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
     trait_item_def_id: Table<DefIndex, RawDefId>,
-    inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
     expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
     unused_generic_params: Table<DefIndex, LazyValue<UnusedGenericParams>>,
     params_in_repr: Table<DefIndex, LazyValue<BitSet<u32>>>,
@@ -403,7 +404,6 @@ fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
     // `DefPathTable` up front, since we may only ever use a few
     // definitions from any given crate.
     def_keys: Table<DefIndex, LazyValue<DefKey>>,
-    def_path_hashes: Table<DefIndex, DefPathHash>,
     proc_macro_quoted_spans: Table<usize, LazyValue<Span>>,
     generator_diagnostic_data: Table<DefIndex, LazyValue<GeneratorDiagnosticData<'static>>>,
     variant_data: Table<DefIndex, LazyValue<VariantData>>,
index 70dbf6476e2fab40d8c4a89b575528b3bd3f6f6b..99bec570600a0faae76c4afb1479ce834e1702c1 100644 (file)
 use std::marker::PhantomData;
 use std::num::NonZeroUsize;
 
+pub(super) trait IsDefault: Default {
+    fn is_default(&self) -> bool;
+}
+
+impl<T> IsDefault for Option<T> {
+    fn is_default(&self) -> bool {
+        self.is_none()
+    }
+}
+
+impl IsDefault for AttrFlags {
+    fn is_default(&self) -> bool {
+        self.is_empty()
+    }
+}
+
+impl IsDefault for bool {
+    fn is_default(&self) -> bool {
+        !self
+    }
+}
+
+impl IsDefault for u32 {
+    fn is_default(&self) -> bool {
+        *self == 0
+    }
+}
+
+impl<T> IsDefault for LazyArray<T> {
+    fn is_default(&self) -> bool {
+        self.num_elems == 0
+    }
+}
+
+impl IsDefault for DefPathHash {
+    fn is_default(&self) -> bool {
+        self.0 == Fingerprint::ZERO
+    }
+}
+
 /// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
 /// Used mainly for Lazy positions and lengths.
 /// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
 /// but this has no impact on safety.
-pub(super) trait FixedSizeEncoding: Default {
+pub(super) trait FixedSizeEncoding: IsDefault {
     /// This should be `[u8; BYTE_LEN]`;
     /// Cannot use an associated `const BYTE_LEN: usize` instead due to const eval limitations.
     type ByteArray;
@@ -23,6 +63,8 @@ pub(super) trait FixedSizeEncoding: Default {
     fn write_to_bytes(self, b: &mut Self::ByteArray);
 }
 
+/// This implementation is not used generically, but for reading/writing
+/// concrete `u32` fields in `Lazy*` structures, which may be zero.
 impl FixedSizeEncoding for u32 {
     type ByteArray = [u8; 4];
 
@@ -58,7 +100,7 @@ impl FixedSizeEncoding for Option<$ty> {
             fn write_to_bytes(self, b: &mut [u8;1]) {
                 use $ty::*;
                 b[0] = match self {
-                    None => 0,
+                    None => unreachable!(),
                     $(Some($($pat)*) => 1 + ${index()},)*
                 }
             }
@@ -155,20 +197,18 @@ impl FixedSizeEncoding for Option<$ty> {
 }
 
 // We directly encode `DefPathHash` because a `LazyValue` would incur a 25% cost.
-impl FixedSizeEncoding for Option<DefPathHash> {
+impl FixedSizeEncoding for DefPathHash {
     type ByteArray = [u8; 16];
 
     #[inline]
     fn from_bytes(b: &[u8; 16]) -> Self {
-        Some(DefPathHash(Fingerprint::from_le_bytes(*b)))
+        DefPathHash(Fingerprint::from_le_bytes(*b))
     }
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 16]) {
-        let Some(DefPathHash(fingerprint)) = self else {
-            panic!("Trying to encode absent DefPathHash.")
-        };
-        *b = fingerprint.to_le_bytes();
+        debug_assert!(!self.is_default());
+        *b = self.0.to_le_bytes();
     }
 }
 
@@ -179,17 +219,17 @@ impl FixedSizeEncoding for Option<RawDefId> {
     #[inline]
     fn from_bytes(b: &[u8; 8]) -> Self {
         let krate = u32::from_le_bytes(b[0..4].try_into().unwrap());
-        let index = u32::from_le_bytes(b[4..8].try_into().unwrap());
         if krate == 0 {
             return None;
         }
+        let index = u32::from_le_bytes(b[4..8].try_into().unwrap());
         Some(RawDefId { krate: krate - 1, index })
     }
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 8]) {
         match self {
-            None => *b = [0; 8],
+            None => unreachable!(),
             Some(RawDefId { krate, index }) => {
                 // CrateNum is less than `CrateNum::MAX_AS_U32`.
                 debug_assert!(krate < u32::MAX);
@@ -210,6 +250,7 @@ impl FixedSizeEncoding for AttrFlags {
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 1]) {
+        debug_assert!(!self.is_default());
         b[0] = self.bits();
     }
 }
@@ -224,6 +265,7 @@ impl FixedSizeEncoding for bool {
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 1]) {
+        debug_assert!(!self.is_default());
         b[0] = self as u8
     }
 }
@@ -242,34 +284,72 @@ impl<T> FixedSizeEncoding for Option<LazyValue<T>> {
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 4]) {
-        let position = self.map_or(0, |lazy| lazy.position.get());
+        match self {
+            None => unreachable!(),
+            Some(lazy) => {
+                let position = lazy.position.get();
+                let position: u32 = position.try_into().unwrap();
+                position.write_to_bytes(b)
+            }
+        }
+    }
+}
+
+impl<T> LazyArray<T> {
+    #[inline]
+    fn write_to_bytes_impl(self, b: &mut [u8; 8]) {
+        let ([position_bytes, meta_bytes],[])= b.as_chunks_mut::<4>() else { panic!() };
+
+        let position = self.position.get();
         let position: u32 = position.try_into().unwrap();
-        position.write_to_bytes(b)
+        position.write_to_bytes(position_bytes);
+
+        let len = self.num_elems;
+        let len: u32 = len.try_into().unwrap();
+        len.write_to_bytes(meta_bytes);
+    }
+
+    fn from_bytes_impl(position_bytes: &[u8; 4], meta_bytes: &[u8; 4]) -> Option<LazyArray<T>> {
+        let position = NonZeroUsize::new(u32::from_bytes(position_bytes) as usize)?;
+        let len = u32::from_bytes(meta_bytes) as usize;
+        Some(LazyArray::from_position_and_num_elems(position, len))
     }
 }
 
-impl<T> FixedSizeEncoding for Option<LazyArray<T>> {
+impl<T> FixedSizeEncoding for LazyArray<T> {
     type ByteArray = [u8; 8];
 
     #[inline]
     fn from_bytes(b: &[u8; 8]) -> Self {
-        let ([ref position_bytes, ref meta_bytes],[])= b.as_chunks::<4>() else { panic!() };
-        let position = NonZeroUsize::new(u32::from_bytes(position_bytes) as usize)?;
-        let len = u32::from_bytes(meta_bytes) as usize;
-        Some(LazyArray::from_position_and_num_elems(position, len))
+        let ([position_bytes, meta_bytes],[])= b.as_chunks::<4>() else { panic!() };
+        if *meta_bytes == [0; 4] {
+            return Default::default();
+        }
+        LazyArray::from_bytes_impl(position_bytes, meta_bytes).unwrap()
     }
 
     #[inline]
     fn write_to_bytes(self, b: &mut [u8; 8]) {
-        let ([ref mut position_bytes, ref mut meta_bytes],[])= b.as_chunks_mut::<4>() else { panic!() };
+        assert!(!self.is_default());
+        self.write_to_bytes_impl(b)
+    }
+}
 
-        let position = self.map_or(0, |lazy| lazy.position.get());
-        let position: u32 = position.try_into().unwrap();
-        position.write_to_bytes(position_bytes);
+impl<T> FixedSizeEncoding for Option<LazyArray<T>> {
+    type ByteArray = [u8; 8];
 
-        let len = self.map_or(0, |lazy| lazy.num_elems);
-        let len: u32 = len.try_into().unwrap();
-        len.write_to_bytes(meta_bytes);
+    #[inline]
+    fn from_bytes(b: &[u8; 8]) -> Self {
+        let ([position_bytes, meta_bytes],[])= b.as_chunks::<4>() else { panic!() };
+        LazyArray::from_bytes_impl(position_bytes, meta_bytes)
+    }
+
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 8]) {
+        match self {
+            None => unreachable!(),
+            Some(lazy) => lazy.write_to_bytes_impl(b),
+        }
     }
 }
 
@@ -289,20 +369,27 @@ impl<I: Idx, const N: usize, T> TableBuilder<I, Option<T>>
 where
     Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
 {
-    pub(crate) fn set(&mut self, i: I, value: T) {
-        self.set_nullable(i, Some(value))
+    pub(crate) fn set_some(&mut self, i: I, value: T) {
+        self.set(i, Some(value))
     }
 }
 
 impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]>> TableBuilder<I, T> {
-    pub(crate) fn set_nullable(&mut self, i: I, value: T) {
-        // FIXME(eddyb) investigate more compact encodings for sparse tables.
-        // On the PR @michaelwoerister mentioned:
-        // > Space requirements could perhaps be optimized by using the HAMT `popcnt`
-        // > trick (i.e. divide things into buckets of 32 or 64 items and then
-        // > store bit-masks of which item in each bucket is actually serialized).
-        self.blocks.ensure_contains_elem(i, || [0; N]);
-        value.write_to_bytes(&mut self.blocks[i]);
+    /// Sets the table value if it is not default.
+    /// ATTENTION: For optimization default values are simply ignored by this function, because
+    /// right now metadata tables never need to reset non-default values to default. If such need
+    /// arises in the future then a new method (e.g. `clear` or `reset`) will need to be introduced
+    /// for doing that explicitly.
+    pub(crate) fn set(&mut self, i: I, value: T) {
+        if !value.is_default() {
+            // FIXME(eddyb) investigate more compact encodings for sparse tables.
+            // On the PR @michaelwoerister mentioned:
+            // > Space requirements could perhaps be optimized by using the HAMT `popcnt`
+            // > trick (i.e. divide things into buckets of 32 or 64 items and then
+            // > store bit-masks of which item in each bucket is actually serialized).
+            self.blocks.ensure_contains_elem(i, || [0; N]);
+            value.write_to_bytes(&mut self.blocks[i]);
+        }
     }
 
     pub(crate) fn encode(&self, buf: &mut FileEncoder) -> LazyTable<I, T> {
@@ -331,10 +418,7 @@ pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(&self, metadata: M, i: I) ->
         let start = self.position.get();
         let bytes = &metadata.blob()[start..start + self.encoded_size];
         let (bytes, []) = bytes.as_chunks::<N>() else { panic!() };
-        match bytes.get(i.index()) {
-            Some(bytes) => FixedSizeEncoding::from_bytes(bytes),
-            None => FixedSizeEncoding::from_bytes(&[0; N]),
-        }
+        bytes.get(i.index()).map_or_else(Default::default, FixedSizeEncoding::from_bytes)
     }
 
     /// Size of the table in entries, including possible gaps.
index 6e130bbf7d8284403fccb3af90c7e1a229a08c86..d6f20a8fc06ec563f960c59e604c96b89464c2b7 100644 (file)
@@ -324,10 +324,8 @@ pub fn unchecked_rebind<W>(self, value: W) -> Canonical<'tcx, W> {
     }
 }
 
-pub type QueryOutlivesConstraint<'tcx> = (
-    ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>,
-    ConstraintCategory<'tcx>,
-);
+pub type QueryOutlivesConstraint<'tcx> =
+    (ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
 
 TrivialTypeTraversalAndLiftImpls! {
     for <'tcx> {
index bd9cd53e11578b2442d0a981d1c3b6dd7fe1a8a2..f22c0dbc60d9d0f6a7114f0db7f87b550737eaca 100644 (file)
@@ -430,8 +430,10 @@ pub enum ResourceExhaustionInfo {
     ///
     /// The exact limit is set by the `const_eval_limit` attribute.
     StepLimitReached,
-    /// There is not enough memory to perform an allocation.
+    /// There is not enough memory (on the host) to perform an allocation.
     MemoryExhausted,
+    /// The address space (of the target) is full.
+    AddressSpaceFull,
 }
 
 impl fmt::Display for ResourceExhaustionInfo {
@@ -447,6 +449,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             MemoryExhausted => {
                 write!(f, "tried to allocate more memory than available to compiler")
             }
+            AddressSpaceFull => {
+                write!(f, "there are no more free addresses in the address space")
+            }
         }
     }
 }
index 4cebe416354a928fd423f0cd4c56f68af5d3c253..0a16ede64991de8d36cd4adf23c1ac435a783e07 100644 (file)
     /// This is because the `hir_crate` query gives you access to all other items.
     /// To avoid this fate, do not call `tcx.hir().krate()`; instead,
     /// prefer wrappers like `tcx.visit_all_items_in_krate()`.
-    query hir_crate(key: ()) -> Crate<'tcx> {
+    query hir_crate(key: ()) -> &'tcx Crate<'tcx> {
         arena_cache
         eval_always
         desc { "getting the crate HIR" }
     }
 
     /// All items in the crate.
-    query hir_crate_items(_: ()) -> rustc_middle::hir::ModuleItems {
+    query hir_crate_items(_: ()) -> &'tcx rustc_middle::hir::ModuleItems {
         arena_cache
         eval_always
         desc { "getting HIR crate items" }
@@ -71,7 +71,7 @@
     ///
     /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`.
     /// Avoid calling this query directly.
-    query hir_module_items(key: LocalDefId) -> rustc_middle::hir::ModuleItems {
+    query hir_module_items(key: LocalDefId) -> &'tcx rustc_middle::hir::ModuleItems {
         arena_cache
         desc { |tcx| "getting HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
         cache_on_disk_if { true }
         separate_provide_extern
     }
 
-    query unsizing_params_for_adt(key: DefId) -> rustc_index::bit_set::BitSet<u32>
+    query unsizing_params_for_adt(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32>
     {
         arena_cache
         desc { |tcx|
 
     /// Maps from the `DefId` of an item (trait/struct/enum/fn) to its
     /// associated generics.
-    query generics_of(key: DefId) -> ty::Generics {
+    query generics_of(key: DefId) -> &'tcx ty::Generics {
         desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) }
         arena_cache
         cache_on_disk_if { key.is_local() }
     /// These are assembled from the following places:
     /// - `extern` blocks (depending on their `link` attributes)
     /// - the `libs` (`-l`) option
-    query native_libraries(_: CrateNum) -> Vec<NativeLib> {
+    query native_libraries(_: CrateNum) -> &'tcx Vec<NativeLib> {
         arena_cache
         desc { "looking up the native libraries of a linked crate" }
         separate_provide_extern
     }
 
-    query shallow_lint_levels_on(key: hir::OwnerId) -> rustc_middle::lint::ShallowLintLevelMap {
+    query shallow_lint_levels_on(key: hir::OwnerId) -> &'tcx rustc_middle::lint::ShallowLintLevelMap {
         eval_always // fetches `resolutions`
         arena_cache
         desc { |tcx| "looking up lint levels for `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
-    query lint_expectations(_: ()) -> Vec<(LintExpectationId, LintExpectation)> {
+    query lint_expectations(_: ()) -> &'tcx Vec<(LintExpectationId, LintExpectation)> {
         arena_cache
         desc { "computing `#[expect]`ed lints in this crate" }
     }
     }
 
     /// Set of param indexes for type params that are in the type's representation
-    query params_in_repr(key: DefId) -> rustc_index::bit_set::BitSet<u32> {
+    query params_in_repr(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32> {
         desc { "finding type parameters in the representation" }
         arena_cache
         no_hash
     }
 
     /// Create a THIR tree for debugging.
-    query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> String {
+    query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx String {
         no_hash
         arena_cache
         desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) }
     }
 
     /// Create a list-like THIR representation for debugging.
-    query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> String {
+    query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx String {
         no_hash
         arena_cache
         desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key.did.to_def_id()) }
     /// Set of all the `DefId`s in this crate that have MIR associated with
     /// them. This includes all the body owners, but also things like struct
     /// constructors.
-    query mir_keys(_: ()) -> rustc_data_structures::fx::FxIndexSet<LocalDefId> {
+    query mir_keys(_: ()) -> &'tcx rustc_data_structures::fx::FxIndexSet<LocalDefId> {
         arena_cache
         desc { "getting a list of all mir_keys" }
     }
 
     query symbols_for_closure_captures(
         key: (LocalDefId, LocalDefId)
-    ) -> Vec<rustc_span::Symbol> {
+    ) -> &'tcx Vec<rustc_span::Symbol> {
         arena_cache
         desc {
             |tcx| "finding symbols for captures of closure `{}` in `{}`",
         }
     }
 
-    query mir_generator_witnesses(key: DefId) -> mir::GeneratorLayout<'tcx> {
+    query mir_generator_witnesses(key: DefId) -> &'tcx mir::GeneratorLayout<'tcx> {
         arena_cache
         desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
 
     /// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
     /// MIR pass (assuming the -Cinstrument-coverage option is enabled).
-    query coverageinfo(key: ty::InstanceDef<'tcx>) -> mir::CoverageInfo {
+    query coverageinfo(key: ty::InstanceDef<'tcx>) -> &'tcx mir::CoverageInfo {
         desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key.def_id()) }
         arena_cache
     }
 
     /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the
     /// function was optimized out before codegen, and before being added to the Coverage Map.
-    query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> {
+    query covered_code_regions(key: DefId) -> &'tcx Vec<&'tcx mir::coverage::CodeRegion> {
         desc {
             |tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`",
             tcx.def_path_str(key)
         desc { "erasing regions from `{}`", ty }
     }
 
-    query wasm_import_module_map(_: CrateNum) -> FxHashMap<DefId, String> {
+    query wasm_import_module_map(_: CrateNum) -> &'tcx FxHashMap<DefId, String> {
         arena_cache
         desc { "getting wasm import module map" }
     }
         desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir().ty_param_name(key.1) }
     }
 
-    query trait_def(key: DefId) -> ty::TraitDef {
+    query trait_def(key: DefId) -> &'tcx ty::TraitDef {
         desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) }
         arena_cache
         cache_on_disk_if { key.is_local() }
     }
 
     /// Gets a map with the variance of every item; use `item_variance` instead.
-    query crate_variances(_: ()) -> ty::CrateVariancesMap<'tcx> {
+    query crate_variances(_: ()) -> &'tcx ty::CrateVariancesMap<'tcx> {
         arena_cache
         desc { "computing the variances for items in this crate" }
     }
     }
 
     /// Maps from thee `DefId` of a type to its (inferred) outlives.
-    query inferred_outlives_crate(_: ()) -> ty::CratePredicatesMap<'tcx> {
+    query inferred_outlives_crate(_: ()) -> &'tcx ty::CratePredicatesMap<'tcx> {
         arena_cache
         desc { "computing the inferred outlives predicates for items in this crate" }
     }
     }
 
     /// Maps from a trait item to the trait item "descriptor".
-    query associated_item(key: DefId) -> ty::AssocItem {
+    query associated_item(key: DefId) -> &'tcx ty::AssocItem {
         desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) }
         arena_cache
         cache_on_disk_if { key.is_local() }
     }
 
     /// Collects the associated items defined on a trait or impl.
-    query associated_items(key: DefId) -> ty::AssocItems<'tcx> {
+    query associated_items(key: DefId) -> &'tcx ty::AssocItems<'tcx> {
         arena_cache
         desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
     }
     ///
     /// The map returned for `tcx.impl_item_implementor_ids(impl_id)` would be
     ///`{ trait_f: impl_f, trait_g: impl_g }`
-    query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap<DefId, DefId> {
+    query impl_item_implementor_ids(impl_id: DefId) -> &'tcx FxHashMap<DefId, DefId> {
         arena_cache
         desc { |tcx| "comparing impl items against trait for `{}`", tcx.def_path_str(impl_id) }
     }
     ///
     /// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone) and
     /// their respective impl (i.e., part of the derive macro)
-    query live_symbols_and_ignored_derived_traits(_: ()) -> (
+    query live_symbols_and_ignored_derived_traits(_: ()) -> &'tcx (
         FxHashSet<LocalDefId>,
         FxHashMap<LocalDefId, Vec<(DefId, DefId)>>
     ) {
 
     /// Gets a complete map from all types to their inherent impls.
     /// Not meant to be used directly outside of coherence.
-    query crate_inherent_impls(k: ()) -> CrateInherentImpls {
+    query crate_inherent_impls(k: ()) -> &'tcx CrateInherentImpls {
         arena_cache
         desc { "finding all inherent impls defined in crate" }
     }
         desc { "checking for private elements in public interfaces" }
     }
 
-    query reachable_set(_: ()) -> FxHashSet<LocalDefId> {
+    query reachable_set(_: ()) -> &'tcx FxHashSet<LocalDefId> {
         arena_cache
         desc { "reachability" }
     }
     }
 
     /// Generates a MIR body for the shim.
-    query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> {
+    query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::Body<'tcx> {
         arena_cache
         desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
     }
         separate_provide_extern
     }
 
-    query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs {
+    query codegen_fn_attrs(def_id: DefId) -> &'tcx CodegenFnAttrs {
         desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) }
         arena_cache
         cache_on_disk_if { def_id.is_local() }
     }
     /// Gets the rendered value of the specified constant or associated constant.
     /// Used by rustdoc.
-    query rendered_const(def_id: DefId) -> String {
+    query rendered_const(def_id: DefId) -> &'tcx String {
         arena_cache
         desc { |tcx| "rendering constant initializer of `{}`", tcx.def_path_str(def_id) }
         cache_on_disk_if { def_id.is_local() }
     }
 
     /// Given a trait `trait_id`, return all known `impl` blocks.
-    query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls {
+    query trait_impls_of(trait_id: DefId) -> &'tcx ty::trait_def::TraitImpls {
         arena_cache
         desc { |tcx| "finding trait impls of `{}`", tcx.def_path_str(trait_id) }
     }
 
-    query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph {
+    query specialization_graph_of(trait_id: DefId) -> &'tcx specialization_graph::Graph {
         arena_cache
         desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
         cache_on_disk_if { true }
         separate_provide_extern
     }
 
-    query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> {
+    query dependency_formats(_: ()) -> &'tcx Lrc<crate::middle::dependency_format::Dependencies> {
         arena_cache
         desc { "getting the linkage format of all dependencies" }
     }
     // Does not include external symbols that don't have a corresponding DefId,
     // like the compiler-generated `main` function and so on.
     query reachable_non_generics(_: CrateNum)
-        -> DefIdMap<SymbolExportInfo> {
+        -> &'tcx DefIdMap<SymbolExportInfo> {
         arena_cache
         desc { "looking up the exported symbols of a crate" }
         separate_provide_extern
     /// added or removed in any upstream crate. Instead use the narrower
     /// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even
     /// better, `Instance::upstream_monomorphization()`.
-    query upstream_monomorphizations(_: ()) -> DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> {
+    query upstream_monomorphizations(_: ()) -> &'tcx DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> {
         arena_cache
         desc { "collecting available upstream monomorphizations" }
     }
     query upstream_monomorphizations_for(def_id: DefId)
         -> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>>
     {
-        arena_cache
         desc { |tcx|
             "collecting available upstream monomorphizations for `{}`",
             tcx.def_path_str(def_id),
     }
 
     /// Returns a list of all `extern` blocks of a crate.
-    query foreign_modules(_: CrateNum) -> FxHashMap<DefId, ForeignModule> {
+    query foreign_modules(_: CrateNum) -> &'tcx FxHashMap<DefId, ForeignModule> {
         arena_cache
         desc { "looking up the foreign modules of a linked crate" }
         separate_provide_extern
 
     /// Gets the extra data to put in each output filename for a crate.
     /// For example, compiling the `foo` crate with `extra-filename=-a` creates a `libfoo-b.rlib` file.
-    query extra_filename(_: CrateNum) -> String {
+    query extra_filename(_: CrateNum) -> &'tcx String {
         arena_cache
         eval_always
         desc { "looking up the extra filename for a crate" }
     }
 
     /// Gets the paths where the crate came from in the file system.
-    query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> {
+    query crate_extern_paths(_: CrateNum) -> &'tcx Vec<PathBuf> {
         arena_cache
         eval_always
         desc { "looking up the paths for extern crates" }
     /// Does lifetime resolution on items. Importantly, we can't resolve
     /// lifetimes directly on things like trait methods, because of trait params.
     /// See `rustc_resolve::late::lifetimes for details.
-    query resolve_lifetimes(_: hir::OwnerId) -> ResolveLifetimes {
+    query resolve_lifetimes(_: hir::OwnerId) -> &'tcx ResolveLifetimes {
         arena_cache
         desc { "resolving lifetimes" }
     }
         desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
     }
 
-    query lib_features(_: ()) -> LibFeatures {
+    query lib_features(_: ()) -> &'tcx LibFeatures {
         arena_cache
         desc { "calculating the lib features map" }
     }
         desc { "calculating the lib features defined in a crate" }
         separate_provide_extern
     }
-    query stability_implications(_: CrateNum) -> FxHashMap<Symbol, Symbol> {
+    query stability_implications(_: CrateNum) -> &'tcx FxHashMap<Symbol, Symbol> {
         arena_cache
         desc { "calculating the implications between `#[unstable]` features defined in a crate" }
         separate_provide_extern
         separate_provide_extern
     }
     /// Returns the lang items defined in another crate by loading it from metadata.
-    query get_lang_items(_: ()) -> LanguageItems {
+    query get_lang_items(_: ()) -> &'tcx LanguageItems {
         arena_cache
         eval_always
         desc { "calculating the lang items map" }
     }
 
     /// Returns all diagnostic items defined in all crates.
-    query all_diagnostic_items(_: ()) -> rustc_hir::diagnostic_items::DiagnosticItems {
+    query all_diagnostic_items(_: ()) -> &'tcx rustc_hir::diagnostic_items::DiagnosticItems {
         arena_cache
         eval_always
         desc { "calculating the diagnostic items map" }
     }
 
     /// Returns the diagnostic items defined in a crate.
-    query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems {
+    query diagnostic_items(_: CrateNum) -> &'tcx rustc_hir::diagnostic_items::DiagnosticItems {
         arena_cache
         desc { "calculating the diagnostic items map in a crate" }
         separate_provide_extern
         desc { "calculating the missing lang items in a crate" }
         separate_provide_extern
     }
-    query visible_parent_map(_: ()) -> DefIdMap<DefId> {
+    query visible_parent_map(_: ()) -> &'tcx DefIdMap<DefId> {
         arena_cache
         desc { "calculating the visible parent map" }
     }
-    query trimmed_def_paths(_: ()) -> FxHashMap<DefId, Symbol> {
+    query trimmed_def_paths(_: ()) -> &'tcx FxHashMap<DefId, Symbol> {
         arena_cache
         desc { "calculating trimmed def paths" }
     }
         desc { "seeing if we're missing an `extern crate` item for this crate" }
         separate_provide_extern
     }
-    query used_crate_source(_: CrateNum) -> Lrc<CrateSource> {
+    query used_crate_source(_: CrateNum) -> &'tcx Lrc<CrateSource> {
         arena_cache
         eval_always
         desc { "looking at the source for a crate" }
         separate_provide_extern
     }
     /// Returns the debugger visualizers defined for this crate.
-    query debugger_visualizers(_: CrateNum) -> Vec<rustc_span::DebuggerVisualizerFile> {
+    query debugger_visualizers(_: CrateNum) -> &'tcx Vec<rustc_span::DebuggerVisualizerFile> {
         arena_cache
         desc { "looking up the debugger visualizers for this crate" }
         separate_provide_extern
         desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
     }
 
-    query stability_index(_: ()) -> stability::Index {
+    query stability_index(_: ()) -> &'tcx stability::Index {
         arena_cache
         eval_always
         desc { "calculating the stability index for the local crate" }
     ///
     /// This query returns an `&Arc` because codegen backends need the value even after the `TyCtxt`
     /// has been destroyed.
-    query output_filenames(_: ()) -> Arc<OutputFilenames> {
+    query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> {
         feedable
         desc { "getting output filenames" }
         arena_cache
         remap_env_constness
     }
 
-    query supported_target_features(_: CrateNum) -> FxHashMap<String, Option<Symbol>> {
+    query supported_target_features(_: CrateNum) -> &'tcx FxHashMap<String, Option<Symbol>> {
         arena_cache
         eval_always
         desc { "looking up supported target features" }
     /// span) for an *existing* error. Therefore, it is best-effort, and may never handle
     /// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine,
     /// because the `ty::Ty`-based wfcheck is always run.
-    query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, traits::WellFormedLoc)) -> Option<traits::ObligationCause<'tcx>> {
+    query diagnostic_hir_wf_check(
+        key: (ty::Predicate<'tcx>, traits::WellFormedLoc)
+    ) -> &'tcx Option<traits::ObligationCause<'tcx>> {
         arena_cache
         eval_always
         no_hash
         desc { "performing HIR wf-checking for predicate `{:?}` at item `{:?}`", key.0, key.1 }
     }
 
-
     /// The list of backend features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
     /// `--target` and similar).
-    query global_backend_features(_: ()) -> Vec<String> {
+    query global_backend_features(_: ()) -> &'tcx Vec<String> {
         arena_cache
         eval_always
         desc { "computing the backend features for CLI flags" }
     }
 
-    query generator_diagnostic_data(key: DefId) -> Option<GeneratorDiagnosticData<'tcx>> {
+    query generator_diagnostic_data(key: DefId) -> &'tcx Option<GeneratorDiagnosticData<'tcx>> {
         arena_cache
         desc { |tcx| "looking up generator diagnostic data of `{}`", tcx.def_path_str(key) }
         separate_provide_extern
index cd9b927014077190b973197824728c565181329c..0a30ae9d0aa78522c461b8a6dff9c81d7e0b28e9 100644 (file)
@@ -193,6 +193,9 @@ fn suggest_removing_unsized_bound(
 }
 
 /// Suggest restricting a type param with a new bound.
+///
+/// If `span_to_replace` is provided, then that span will be replaced with the
+/// `constraint`. If one wasn't provided, then the full bound will be suggested.
 pub fn suggest_constraining_type_param(
     tcx: TyCtxt<'_>,
     generics: &hir::Generics<'_>,
@@ -200,12 +203,14 @@ pub fn suggest_constraining_type_param(
     param_name: &str,
     constraint: &str,
     def_id: Option<DefId>,
+    span_to_replace: Option<Span>,
 ) -> bool {
     suggest_constraining_type_params(
         tcx,
         generics,
         err,
         [(param_name, constraint, def_id)].into_iter(),
+        span_to_replace,
     )
 }
 
@@ -215,6 +220,7 @@ pub fn suggest_constraining_type_params<'a>(
     generics: &hir::Generics<'_>,
     err: &mut Diagnostic,
     param_names_and_constraints: impl Iterator<Item = (&'a str, &'a str, Option<DefId>)>,
+    span_to_replace: Option<Span>,
 ) -> bool {
     let mut grouped = FxHashMap::default();
     param_names_and_constraints.for_each(|(param_name, constraint, def_id)| {
@@ -253,7 +259,9 @@ pub fn suggest_constraining_type_params<'a>(
         let mut suggest_restrict = |span, bound_list_non_empty| {
             suggestions.push((
                 span,
-                if bound_list_non_empty {
+                if span_to_replace.is_some() {
+                    constraint.clone()
+                } else if bound_list_non_empty {
                     format!(" + {}", constraint)
                 } else {
                     format!(" {}", constraint)
@@ -262,6 +270,11 @@ pub fn suggest_constraining_type_params<'a>(
             ))
         };
 
+        if let Some(span) = span_to_replace {
+            suggest_restrict(span, true);
+            continue;
+        }
+
         // When the type parameter has been provided bounds
         //
         //    Message:
index cdcd6281f209bb4d25761ebb9e0a6cd9d1fac8f3..4c2855821384bcf4ed35bda7e3635eaacdcc1e7d 100644 (file)
@@ -818,125 +818,114 @@ fn ty_and_layout_pointee_info_at(
         let tcx = cx.tcx();
         let param_env = cx.param_env();
 
-        let pointee_info =
-            match *this.ty.kind() {
-                ty::RawPtr(mt) if offset.bytes() == 0 => {
-                    tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
-                        size: layout.size,
-                        align: layout.align.abi,
-                        safe: None,
-                    })
-                }
-                ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
-                    tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| {
-                        PointeeInfo { size: layout.size, align: layout.align.abi, safe: None }
-                    })
-                }
-                ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
-                    let kind = if tcx.sess.opts.optimize == OptLevel::No {
-                        // Use conservative pointer kind if not optimizing. This saves us the
-                        // Freeze/Unpin queries, and can save time in the codegen backend (noalias
-                        // attributes in LLVM have compile-time cost even in unoptimized builds).
-                        PointerKind::SharedMutable
-                    } else {
-                        match mt {
-                            hir::Mutability::Not => {
-                                if ty.is_freeze(tcx, cx.param_env()) {
-                                    PointerKind::Frozen
-                                } else {
-                                    PointerKind::SharedMutable
-                                }
-                            }
-                            hir::Mutability::Mut => {
-                                // References to self-referential structures should not be considered
-                                // noalias, as another pointer to the structure can be obtained, that
-                                // is not based-on the original reference. We consider all !Unpin
-                                // types to be potentially self-referential here.
-                                if ty.is_unpin(tcx, cx.param_env()) {
-                                    PointerKind::UniqueBorrowed
-                                } else {
-                                    PointerKind::UniqueBorrowedPinned
-                                }
-                            }
-                        }
-                    };
+        let pointee_info = match *this.ty.kind() {
+            ty::RawPtr(mt) if offset.bytes() == 0 => {
+                tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
+                    size: layout.size,
+                    align: layout.align.abi,
+                    safe: None,
+                })
+            }
+            ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
+                tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo {
+                    size: layout.size,
+                    align: layout.align.abi,
+                    safe: None,
+                })
+            }
+            ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
+                // Use conservative pointer kind if not optimizing. This saves us the
+                // Freeze/Unpin queries, and can save time in the codegen backend (noalias
+                // attributes in LLVM have compile-time cost even in unoptimized builds).
+                let optimize = tcx.sess.opts.optimize != OptLevel::No;
+                let kind = match mt {
+                    hir::Mutability::Not => PointerKind::SharedRef {
+                        frozen: optimize && ty.is_freeze(tcx, cx.param_env()),
+                    },
+                    hir::Mutability::Mut => PointerKind::MutableRef {
+                        unpin: optimize && ty.is_unpin(tcx, cx.param_env()),
+                    },
+                };
 
-                    tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
-                        size: layout.size,
-                        align: layout.align.abi,
-                        safe: Some(kind),
-                    })
-                }
+                tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
+                    size: layout.size,
+                    align: layout.align.abi,
+                    safe: Some(kind),
+                })
+            }
 
-                _ => {
-                    let mut data_variant = match this.variants {
-                        // Within the discriminant field, only the niche itself is
-                        // always initialized, so we only check for a pointer at its
-                        // offset.
-                        //
-                        // If the niche is a pointer, it's either valid (according
-                        // to its type), or null (which the niche field's scalar
-                        // validity range encodes). This allows using
-                        // `dereferenceable_or_null` for e.g., `Option<&T>`, and
-                        // this will continue to work as long as we don't start
-                        // using more niches than just null (e.g., the first page of
-                        // the address space, or unaligned pointers).
-                        Variants::Multiple {
-                            tag_encoding: TagEncoding::Niche { untagged_variant, .. },
-                            tag_field,
-                            ..
-                        } if this.fields.offset(tag_field) == offset => {
-                            Some(this.for_variant(cx, untagged_variant))
-                        }
-                        _ => Some(this),
-                    };
+            _ => {
+                let mut data_variant = match this.variants {
+                    // Within the discriminant field, only the niche itself is
+                    // always initialized, so we only check for a pointer at its
+                    // offset.
+                    //
+                    // If the niche is a pointer, it's either valid (according
+                    // to its type), or null (which the niche field's scalar
+                    // validity range encodes). This allows using
+                    // `dereferenceable_or_null` for e.g., `Option<&T>`, and
+                    // this will continue to work as long as we don't start
+                    // using more niches than just null (e.g., the first page of
+                    // the address space, or unaligned pointers).
+                    Variants::Multiple {
+                        tag_encoding: TagEncoding::Niche { untagged_variant, .. },
+                        tag_field,
+                        ..
+                    } if this.fields.offset(tag_field) == offset => {
+                        Some(this.for_variant(cx, untagged_variant))
+                    }
+                    _ => Some(this),
+                };
 
-                    if let Some(variant) = data_variant {
-                        // We're not interested in any unions.
-                        if let FieldsShape::Union(_) = variant.fields {
-                            data_variant = None;
-                        }
+                if let Some(variant) = data_variant {
+                    // We're not interested in any unions.
+                    if let FieldsShape::Union(_) = variant.fields {
+                        data_variant = None;
                     }
+                }
 
-                    let mut result = None;
-
-                    if let Some(variant) = data_variant {
-                        // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
-                        // (requires passing in the expected address space from the caller)
-                        let ptr_end = offset + Pointer(AddressSpace::DATA).size(cx);
-                        for i in 0..variant.fields.count() {
-                            let field_start = variant.fields.offset(i);
-                            if field_start <= offset {
-                                let field = variant.field(cx, i);
-                                result = field.to_result().ok().and_then(|field| {
-                                    if ptr_end <= field_start + field.size {
-                                        // We found the right field, look inside it.
-                                        let field_info =
-                                            field.pointee_info_at(cx, offset - field_start);
-                                        field_info
-                                    } else {
-                                        None
-                                    }
-                                });
-                                if result.is_some() {
-                                    break;
+                let mut result = None;
+
+                if let Some(variant) = data_variant {
+                    // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+                    // (requires passing in the expected address space from the caller)
+                    let ptr_end = offset + Pointer(AddressSpace::DATA).size(cx);
+                    for i in 0..variant.fields.count() {
+                        let field_start = variant.fields.offset(i);
+                        if field_start <= offset {
+                            let field = variant.field(cx, i);
+                            result = field.to_result().ok().and_then(|field| {
+                                if ptr_end <= field_start + field.size {
+                                    // We found the right field, look inside it.
+                                    let field_info =
+                                        field.pointee_info_at(cx, offset - field_start);
+                                    field_info
+                                } else {
+                                    None
                                 }
+                            });
+                            if result.is_some() {
+                                break;
                             }
                         }
                     }
+                }
 
-                    // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
-                    if let Some(ref mut pointee) = result {
-                        if let ty::Adt(def, _) = this.ty.kind() {
-                            if def.is_box() && offset.bytes() == 0 {
-                                pointee.safe = Some(PointerKind::UniqueOwned);
-                            }
+                // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
+                if let Some(ref mut pointee) = result {
+                    if let ty::Adt(def, _) = this.ty.kind() {
+                        if def.is_box() && offset.bytes() == 0 {
+                            let optimize = tcx.sess.opts.optimize != OptLevel::No;
+                            pointee.safe = Some(PointerKind::Box {
+                                unpin: optimize && this.ty.boxed_ty().is_unpin(tcx, cx.param_env()),
+                            });
                         }
                     }
-
-                    result
                 }
-            };
+
+                result
+            }
+        };
 
         debug!(
             "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
index 7151b79c5ab63f4b4b7ba8a56a4e5cd275320889..933aaadd62e1dd4a34dfc36410a192d904b2f259 100644 (file)
@@ -112,15 +112,15 @@ macro_rules! query_helper_param_ty {
     ($K:ty) => { $K };
 }
 
-macro_rules! query_storage {
-    ([][$K:ty, $V:ty]) => {
-        <<$K as Key>::CacheSelector as CacheSelector<'tcx, $V>>::Cache
+macro_rules! query_if_arena {
+    ([] $arena:ty, $no_arena:ty) => {
+        $no_arena
     };
-    ([(arena_cache) $($rest:tt)*][$K:ty, $V:ty]) => {
-        <<$K as Key>::CacheSelector as CacheSelector<'tcx, $V>>::ArenaCache
+    ([(arena_cache) $($rest:tt)*] $arena:ty, $no_arena:ty) => {
+        $arena
     };
-    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
-        query_storage!([$($modifiers)*][$($args)*])
+    ([$other:tt $($modifiers:tt)*]$($args:tt)*) => {
+        query_if_arena!([$($modifiers)*]$($args)*)
     };
 }
 
@@ -184,23 +184,30 @@ pub mod query_keys {
 
             $(pub type $name<'tcx> = $($K)*;)*
         }
-        #[allow(nonstandard_style, unused_lifetimes)]
+        #[allow(nonstandard_style, unused_lifetimes, unused_parens)]
         pub mod query_values {
             use super::*;
 
-            $(pub type $name<'tcx> = $V;)*
+            $(pub type $name<'tcx> = query_if_arena!([$($modifiers)*] <$V as Deref>::Target, $V);)*
         }
-        #[allow(nonstandard_style, unused_lifetimes)]
+        #[allow(nonstandard_style, unused_lifetimes, unused_parens)]
         pub mod query_storage {
             use super::*;
 
-            $(pub type $name<'tcx> = query_storage!([$($modifiers)*][$($K)*, $V]);)*
+            $(
+                pub type $name<'tcx> = query_if_arena!([$($modifiers)*]
+                    <<$($K)* as Key>::CacheSelector
+                        as CacheSelector<'tcx, <$V as Deref>::Target>>::ArenaCache,
+                    <<$($K)* as Key>::CacheSelector as CacheSelector<'tcx, $V>>::Cache
+                );
+            )*
         }
+
         #[allow(nonstandard_style, unused_lifetimes)]
         pub mod query_stored {
             use super::*;
 
-            $(pub type $name<'tcx> = <query_storage::$name<'tcx> as QueryStorage>::Stored;)*
+            $(pub type $name<'tcx> = $V;)*
         }
 
         #[derive(Default)]
@@ -226,7 +233,7 @@ impl<'tcx> TyCtxt<'tcx> {
             $($(#[$attr])*
             #[inline(always)]
             #[must_use]
-            pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'tcx>
+            pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V
             {
                 self.at(DUMMY_SP).$name(key)
             })*
@@ -235,7 +242,7 @@ pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'
         impl<'tcx> TyCtxtAt<'tcx> {
             $($(#[$attr])*
             #[inline(always)]
-            pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'tcx>
+            pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V
             {
                 let key = key.into_query_param();
                 opt_remap_env_constness!([$($modifiers)*][key]);
@@ -306,7 +313,7 @@ fn $name(
                 span: Span,
                 key: query_keys::$name<'tcx>,
                 mode: QueryMode,
-            ) -> Option<query_stored::$name<'tcx>>;)*
+            ) -> Option<$V>;)*
         }
     };
 }
@@ -328,7 +335,7 @@ macro_rules! define_feedable {
         $(impl<'tcx, K: IntoQueryParam<$($K)*> + Copy> TyCtxtFeed<'tcx, K> {
             $(#[$attr])*
             #[inline(always)]
-            pub fn $name(self, value: $V) -> query_stored::$name<'tcx> {
+            pub fn $name(self, value: query_values::$name<'tcx>) -> $V {
                 let key = self.key().into_query_param();
                 opt_remap_env_constness!([$($modifiers)*][key]);
 
index 3224e13f7af4bfe9da8c9fd3b045edadee2b5496..0d466bbe56e01d82b7d5550ca8dc2688495c3a0c 100644 (file)
@@ -1,5 +1,5 @@
 use crate::elaborate_drops::DropFlagState;
-use rustc_middle::mir::{self, Body, Location};
+use rustc_middle::mir::{self, Body, Location, Terminator, TerminatorKind};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_target::abi::VariantIdx;
 
@@ -194,6 +194,17 @@ pub fn drop_flag_effects_for_location<'tcx, F>(
         on_all_children_bits(tcx, body, move_data, path, |mpi| callback(mpi, DropFlagState::Absent))
     }
 
+    // Drop does not count as a move but we should still consider the variable uninitialized.
+    if let Some(Terminator { kind: TerminatorKind::Drop { place, .. }, .. }) =
+        body.stmt_at(loc).right()
+    {
+        if let LookupResult::Exact(mpi) = move_data.rev_lookup.find(place.as_ref()) {
+            on_all_children_bits(tcx, body, move_data, mpi, |mpi| {
+                callback(mpi, DropFlagState::Absent)
+            })
+        }
+    }
+
     debug!("drop_flag_effects: assignment for location({:?})", loc);
 
     for_location_inits(tcx, body, move_data, loc, |mpi| callback(mpi, DropFlagState::Present));
index 0195693a7cb0e6d9bf8639e83d8e96a5b59797a3..115c8afcce0cf7c15964bd53b175366c0ac6b7fd 100644 (file)
@@ -376,7 +376,8 @@ fn gather_terminator(&mut self, term: &Terminator<'tcx>) {
             | TerminatorKind::Resume
             | TerminatorKind::Abort
             | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Unreachable => {}
+            | TerminatorKind::Unreachable
+            | TerminatorKind::Drop { .. } => {}
 
             TerminatorKind::Assert { ref cond, .. } => {
                 self.gather_operand(cond);
@@ -391,10 +392,6 @@ fn gather_terminator(&mut self, term: &Terminator<'tcx>) {
                 self.create_move_path(place);
                 self.gather_init(place.as_ref(), InitKind::Deep);
             }
-
-            TerminatorKind::Drop { place, target: _, unwind: _ } => {
-                self.gather_move(place);
-            }
             TerminatorKind::DropAndReplace { place, ref value, .. } => {
                 self.create_move_path(place);
                 self.gather_operand(value);
index 8bf6493be4b0168ba6e78d8be9d0cbb7c038382c..a6ef2a742c8736219f84946e85a8e6e44ee2c544 100644 (file)
@@ -223,13 +223,13 @@ fn handle_terminator(&self, terminator: &Terminator<'tcx>, state: &mut State<Sel
         self.super_terminator(terminator, state)
     }
 
-    fn super_terminator(&self, terminator: &Terminator<'tcx>, _state: &mut State<Self::Value>) {
+    fn super_terminator(&self, terminator: &Terminator<'tcx>, state: &mut State<Self::Value>) {
         match &terminator.kind {
             TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => {
                 // Effect is applied by `handle_call_return`.
             }
-            TerminatorKind::Drop { .. } => {
-                // We don't track dropped places.
+            TerminatorKind::Drop { place, .. } => {
+                state.flood_with(place.as_ref(), self.map(), Self::Value::bottom());
             }
             TerminatorKind::DropAndReplace { .. } | TerminatorKind::Yield { .. } => {
                 // They would have an effect, but are not allowed in this phase.
index 4c7d45be0753e1944d25e60434463fb964a462b2..6e279232bcb48ce3e22ed586e0d9b6c96ec6dde9 100644 (file)
@@ -153,8 +153,9 @@ fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Loca
 
     fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
         if let Operand::Move(place) = *operand
-            && let Some(local) = place.as_local()
-            && !self.fully_moved.contains(local)
+            // A move out of a projection of a copy is equivalent to a copy of the original projection.
+            && !place.has_deref()
+            && !self.fully_moved.contains(place.local)
         {
             *operand = Operand::Copy(place);
         }
index 65f4956d23acd5e7722e75caf517269a838b21d7..c2ff8645635e01597ea6c0d55ece679df9e80f9f 100644 (file)
 use rustc_target::abi::VariantIdx;
 use std::fmt;
 
+/// During MIR building, Drop and DropAndReplace terminators are inserted in every place where a drop may occur.
+/// However, in this phase, the presence of these terminators does not guarantee that a destructor will run,
+/// as the target of the drop may be uninitialized.
+/// In general, the compiler cannot determine at compile time whether a destructor will run or not.
+///
+/// At a high level, this pass refines Drop and DropAndReplace to only run the destructor if the
+/// target is initialized. The way this is achievied is by inserting drop flags for every variable
+/// that may be dropped, and then using those flags to determine whether a destructor should run.
+/// This pass also removes DropAndReplace, replacing it with a Drop paired with an assign statement.
+/// Once this is complete, Drop terminators in the MIR correspond to a call to the "drop glue" or
+/// "drop shim" for the type of the dropped place.
+///
+/// This pass relies on dropped places having an associated move path, which is then used to determine
+/// the initialization status of the place and its descendants.
+/// It's worth noting that a MIR containing a Drop without an associated move path is probably ill formed,
+/// as it would allow running a destructor on a place behind a reference:
+///
+/// ```text
+// fn drop_term<T>(t: &mut T) {
+//     mir!(
+//         {
+//             Drop(*t, exit)
+//         }
+//         exit = {
+//             Return()
+//         }
+//     )
+// }
+/// ```
 pub struct ElaborateDrops;
 
 impl<'tcx> MirPass<'tcx> for ElaborateDrops {
index 47b2fd8f8f47a4d31da672b7e76c5de3b69d5d2f..9443ded704d63059c8ae48cdd7acc859876ecc74 100644 (file)
@@ -47,7 +47,7 @@ impl DepNodeIndex {
 }
 
 impl From<DepNodeIndex> for QueryInvocationId {
-    #[inline]
+    #[inline(always)]
     fn from(dep_node_index: DepNodeIndex) -> Self {
         QueryInvocationId(dep_node_index.as_u32())
     }
index ffc413d15f52b0528d7c294b554be089940df5fc..f59d71124ecbf4452d6ada8139d557ac3cfd2c10 100644 (file)
@@ -346,9 +346,7 @@ pub fn try_get_cached<Tcx, C>(tcx: Tcx, cache: &C, key: &C::Key) -> Option<C::St
 {
     match cache.lookup(&key) {
         Some((value, index)) => {
-            if std::intrinsics::unlikely(tcx.profiler().enabled()) {
-                tcx.profiler().query_cache_hit(index.into());
-            }
+            tcx.profiler().query_cache_hit(index.into());
             tcx.dep_graph().read_index(index);
             Some(value)
         }
@@ -408,9 +406,7 @@ fn try_execute_query<Q, Qcx>(
                 panic!("value must be in cache after waiting")
             };
 
-            if std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) {
-                qcx.dep_context().profiler().query_cache_hit(index.into());
-            }
+            qcx.dep_context().profiler().query_cache_hit(index.into());
             query_blocked_prof_timer.finish_with_query_invocation_id(index.into());
 
             (v, Some(index))
@@ -776,9 +772,7 @@ pub fn force_query<Q, Qcx, D>(qcx: Qcx, key: Q::Key, dep_node: DepNode<Qcx::DepK
     // Ensure that only one of them runs the query.
     let cache = Q::query_cache(qcx);
     if let Some((_, index)) = cache.lookup(&key) {
-        if std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) {
-            qcx.dep_context().profiler().query_cache_hit(index.into());
-        }
+        qcx.dep_context().profiler().query_cache_hit(index.into());
         return;
     }
 
index 7c5e1427d1ed72e9e7a8f45ad2c2e70cb8eef90e..cdda052f529067a27f4c82d49c04bef4a8d7df6e 100644 (file)
@@ -119,6 +119,12 @@ pub fn new(stable_crate_id: StableCrateId, local_hash: u64) -> DefPathHash {
     }
 }
 
+impl Default for DefPathHash {
+    fn default() -> Self {
+        DefPathHash(Fingerprint::ZERO)
+    }
+}
+
 impl Borrow<Fingerprint> for DefPathHash {
     #[inline]
     fn borrow(&self) -> &Fingerprint {
index f1119214be44db4e7d61615bfa9f488253c2f634..1ced75cccbb30251a3a7e918a63ca66e28a72498 100644 (file)
         plugins,
         pointee_trait,
         pointer,
-        pointer_sized,
+        pointer_like,
         poll,
         position,
         post_dash_lto: "post-lto",
index ccdf6246083cc59787129366e46b47c2748edd91..8525b96c0c21ffdf2927a63b6c2ab5822095bd3a 100644 (file)
@@ -128,9 +128,9 @@ fn consider_builtin_copy_clone_candidate(
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
-    // A type is `PointerSized` if we can compute its layout, and that layout
+    // A type is `PointerLike` if we can compute its layout, and that layout
     // matches the layout of `usize`.
-    fn consider_builtin_pointer_sized_candidate(
+    fn consider_builtin_pointer_like_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
@@ -312,8 +312,8 @@ fn assemble_builtin_impl_candidates<G: GoalKind<'tcx>>(
             || lang_items.clone_trait() == Some(trait_def_id)
         {
             G::consider_builtin_copy_clone_candidate(self, goal)
-        } else if lang_items.pointer_sized() == Some(trait_def_id) {
-            G::consider_builtin_pointer_sized_candidate(self, goal)
+        } else if lang_items.pointer_like() == Some(trait_def_id) {
+            G::consider_builtin_pointer_like_candidate(self, goal)
         } else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) {
             G::consider_builtin_fn_trait_candidates(self, goal, kind)
         } else if lang_items.tuple_trait() == Some(trait_def_id) {
index 9f62f686af647f2c1a3f6a314954e89dbd804c81..f9acf7a53eee5b25b95bd098d87a0a45f057ba0c 100644 (file)
@@ -370,11 +370,11 @@ fn consider_builtin_copy_clone_candidate(
         bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
     }
 
-    fn consider_builtin_pointer_sized_candidate(
+    fn consider_builtin_pointer_like_candidate(
         _ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        bug!("`PointerSized` does not have an associated type: {:?}", goal);
+        bug!("`PointerLike` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_fn_trait_candidates(
index 0003dfeaee78117ca8a4426dfa48a052808c4ab2..1cf1efc97049bcb740fa65217a2a18b5983d77fb 100644 (file)
@@ -131,7 +131,7 @@ fn consider_builtin_copy_clone_candidate(
         )
     }
 
-    fn consider_builtin_pointer_sized_candidate(
+    fn consider_builtin_pointer_like_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
index 87dbf7c3fd699b2649d36acb122d49de5a99676c..91da690a00056d58fc9fcfec0746d832c01de720 100644 (file)
@@ -679,6 +679,7 @@ fn suggest_restricting_param_bound(
                         &param_name,
                         &constraint,
                         Some(trait_pred.def_id()),
+                        None,
                     ) {
                         return;
                     }
@@ -1087,6 +1088,7 @@ fn suggest_add_clone_to_arg(
                     param.name.as_str(),
                     "Clone",
                     Some(clone_trait),
+                    None,
                 );
             }
             err.span_suggestion_verbose(
index 7b7abcf552ab7da31b513f5346fbad37e814113a..bba07ed965b210693badf57439a285fd71022fef 100644 (file)
@@ -94,7 +94,7 @@ pub(super) fn assemble_candidates<'o>(
                 self.assemble_candidates_for_transmutability(obligation, &mut candidates);
             } else if lang_items.tuple_trait() == Some(def_id) {
                 self.assemble_candidate_for_tuple(obligation, &mut candidates);
-            } else if lang_items.pointer_sized() == Some(def_id) {
+            } else if lang_items.pointer_like() == Some(def_id) {
                 self.assemble_candidate_for_ptr_sized(obligation, &mut candidates);
             } else {
                 if lang_items.clone_trait() == Some(def_id) {
index 1c74aeca5ab1fae38a6e6234c6ad7b40b292078b..ad5527f5a778b89bb11ba49c9f95c23f3b307491 100644 (file)
@@ -254,15 +254,18 @@ fn adjust_for_rust_scalar<'tcx>(
         if let Some(kind) = pointee.safe {
             attrs.pointee_align = Some(pointee.align);
 
-            // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable
-            // for the entire duration of the function as they can be deallocated
-            // at any time. Same for shared mutable references. If LLVM had a
-            // way to say "dereferenceable on entry" we could use it here.
+            // `Box` are not necessarily dereferenceable for the entire duration of the function as
+            // they can be deallocated at any time. Same for non-frozen shared references (see
+            // <https://github.com/rust-lang/rust/pull/98017>), and for mutable references to
+            // potentially self-referential types (see
+            // <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>). If LLVM had a way
+            // to say "dereferenceable on entry" we could use it here.
             attrs.pointee_size = match kind {
-                PointerKind::UniqueBorrowed
-                | PointerKind::UniqueBorrowedPinned
-                | PointerKind::Frozen => pointee.size,
-                PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO,
+                PointerKind::Box { .. }
+                | PointerKind::SharedRef { frozen: false }
+                | PointerKind::MutableRef { unpin: false } => Size::ZERO,
+                PointerKind::SharedRef { frozen: true }
+                | PointerKind::MutableRef { unpin: true } => pointee.size,
             };
 
             // The aliasing rules for `Box<T>` are still not decided, but currently we emit
@@ -275,18 +278,16 @@ fn adjust_for_rust_scalar<'tcx>(
             // versions at all anymore. We still support turning it off using -Zmutable-noalias.
             let noalias_mut_ref = cx.tcx.sess.opts.unstable_opts.mutable_noalias;
 
-            // `&mut` pointer parameters never alias other parameters,
-            // or mutable global data
+            // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as both
+            // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on memory
+            // dependencies rather than pointer equality. However this only applies to arguments,
+            // not return values.
             //
-            // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
-            // and can be marked as both `readonly` and `noalias`, as
-            // LLVM's definition of `noalias` is based solely on memory
-            // dependencies rather than pointer equality
+            // `&mut T` and `Box<T>` where `T: Unpin` are unique and hence `noalias`.
             let no_alias = match kind {
-                PointerKind::SharedMutable | PointerKind::UniqueBorrowedPinned => false,
-                PointerKind::UniqueBorrowed => noalias_mut_ref,
-                PointerKind::UniqueOwned => noalias_for_box,
-                PointerKind::Frozen => true,
+                PointerKind::SharedRef { frozen } => frozen,
+                PointerKind::MutableRef { unpin } => unpin && noalias_mut_ref,
+                PointerKind::Box { unpin } => unpin && noalias_for_box,
             };
             // 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>).
@@ -294,7 +295,7 @@ fn adjust_for_rust_scalar<'tcx>(
                 attrs.set(ArgAttribute::NoAlias);
             }
 
-            if kind == PointerKind::Frozen && !is_return {
+            if matches!(kind, PointerKind::SharedRef { frozen: true }) && !is_return {
                 attrs.set(ArgAttribute::ReadOnly);
             }
         }
index 424b52309d3af8bcc58bf1a1164d9a4f18c0839c..a6e0f13f69830350d8c55611c635841edc461212 100644 (file)
@@ -22,14 +22,17 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
         hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
             impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()),
         ),
-        hir::ItemKind::TraitAlias(..) => &[],
         _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
     }
 }
 
 fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
-    let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
-    ty::AssocItems::new(items)
+    if tcx.is_trait_alias(def_id) {
+        ty::AssocItems::new(Vec::new())
+    } else {
+        let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
+        ty::AssocItems::new(items)
+    }
 }
 
 fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap<DefId, DefId> {
index d5de457a82ce98ece71342abaa4d3ff6f0ee2225..4aa958878d4b304678644cd7eb50c5d92812371a 100644 (file)
@@ -220,7 +220,8 @@ pub struct TypeFlags: u32 {
                                           // which is different from how types/const are freshened.
                                           | TypeFlags::HAS_TY_FRESH.bits
                                           | TypeFlags::HAS_CT_FRESH.bits
-                                          | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
+                                          | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits
+                                          | TypeFlags::HAS_RE_ERASED.bits;
 
         /// Does this have `Projection`?
         const HAS_TY_PROJECTION           = 1 << 10;
index 016f139a501a00da5749e941e4c1d47df2fdaccb..000b9bd0fab42408a790d5b811c06f94385eba8a 100644 (file)
@@ -41,6 +41,28 @@ pub unsafe fn awaken(self) -> &'a mut T {
         // SAFETY: our own safety conditions imply this reference is again unique.
         unsafe { &mut *self.ptr.as_ptr() }
     }
+
+    /// Borrows a new mutable reference from the unique borrow initially captured.
+    ///
+    /// # Safety
+    ///
+    /// The reborrow must have ended, i.e., the reference returned by `new` and
+    /// all pointers and references derived from it, must not be used anymore.
+    pub unsafe fn reborrow(&mut self) -> &'a mut T {
+        // SAFETY: our own safety conditions imply this reference is again unique.
+        unsafe { &mut *self.ptr.as_ptr() }
+    }
+
+    /// Borrows a new shared reference from the unique borrow initially captured.
+    ///
+    /// # Safety
+    ///
+    /// The reborrow must have ended, i.e., the reference returned by `new` and
+    /// all pointers and references derived from it, must not be used anymore.
+    pub unsafe fn reborrow_shared(&self) -> &'a T {
+        // SAFETY: our own safety conditions imply this reference is again unique.
+        unsafe { &*self.ptr.as_ptr() }
+    }
 }
 
 #[cfg(test)]
index 1d9c4460ec92a9537f9b7cf8c86a634cc7829474..386cd1a1657e26f0dd9934dee92af16020cfe9fa 100644 (file)
@@ -6,7 +6,7 @@
 use core::iter::{FromIterator, FusedIterator};
 use core::marker::PhantomData;
 use core::mem::{self, ManuallyDrop};
-use core::ops::{Index, RangeBounds};
+use core::ops::{Bound, Index, RangeBounds};
 use core::ptr;
 
 use crate::alloc::{Allocator, Global};
@@ -15,7 +15,7 @@
 use super::dedup_sorted_iter::DedupSortedIter;
 use super::navigate::{LazyLeafRange, LeafRange};
 use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root};
-use super::search::SearchResult::*;
+use super::search::{SearchBound, SearchResult::*};
 use super::set_val::SetValZST;
 
 mod entry;
@@ -2422,6 +2422,732 @@ pub const fn len(&self) -> usize {
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
+
+    /// Returns a [`Cursor`] pointing at the first element that is above the
+    /// given bound.
+    ///
+    /// If no such element exists then a cursor pointing at the "ghost"
+    /// non-element is returned.
+    ///
+    /// Passing [`Bound::Unbounded`] will return a cursor pointing at the first
+    /// element of the map.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(btree_cursors)]
+    ///
+    /// use std::collections::BTreeMap;
+    /// use std::ops::Bound;
+    ///
+    /// let mut a = BTreeMap::new();
+    /// a.insert(1, "a");
+    /// a.insert(2, "b");
+    /// a.insert(3, "c");
+    /// a.insert(4, "c");
+    /// let cursor = a.lower_bound(Bound::Excluded(&2));
+    /// assert_eq!(cursor.key(), Some(&3));
+    /// ```
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn lower_bound<Q>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V>
+    where
+        K: Borrow<Q> + Ord,
+        Q: Ord,
+    {
+        let root_node = match self.root.as_ref() {
+            None => return Cursor { current: None, root: None },
+            Some(root) => root.reborrow(),
+        };
+        let edge = root_node.lower_bound(SearchBound::from_range(bound));
+        Cursor { current: edge.next_kv().ok(), root: self.root.as_ref() }
+    }
+
+    /// Returns a [`CursorMut`] pointing at the first element that is above the
+    /// given bound.
+    ///
+    /// If no such element exists then a cursor pointing at the "ghost"
+    /// non-element is returned.
+    ///
+    /// Passing [`Bound::Unbounded`] will return a cursor pointing at the first
+    /// element of the map.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(btree_cursors)]
+    ///
+    /// use std::collections::BTreeMap;
+    /// use std::ops::Bound;
+    ///
+    /// let mut a = BTreeMap::new();
+    /// a.insert(1, "a");
+    /// a.insert(2, "b");
+    /// a.insert(3, "c");
+    /// a.insert(4, "c");
+    /// let cursor = a.lower_bound_mut(Bound::Excluded(&2));
+    /// assert_eq!(cursor.key(), Some(&3));
+    /// ```
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn lower_bound_mut<Q>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A>
+    where
+        K: Borrow<Q> + Ord,
+        Q: Ord,
+    {
+        let (root, dormant_root) = DormantMutRef::new(&mut self.root);
+        let root_node = match root.as_mut() {
+            None => {
+                return CursorMut {
+                    current: None,
+                    root: dormant_root,
+                    length: &mut self.length,
+                    alloc: &mut *self.alloc,
+                };
+            }
+            Some(root) => root.borrow_mut(),
+        };
+        let edge = root_node.lower_bound(SearchBound::from_range(bound));
+        CursorMut {
+            current: edge.next_kv().ok(),
+            root: dormant_root,
+            length: &mut self.length,
+            alloc: &mut *self.alloc,
+        }
+    }
+
+    /// Returns a [`Cursor`] pointing at the last element that is below the
+    /// given bound.
+    ///
+    /// If no such element exists then a cursor pointing at the "ghost"
+    /// non-element is returned.
+    ///
+    /// Passing [`Bound::Unbounded`] will return a cursor pointing at the last
+    /// element of the map.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(btree_cursors)]
+    ///
+    /// use std::collections::BTreeMap;
+    /// use std::ops::Bound;
+    ///
+    /// let mut a = BTreeMap::new();
+    /// a.insert(1, "a");
+    /// a.insert(2, "b");
+    /// a.insert(3, "c");
+    /// a.insert(4, "c");
+    /// let cursor = a.upper_bound(Bound::Excluded(&3));
+    /// assert_eq!(cursor.key(), Some(&2));
+    /// ```
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn upper_bound<Q>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V>
+    where
+        K: Borrow<Q> + Ord,
+        Q: Ord,
+    {
+        let root_node = match self.root.as_ref() {
+            None => return Cursor { current: None, root: None },
+            Some(root) => root.reborrow(),
+        };
+        let edge = root_node.upper_bound(SearchBound::from_range(bound));
+        Cursor { current: edge.next_back_kv().ok(), root: self.root.as_ref() }
+    }
+
+    /// Returns a [`CursorMut`] pointing at the last element that is below the
+    /// given bound.
+    ///
+    /// If no such element exists then a cursor pointing at the "ghost"
+    /// non-element is returned.
+    ///
+    /// Passing [`Bound::Unbounded`] will return a cursor pointing at the last
+    /// element of the map.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(btree_cursors)]
+    ///
+    /// use std::collections::BTreeMap;
+    /// use std::ops::Bound;
+    ///
+    /// let mut a = BTreeMap::new();
+    /// a.insert(1, "a");
+    /// a.insert(2, "b");
+    /// a.insert(3, "c");
+    /// a.insert(4, "c");
+    /// let cursor = a.upper_bound_mut(Bound::Excluded(&3));
+    /// assert_eq!(cursor.key(), Some(&2));
+    /// ```
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn upper_bound_mut<Q>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A>
+    where
+        K: Borrow<Q> + Ord,
+        Q: Ord,
+    {
+        let (root, dormant_root) = DormantMutRef::new(&mut self.root);
+        let root_node = match root.as_mut() {
+            None => {
+                return CursorMut {
+                    current: None,
+                    root: dormant_root,
+                    length: &mut self.length,
+                    alloc: &mut *self.alloc,
+                };
+            }
+            Some(root) => root.borrow_mut(),
+        };
+        let edge = root_node.upper_bound(SearchBound::from_range(bound));
+        CursorMut {
+            current: edge.next_back_kv().ok(),
+            root: dormant_root,
+            length: &mut self.length,
+            alloc: &mut *self.alloc,
+        }
+    }
+}
+
+/// A cursor over a `BTreeMap`.
+///
+/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth.
+///
+/// Cursors always point to an element in the tree, and index in a logically circular way.
+/// To accommodate this, there is a "ghost" non-element that yields `None` between the last and
+/// first elements of the tree.
+///
+/// A `Cursor` is created with the [`BTreeMap::lower_bound`] and [`BTreeMap::upper_bound`] methods.
+#[unstable(feature = "btree_cursors", issue = "107540")]
+pub struct Cursor<'a, K: 'a, V: 'a> {
+    current: Option<Handle<NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>, marker::KV>>,
+    root: Option<&'a node::Root<K, V>>,
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl<K, V> Clone for Cursor<'_, K, V> {
+    fn clone(&self) -> Self {
+        let Cursor { current, root } = *self;
+        Cursor { current, root }
+    }
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl<K: Debug, V: Debug> Debug for Cursor<'_, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("Cursor").field(&self.key_value()).finish()
+    }
+}
+
+/// A cursor over a `BTreeMap` with editing operations.
+///
+/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can
+/// safely mutate the tree during iteration. This is because the lifetime of its yielded
+/// references is tied to its own lifetime, instead of just the underlying tree. This means
+/// cursors cannot yield multiple elements at once.
+///
+/// Cursors always point to an element in the tree, and index in a logically circular way.
+/// To accommodate this, there is a "ghost" non-element that yields `None` between the last and
+/// first elements of the tree.
+///
+/// A `Cursor` is created with the [`BTreeMap::lower_bound_mut`] and [`BTreeMap::upper_bound_mut`]
+/// methods.
+#[unstable(feature = "btree_cursors", issue = "107540")]
+pub struct CursorMut<
+    'a,
+    K: 'a,
+    V: 'a,
+    #[unstable(feature = "allocator_api", issue = "32838")] A = Global,
+> {
+    current: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>>,
+    root: DormantMutRef<'a, Option<node::Root<K, V>>>,
+    length: &'a mut usize,
+    alloc: &'a mut A,
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl<K: Debug, V: Debug, A> Debug for CursorMut<'_, K, V, A> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("CursorMut").field(&self.key_value()).finish()
+    }
+}
+
+impl<'a, K, V> Cursor<'a, K, V> {
+    /// Moves the cursor to the next element of the `BTreeMap`.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this will move it to
+    /// the first element of the `BTreeMap`. If it is pointing to the last
+    /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn move_next(&mut self) {
+        match self.current.take() {
+            None => {
+                self.current = self.root.and_then(|root| {
+                    root.reborrow().first_leaf_edge().forget_node_type().right_kv().ok()
+                });
+            }
+            Some(current) => {
+                self.current = current.next_leaf_edge().next_kv().ok();
+            }
+        }
+    }
+
+    /// Moves the cursor to the previous element of the `BTreeMap`.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this will move it to
+    /// the last element of the `BTreeMap`. If it is pointing to the first
+    /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn move_prev(&mut self) {
+        match self.current.take() {
+            None => {
+                self.current = self.root.and_then(|root| {
+                    root.reborrow().last_leaf_edge().forget_node_type().left_kv().ok()
+                });
+            }
+            Some(current) => {
+                self.current = current.next_back_leaf_edge().next_back_kv().ok();
+            }
+        }
+    }
+
+    /// Returns a reference to the key of the element that the cursor is
+    /// currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn key(&self) -> Option<&'a K> {
+        self.current.as_ref().map(|current| current.into_kv().0)
+    }
+
+    /// Returns a reference to the value of the element that the cursor is
+    /// currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn value(&self) -> Option<&'a V> {
+        self.current.as_ref().map(|current| current.into_kv().1)
+    }
+
+    /// Returns a reference to the key and value of the element that the cursor
+    /// is currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn key_value(&self) -> Option<(&'a K, &'a V)> {
+        self.current.as_ref().map(|current| current.into_kv())
+    }
+
+    /// Returns a reference to the next element.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this returns
+    /// the first element of the `BTreeMap`. If it is pointing to the last
+    /// element of the `BTreeMap` then this returns `None`.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn peek_next(&self) -> Option<(&'a K, &'a V)> {
+        let mut next = self.clone();
+        next.move_next();
+        next.current.as_ref().map(|current| current.into_kv())
+    }
+
+    /// Returns a reference to the previous element.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this returns
+    /// the last element of the `BTreeMap`. If it is pointing to the first
+    /// element of the `BTreeMap` then this returns `None`.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn peek_prev(&self) -> Option<(&'a K, &'a V)> {
+        let mut prev = self.clone();
+        prev.move_prev();
+        prev.current.as_ref().map(|current| current.into_kv())
+    }
+}
+
+impl<'a, K, V, A> CursorMut<'a, K, V, A> {
+    /// Moves the cursor to the next element of the `BTreeMap`.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this will move it to
+    /// the first element of the `BTreeMap`. If it is pointing to the last
+    /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn move_next(&mut self) {
+        match self.current.take() {
+            None => {
+                // SAFETY: The previous borrow of root has ended.
+                self.current = unsafe { self.root.reborrow() }.as_mut().and_then(|root| {
+                    root.borrow_mut().first_leaf_edge().forget_node_type().right_kv().ok()
+                });
+            }
+            Some(current) => {
+                self.current = current.next_leaf_edge().next_kv().ok();
+            }
+        }
+    }
+
+    /// Moves the cursor to the previous element of the `BTreeMap`.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this will move it to
+    /// the last element of the `BTreeMap`. If it is pointing to the first
+    /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn move_prev(&mut self) {
+        match self.current.take() {
+            None => {
+                // SAFETY: The previous borrow of root has ended.
+                self.current = unsafe { self.root.reborrow() }.as_mut().and_then(|root| {
+                    root.borrow_mut().last_leaf_edge().forget_node_type().left_kv().ok()
+                });
+            }
+            Some(current) => {
+                self.current = current.next_back_leaf_edge().next_back_kv().ok();
+            }
+        }
+    }
+
+    /// Returns a reference to the key of the element that the cursor is
+    /// currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn key(&self) -> Option<&K> {
+        self.current.as_ref().map(|current| current.reborrow().into_kv().0)
+    }
+
+    /// Returns a reference to the value of the element that the cursor is
+    /// currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn value(&self) -> Option<&V> {
+        self.current.as_ref().map(|current| current.reborrow().into_kv().1)
+    }
+
+    /// Returns a reference to the key and value of the element that the cursor
+    /// is currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn key_value(&self) -> Option<(&K, &V)> {
+        self.current.as_ref().map(|current| current.reborrow().into_kv())
+    }
+
+    /// Returns a mutable reference to the value of the element that the cursor
+    /// is currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn value_mut(&mut self) -> Option<&mut V> {
+        self.current.as_mut().map(|current| current.kv_mut().1)
+    }
+
+    /// Returns a reference to the key and mutable reference to the value of the
+    /// element that the cursor is currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn key_value_mut(&mut self) -> Option<(&K, &mut V)> {
+        self.current.as_mut().map(|current| {
+            let (k, v) = current.kv_mut();
+            (&*k, v)
+        })
+    }
+
+    /// Returns a mutable reference to the of the element that the cursor is
+    /// currently pointing to.
+    ///
+    /// This returns `None` if the cursor is currently pointing to the
+    /// "ghost" non-element.
+    ///
+    /// # Safety
+    ///
+    /// This can be used to modify the key, but you must ensure that the
+    /// `BTreeMap` invariants are maintained. Specifically:
+    ///
+    /// * The key must remain unique within the tree.
+    /// * The key must remain in sorted order with regards to other elements in
+    ///   the tree.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub unsafe fn key_mut_unchecked(&mut self) -> Option<&mut K> {
+        self.current.as_mut().map(|current| current.kv_mut().0)
+    }
+
+    /// Returns a reference to the key and value of the next element.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this returns
+    /// the first element of the `BTreeMap`. If it is pointing to the last
+    /// element of the `BTreeMap` then this returns `None`.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn peek_next(&mut self) -> Option<(&K, &mut V)> {
+        let (k, v) = match self.current {
+            None => {
+                // SAFETY: The previous borrow of root has ended.
+                unsafe { self.root.reborrow() }
+                    .as_mut()?
+                    .borrow_mut()
+                    .first_leaf_edge()
+                    .next_kv()
+                    .ok()?
+                    .into_kv_valmut()
+            }
+            // SAFETY: We're not using this to mutate the tree.
+            Some(ref mut current) => {
+                unsafe { current.reborrow_mut() }.next_leaf_edge().next_kv().ok()?.into_kv_valmut()
+            }
+        };
+        Some((k, v))
+    }
+
+    /// Returns a reference to the key and value of the previous element.
+    ///
+    /// If the cursor is pointing to the "ghost" non-element then this returns
+    /// the last element of the `BTreeMap`. If it is pointing to the first
+    /// element of the `BTreeMap` then this returns `None`.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn peek_prev(&mut self) -> Option<(&K, &mut V)> {
+        let (k, v) = match self.current.as_mut() {
+            None => {
+                // SAFETY: The previous borrow of root has ended.
+                unsafe { self.root.reborrow() }
+                    .as_mut()?
+                    .borrow_mut()
+                    .first_leaf_edge()
+                    .next_kv()
+                    .ok()?
+                    .into_kv_valmut()
+            }
+            Some(current) => {
+                // SAFETY: We're not using this to mutate the tree.
+                unsafe { current.reborrow_mut() }
+                    .next_back_leaf_edge()
+                    .next_back_kv()
+                    .ok()?
+                    .into_kv_valmut()
+            }
+        };
+        Some((k, v))
+    }
+
+    /// Returns a read-only cursor pointing to the current element.
+    ///
+    /// The lifetime of the returned `Cursor` is bound to that of the
+    /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the
+    /// `CursorMut` is frozen for the lifetime of the `Cursor`.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn as_cursor(&self) -> Cursor<'_, K, V> {
+        Cursor {
+            // SAFETY: The tree is immutable while the cursor exists.
+            root: unsafe { self.root.reborrow_shared().as_ref() },
+            current: self.current.as_ref().map(|current| current.reborrow()),
+        }
+    }
+}
+
+// Now the tree editing operations
+impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
+    /// Inserts a new element into the `BTreeMap` after the current one.
+    ///
+    /// If the cursor is pointing at the "ghost" non-element then the new element is
+    /// inserted at the front of the `BTreeMap`.
+    ///
+    /// # Safety
+    ///
+    /// You must ensure that the `BTreeMap` invariants are maintained.
+    /// Specifically:
+    ///
+    /// * The key of the newly inserted element must be unique in the tree.
+    /// * All keys in the tree must remain in sorted order.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub unsafe fn insert_after_unchecked(&mut self, key: K, value: V) {
+        let edge = match self.current.take() {
+            None => {
+                // SAFETY: We have no other reference to the tree.
+                match unsafe { self.root.reborrow() } {
+                    root @ None => {
+                        // Tree is empty, allocate a new root.
+                        let mut node = NodeRef::new_leaf(self.alloc.clone());
+                        node.borrow_mut().push(key, value);
+                        *root = Some(node.forget_type());
+                        *self.length += 1;
+                        return;
+                    }
+                    Some(root) => root.borrow_mut().first_leaf_edge(),
+                }
+            }
+            Some(current) => current.next_leaf_edge(),
+        };
+
+        let handle = edge.insert_recursing(key, value, self.alloc.clone(), |ins| {
+            drop(ins.left);
+            // SAFETY: The handle to the newly inserted value is always on a
+            // leaf node, so adding a new root node doesn't invalidate it.
+            let root = unsafe { self.root.reborrow().as_mut().unwrap() };
+            root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right)
+        });
+        self.current = handle.left_edge().next_back_kv().ok();
+        *self.length += 1;
+    }
+
+    /// Inserts a new element into the `BTreeMap` before the current one.
+    ///
+    /// If the cursor is pointing at the "ghost" non-element then the new element is
+    /// inserted at the end of the `BTreeMap`.
+    ///
+    /// # Safety
+    ///
+    /// You must ensure that the `BTreeMap` invariants are maintained.
+    /// Specifically:
+    ///
+    /// * The key of the newly inserted element must be unique in the tree.
+    /// * All keys in the tree must remain in sorted order.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub unsafe fn insert_before_unchecked(&mut self, key: K, value: V) {
+        let edge = match self.current.take() {
+            None => {
+                // SAFETY: We have no other reference to the tree.
+                match unsafe { self.root.reborrow() } {
+                    root @ None => {
+                        // Tree is empty, allocate a new root.
+                        let mut node = NodeRef::new_leaf(self.alloc.clone());
+                        node.borrow_mut().push(key, value);
+                        *root = Some(node.forget_type());
+                        *self.length += 1;
+                        return;
+                    }
+                    Some(root) => root.borrow_mut().last_leaf_edge(),
+                }
+            }
+            Some(current) => current.next_back_leaf_edge(),
+        };
+
+        let handle = edge.insert_recursing(key, value, self.alloc.clone(), |ins| {
+            drop(ins.left);
+            // SAFETY: The handle to the newly inserted value is always on a
+            // leaf node, so adding a new root node doesn't invalidate it.
+            let root = unsafe { self.root.reborrow().as_mut().unwrap() };
+            root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right)
+        });
+        self.current = handle.right_edge().next_kv().ok();
+        *self.length += 1;
+    }
+
+    /// Inserts a new element into the `BTreeMap` after the current one.
+    ///
+    /// If the cursor is pointing at the "ghost" non-element then the new element is
+    /// inserted at the front of the `BTreeMap`.
+    ///
+    /// # Panics
+    ///
+    /// This function panics if:
+    /// - the given key compares less than or equal to the current element (if
+    ///   any).
+    /// - the given key compares greater than or equal to the next element (if
+    ///   any).
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn insert_after(&mut self, key: K, value: V) {
+        if let Some(current) = self.key() {
+            if &key <= current {
+                panic!("key must be ordered above the current element");
+            }
+        }
+        if let Some((next, _)) = self.peek_prev() {
+            if &key >= next {
+                panic!("key must be ordered below the next element");
+            }
+        }
+        unsafe {
+            self.insert_after_unchecked(key, value);
+        }
+    }
+
+    /// Inserts a new element into the `BTreeMap` before the current one.
+    ///
+    /// If the cursor is pointing at the "ghost" non-element then the new element is
+    /// inserted at the end of the `BTreeMap`.
+    ///
+    /// # Panics
+    ///
+    /// This function panics if:
+    /// - the given key compares greater than or equal to the current element
+    ///   (if any).
+    /// - the given key compares less than or equal to the previous element (if
+    ///   any).
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn insert_before(&mut self, key: K, value: V) {
+        if let Some(current) = self.key() {
+            if &key >= current {
+                panic!("key must be ordered below the current element");
+            }
+        }
+        if let Some((prev, _)) = self.peek_prev() {
+            if &key <= prev {
+                panic!("key must be ordered above the previous element");
+            }
+        }
+        unsafe {
+            self.insert_before_unchecked(key, value);
+        }
+    }
+
+    /// Removes the current element from the `BTreeMap`.
+    ///
+    /// The element that was removed is returned, and the cursor is
+    /// moved to point to the next element in the `BTreeMap`.
+    ///
+    /// If the cursor is currently pointing to the "ghost" non-element then no element
+    /// is removed and `None` is returned. The cursor is not moved in this case.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn remove_current(&mut self) -> Option<(K, V)> {
+        let current = self.current.take()?;
+        let mut emptied_internal_root = false;
+        let (kv, pos) =
+            current.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone());
+        self.current = pos.next_kv().ok();
+        *self.length -= 1;
+        if emptied_internal_root {
+            // SAFETY: This is safe since current does not point within the now
+            // empty root node.
+            let root = unsafe { self.root.reborrow().as_mut().unwrap() };
+            root.pop_internal_level(self.alloc.clone());
+        }
+        Some(kv)
+    }
+
+    /// Removes the current element from the `BTreeMap`.
+    ///
+    /// The element that was removed is returned, and the cursor is
+    /// moved to point to the previous element in the `BTreeMap`.
+    ///
+    /// If the cursor is currently pointing to the "ghost" non-element then no element
+    /// is removed and `None` is returned. The cursor is not moved in this case.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn remove_current_and_move_back(&mut self) -> Option<(K, V)> {
+        let current = self.current.take()?;
+        let mut emptied_internal_root = false;
+        let (kv, pos) =
+            current.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone());
+        self.current = pos.next_back_kv().ok();
+        *self.length -= 1;
+        if emptied_internal_root {
+            // SAFETY: This is safe since current does not point within the now
+            // empty root node.
+            let root = unsafe { self.root.reborrow().as_mut().unwrap() };
+            root.pop_internal_level(self.alloc.clone());
+        }
+        Some(kv)
+    }
 }
 
 #[cfg(test)]
index 370b58864af8f3f4f9d1d2c3af7bd054331f3c79..e9366eec9cec3028a05635b62672beed4602f5d3 100644 (file)
@@ -347,7 +347,7 @@ pub fn into_key(self) -> K {
     /// assert_eq!(map["poneyland"], 37);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn insert(self, value: V) -> &'a mut V {
+    pub fn insert(mut self, value: V) -> &'a mut V {
         let out_ptr = match self.handle {
             None => {
                 // SAFETY: There is no tree yet so no reference to it exists.
@@ -358,25 +358,27 @@ pub fn insert(self, value: V) -> &'a mut V {
                 map.length = 1;
                 val_ptr
             }
-            Some(handle) => match handle.insert_recursing(self.key, value, self.alloc.clone()) {
-                (None, val_ptr) => {
-                    // SAFETY: We have consumed self.handle.
-                    let map = unsafe { self.dormant_map.awaken() };
-                    map.length += 1;
-                    val_ptr
-                }
-                (Some(ins), val_ptr) => {
-                    drop(ins.left);
-                    // SAFETY: We have consumed self.handle and dropped the
-                    // remaining reference to the tree, ins.left.
-                    let map = unsafe { self.dormant_map.awaken() };
-                    let root = map.root.as_mut().unwrap(); // same as ins.left
-                    root.push_internal_level(self.alloc).push(ins.kv.0, ins.kv.1, ins.right);
-                    map.length += 1;
-                    val_ptr
-                }
-            },
+            Some(handle) => {
+                let new_handle =
+                    handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| {
+                        drop(ins.left);
+                        // SAFETY: Pushing a new root node doesn't invalidate
+                        // handles to existing nodes.
+                        let map = unsafe { self.dormant_map.reborrow() };
+                        let root = map.root.as_mut().unwrap(); // same as ins.left
+                        root.push_internal_level(self.alloc).push(ins.kv.0, ins.kv.1, ins.right)
+                    });
+
+                // Get the pointer to the value
+                let val_ptr = new_handle.into_val_mut();
+
+                // SAFETY: We have consumed self.handle.
+                let map = unsafe { self.dormant_map.awaken() };
+                map.length += 1;
+                val_ptr
+            }
         };
+
         // Now that we have finished growing the tree using borrowed references,
         // dereference the pointer to a part of it, that we picked up along the way.
         unsafe { &mut *out_ptr }
index 700b1463bfd51f961e8b7bb2cb43e991c9473d4e..76c2f27b46634a885a663a6ba53595a74f79702c 100644 (file)
@@ -2336,3 +2336,52 @@ fn from_array() {
     let unordered_duplicates = BTreeMap::from([(3, 4), (1, 2), (1, 2)]);
     assert_eq!(map, unordered_duplicates);
 }
+
+#[test]
+fn test_cursor() {
+    let map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
+
+    let mut cur = map.lower_bound(Bound::Unbounded);
+    assert_eq!(cur.key(), Some(&1));
+    cur.move_next();
+    assert_eq!(cur.key(), Some(&2));
+    assert_eq!(cur.peek_next(), Some((&3, &'c')));
+    cur.move_prev();
+    assert_eq!(cur.key(), Some(&1));
+    assert_eq!(cur.peek_prev(), None);
+
+    let mut cur = map.upper_bound(Bound::Excluded(&1));
+    assert_eq!(cur.key(), None);
+    cur.move_next();
+    assert_eq!(cur.key(), Some(&1));
+    cur.move_prev();
+    assert_eq!(cur.key(), None);
+    assert_eq!(cur.peek_prev(), Some((&3, &'c')));
+}
+
+#[test]
+fn test_cursor_mut() {
+    let mut map = BTreeMap::from([(1, 'a'), (3, 'c'), (5, 'e')]);
+    let mut cur = map.lower_bound_mut(Bound::Excluded(&3));
+    assert_eq!(cur.key(), Some(&5));
+    cur.insert_before(4, 'd');
+    assert_eq!(cur.key(), Some(&5));
+    assert_eq!(cur.peek_prev(), Some((&4, &mut 'd')));
+    cur.move_next();
+    assert_eq!(cur.key(), None);
+    cur.insert_before(6, 'f');
+    assert_eq!(cur.key(), None);
+    assert_eq!(cur.remove_current(), None);
+    assert_eq!(cur.key(), None);
+    cur.insert_after(0, '?');
+    assert_eq!(cur.key(), None);
+    assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f')]));
+
+    let mut cur = map.upper_bound_mut(Bound::Included(&5));
+    assert_eq!(cur.key(), Some(&5));
+    assert_eq!(cur.remove_current(), Some((5, 'e')));
+    assert_eq!(cur.key(), Some(&6));
+    assert_eq!(cur.remove_current_and_move_back(), Some((6, 'f')));
+    assert_eq!(cur.key(), Some(&4));
+    assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd')]));
+}
index 1e33c1e64d66e085a09cc51b86210556d92f4b11..b890717e50b2544b62dfbc73312ba9e975db3225 100644 (file)
@@ -4,6 +4,7 @@
 use core::ptr;
 
 use super::node::{marker, ForceResult::*, Handle, NodeRef};
+use super::search::SearchBound;
 
 use crate::alloc::Allocator;
 // `front` and `back` are always both `None` or both `Some`.
@@ -386,7 +387,7 @@ pub fn next_kv(
     /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV
     /// on the left side, which is either in the same leaf node or in an ancestor node.
     /// If the leaf edge is the first one in the tree, returns [`Result::Err`] with the root node.
-    fn next_back_kv(
+    pub fn next_back_kv(
         self,
     ) -> Result<
         Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>,
@@ -707,7 +708,9 @@ pub fn next_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, m
     }
 
     /// Returns the leaf edge closest to a KV for backward navigation.
-    fn next_back_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
+    pub fn next_back_leaf_edge(
+        self,
+    ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
         match self.force() {
             Leaf(leaf_kv) => leaf_kv.left_edge(),
             Internal(internal_kv) => {
@@ -717,3 +720,51 @@ fn next_back_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>,
         }
     }
 }
+
+impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
+    /// Returns the leaf edge corresponding to the first point at which the
+    /// given bound is true.
+    pub fn lower_bound<Q: ?Sized>(
+        self,
+        mut bound: SearchBound<&Q>,
+    ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>
+    where
+        Q: Ord,
+        K: Borrow<Q>,
+    {
+        let mut node = self;
+        loop {
+            let (edge, new_bound) = node.find_lower_bound_edge(bound);
+            match edge.force() {
+                Leaf(edge) => return edge,
+                Internal(edge) => {
+                    node = edge.descend();
+                    bound = new_bound;
+                }
+            }
+        }
+    }
+
+    /// Returns the leaf edge corresponding to the last point at which the
+    /// given bound is true.
+    pub fn upper_bound<Q: ?Sized>(
+        self,
+        mut bound: SearchBound<&Q>,
+    ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>
+    where
+        Q: Ord,
+        K: Borrow<Q>,
+    {
+        let mut node = self;
+        loop {
+            let (edge, new_bound) = node.find_upper_bound_edge(bound);
+            match edge.force() {
+                Leaf(edge) => return edge,
+                Internal(edge) => {
+                    node = edge.descend();
+                    bound = new_bound;
+                }
+            }
+        }
+    }
+}
index 6912466448fab444c6860425ba5970a41ef75a8b..3233a575ecf254e73fe18c3d55679716d276f96c 100644 (file)
@@ -442,6 +442,24 @@ fn into_leaf_mut(mut self) -> &'a mut LeafNode<K, V> {
         // SAFETY: we have exclusive access to the entire node.
         unsafe { &mut *ptr }
     }
+
+    /// Returns a dormant copy of this node with its lifetime erased which can
+    /// be reawakened later.
+    pub fn dormant(&self) -> NodeRef<marker::DormantMut, K, V, Type> {
+        NodeRef { height: self.height, node: self.node, _marker: PhantomData }
+    }
+}
+
+impl<K, V, Type> NodeRef<marker::DormantMut, K, V, Type> {
+    /// Revert to the unique borrow initially captured.
+    ///
+    /// # Safety
+    ///
+    /// The reborrow must have ended, i.e., the reference returned by `new` and
+    /// all pointers and references derived from it, must not be used anymore.
+    pub unsafe fn awaken<'a>(self) -> NodeRef<marker::Mut<'a>, K, V, Type> {
+        NodeRef { height: self.height, node: self.node, _marker: PhantomData }
+    }
 }
 
 impl<K, V, Type> NodeRef<marker::Dying, K, V, Type> {
@@ -798,6 +816,25 @@ pub unsafe fn reborrow_mut(
         // We can't use Handle::new_kv or Handle::new_edge because we don't know our type
         Handle { node: unsafe { self.node.reborrow_mut() }, idx: self.idx, _marker: PhantomData }
     }
+
+    /// Returns a dormant copy of this handle which can be reawakened later.
+    ///
+    /// See `DormantMutRef` for more details.
+    pub fn dormant(&self) -> Handle<NodeRef<marker::DormantMut, K, V, NodeType>, HandleType> {
+        Handle { node: self.node.dormant(), idx: self.idx, _marker: PhantomData }
+    }
+}
+
+impl<K, V, NodeType, HandleType> Handle<NodeRef<marker::DormantMut, K, V, NodeType>, HandleType> {
+    /// Revert to the unique borrow initially captured.
+    ///
+    /// # Safety
+    ///
+    /// The reborrow must have ended, i.e., the reference returned by `new` and
+    /// all pointers and references derived from it, must not be used anymore.
+    pub unsafe fn awaken<'a>(self) -> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, HandleType> {
+        Handle { node: unsafe { self.node.awaken() }, idx: self.idx, _marker: PhantomData }
+    }
 }
 
 impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, marker::Edge> {
@@ -851,9 +888,11 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
     /// Inserts a new key-value pair between the key-value pairs to the right and left of
     /// this edge. This method assumes that there is enough space in the node for the new
     /// pair to fit.
-    ///
-    /// The returned pointer points to the inserted value.
-    fn insert_fit(&mut self, key: K, val: V) -> *mut V {
+    unsafe fn insert_fit(
+        mut self,
+        key: K,
+        val: V,
+    ) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> {
         debug_assert!(self.node.len() < CAPACITY);
         let new_len = self.node.len() + 1;
 
@@ -862,7 +901,7 @@ fn insert_fit(&mut self, key: K, val: V) -> *mut V {
             slice_insert(self.node.val_area_mut(..new_len), self.idx, val);
             *self.node.len_mut() = new_len as u16;
 
-            self.node.val_area_mut(self.idx).assume_init_mut()
+            Handle::new_kv(self.node, self.idx)
         }
     }
 }
@@ -871,21 +910,26 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
     /// Inserts a new key-value pair between the key-value pairs to the right and left of
     /// this edge. This method splits the node if there isn't enough room.
     ///
-    /// The returned pointer points to the inserted value.
+    /// Returns a dormant handle to the inserted node which can be reawakened
+    /// once splitting is complete.
     fn insert<A: Allocator + Clone>(
-        mut self,
+        self,
         key: K,
         val: V,
         alloc: A,
-    ) -> (Option<SplitResult<'a, K, V, marker::Leaf>>, *mut V) {
+    ) -> (
+        Option<SplitResult<'a, K, V, marker::Leaf>>,
+        Handle<NodeRef<marker::DormantMut, K, V, marker::Leaf>, marker::KV>,
+    ) {
         if self.node.len() < CAPACITY {
-            let val_ptr = self.insert_fit(key, val);
-            (None, val_ptr)
+            // SAFETY: There is enough space in the node for insertion.
+            let handle = unsafe { self.insert_fit(key, val) };
+            (None, handle.dormant())
         } else {
             let (middle_kv_idx, insertion) = splitpoint(self.idx);
             let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
             let mut result = middle.split(alloc);
-            let mut insertion_edge = match insertion {
+            let insertion_edge = match insertion {
                 LeftOrRight::Left(insert_idx) => unsafe {
                     Handle::new_edge(result.left.reborrow_mut(), insert_idx)
                 },
@@ -893,8 +937,10 @@ fn insert<A: Allocator + Clone>(
                     Handle::new_edge(result.right.borrow_mut(), insert_idx)
                 },
             };
-            let val_ptr = insertion_edge.insert_fit(key, val);
-            (Some(result), val_ptr)
+            // SAFETY: We just split the node, so there is enough space for
+            // insertion.
+            let handle = unsafe { insertion_edge.insert_fit(key, val).dormant() };
+            (Some(result), handle)
         }
     }
 }
@@ -976,21 +1022,31 @@ pub fn insert_recursing<A: Allocator + Clone>(
         key: K,
         value: V,
         alloc: A,
-    ) -> (Option<SplitResult<'a, K, V, marker::LeafOrInternal>>, *mut V) {
-        let (mut split, val_ptr) = match self.insert(key, value, alloc.clone()) {
-            (None, val_ptr) => return (None, val_ptr),
-            (Some(split), val_ptr) => (split.forget_node_type(), val_ptr),
+        split_root: impl FnOnce(SplitResult<'a, K, V, marker::LeafOrInternal>),
+    ) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> {
+        let (mut split, handle) = match self.insert(key, value, alloc.clone()) {
+            // SAFETY: we have finished splitting and can now re-awaken the
+            // handle to the inserted element.
+            (None, handle) => return unsafe { handle.awaken() },
+            (Some(split), handle) => (split.forget_node_type(), handle),
         };
 
         loop {
             split = match split.left.ascend() {
                 Ok(parent) => {
                     match parent.insert(split.kv.0, split.kv.1, split.right, alloc.clone()) {
-                        None => return (None, val_ptr),
+                        // SAFETY: we have finished splitting and can now re-awaken the
+                        // handle to the inserted element.
+                        None => return unsafe { handle.awaken() },
                         Some(split) => split.forget_node_type(),
                     }
                 }
-                Err(root) => return (Some(SplitResult { left: root, ..split }), val_ptr),
+                Err(root) => {
+                    split_root(SplitResult { left: root, ..split });
+                    // SAFETY: we have finished splitting and can now re-awaken the
+                    // handle to the inserted element.
+                    return unsafe { handle.awaken() };
+                }
             };
         }
     }
@@ -1043,6 +1099,14 @@ pub fn into_val_mut(self) -> &'a mut V {
         let leaf = self.node.into_leaf_mut();
         unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }
     }
+
+    pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) {
+        debug_assert!(self.idx < self.node.len());
+        let leaf = self.node.into_leaf_mut();
+        let k = unsafe { leaf.keys.get_unchecked(self.idx).assume_init_ref() };
+        let v = unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() };
+        (k, v)
+    }
 }
 
 impl<'a, K, V, NodeType> Handle<NodeRef<marker::ValMut<'a>, K, V, NodeType>, marker::KV> {
@@ -1667,6 +1731,7 @@ pub enum LeafOrInternal {}
 
     pub enum Owned {}
     pub enum Dying {}
+    pub enum DormantMut {}
     pub struct Immut<'a>(PhantomData<&'a ()>);
     pub struct Mut<'a>(PhantomData<&'a mut ()>);
     pub struct ValMut<'a>(PhantomData<&'a mut ()>);
@@ -1688,6 +1753,7 @@ impl BorrowType for Dying {}
     impl<'a> BorrowType for Immut<'a> {}
     impl<'a> BorrowType for Mut<'a> {}
     impl<'a> BorrowType for ValMut<'a> {}
+    impl BorrowType for DormantMut {}
 
     pub enum KV {}
     pub enum Edge {}
index ca182c8109ec97d3f1ad5dc01353a342e656d0f2..7565918851554bd5de13ae1f88ba4ef551fd3119 100644 (file)
@@ -928,12 +928,12 @@ pub fn push_str(&mut self, string: &str) {
 
     /// Copies elements from `src` range to the end of the string.
     ///
-    /// ## Panics
+    /// # Panics
     ///
     /// Panics if the starting point or end point do not lie on a [`char`]
     /// boundary, or if they're out of bounds.
     ///
-    /// ## Examples
+    /// # Examples
     ///
     /// ```
     /// #![feature(string_extend_from_within)]
index 74055602ec2e62df6c58148f0725789d61faaf02..e11bca5962a156a9059d7a8ceb561731fe68ee53 100644 (file)
@@ -872,13 +872,14 @@ pub trait Destruct {}
 pub trait Tuple {}
 
 /// A marker for things
-#[unstable(feature = "pointer_sized_trait", issue = "none")]
-#[lang = "pointer_sized"]
+#[unstable(feature = "pointer_like_trait", issue = "none")]
+#[cfg_attr(bootstrap, lang = "pointer_sized")]
+#[cfg_attr(not(bootstrap), lang = "pointer_like")]
 #[rustc_on_unimplemented(
-    message = "`{Self}` needs to be a pointer-sized type",
-    label = "`{Self}` needs to be a pointer-sized type"
+    message = "`{Self}` needs to have the same alignment and size as a pointer",
+    label = "`{Self}` needs to be a pointer-like type"
 )]
-pub trait PointerSized {}
+pub trait PointerLike {}
 
 /// Implementations of `Copy` for primitive types.
 ///
index 818721062d7f702aeba8df4096d55fbc6456427e..1d14efc7523b42a9c86e4f23b555e45771df316a 100644 (file)
@@ -928,8 +928,8 @@ pub fn fetch_not(&self, order: Ordering) -> bool {
     /// ```
     #[inline]
     #[unstable(feature = "atomic_mut_ptr", reason = "recently added", issue = "66893")]
-    pub fn as_mut_ptr(&self) -> *mut bool {
-        self.v.get() as *mut bool
+    pub const fn as_mut_ptr(&self) -> *mut bool {
+        self.v.get().cast()
     }
 
     /// Fetches the value, and applies a function to it that returns an optional
@@ -1803,7 +1803,7 @@ pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T {
     ///
     /// ```ignore (extern-declaration)
     /// #![feature(atomic_mut_ptr)]
-    //// use std::sync::atomic::AtomicPtr;
+    /// use std::sync::atomic::AtomicPtr;
     ///
     /// extern "C" {
     ///     fn my_atomic_op(arg: *mut *mut u32);
@@ -1819,7 +1819,7 @@ pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T {
     /// ```
     #[inline]
     #[unstable(feature = "atomic_mut_ptr", reason = "recently added", issue = "66893")]
-    pub fn as_mut_ptr(&self) -> *mut *mut T {
+    pub const fn as_mut_ptr(&self) -> *mut *mut T {
         self.p.get()
     }
 }
@@ -2727,7 +2727,7 @@ pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
             #[unstable(feature = "atomic_mut_ptr",
                    reason = "recently added",
                    issue = "66893")]
-            pub fn as_mut_ptr(&self) -> *mut $int_type {
+            pub const fn as_mut_ptr(&self) -> *mut $int_type {
                 self.v.get()
             }
         }
index 004601cb68b10b1dbc36f2c5e3bb37e7c86af23c..c98a52450849e9bc9bce15d17a92a5d1e40edd72 100644 (file)
@@ -1,6 +1,7 @@
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::Config;
 use crate::{t, VERSION};
+use sha2::Digest;
 use std::env::consts::EXE_SUFFIX;
 use std::fmt::Write as _;
 use std::fs::File;
@@ -10,6 +11,9 @@
 use std::str::FromStr;
 use std::{fmt, fs, io};
 
+#[cfg(test)]
+mod tests;
+
 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
 pub enum Profile {
     Compiler,
@@ -19,6 +23,13 @@ pub enum Profile {
     User,
 }
 
+/// A list of historical hashes of `src/etc/vscode_settings.json`.
+/// New entries should be appended whenever this is updated so we can detected
+/// outdated vs. user-modified settings files.
+static SETTINGS_HASHES: &[&str] =
+    &["ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8"];
+static VSCODE_SETTINGS: &str = include_str!("../etc/vscode_settings.json");
+
 impl Profile {
     fn include_path(&self, src_path: &Path) -> PathBuf {
         PathBuf::from(format!("{}/src/bootstrap/defaults/config.{}.toml", src_path.display(), self))
@@ -155,6 +166,7 @@ pub fn setup(config: &Config, profile: Profile) {
 
     if !config.dry_run() {
         t!(install_git_hook_maybe(&config));
+        t!(create_vscode_settings_maybe(&config));
     }
 
     println!();
@@ -351,6 +363,34 @@ fn parse_with_abbrev(input: &str) -> Result<Profile, String> {
     Ok(template)
 }
 
+#[derive(PartialEq)]
+enum PromptResult {
+    Yes,   // y/Y/yes
+    No,    // n/N/no
+    Print, // p/P/print
+}
+
+/// Prompt a user for a answer, looping until they enter an accepted input or nothing
+fn prompt_user(prompt: &str) -> io::Result<Option<PromptResult>> {
+    let mut input = String::new();
+    loop {
+        print!("{prompt} ");
+        io::stdout().flush()?;
+        input.clear();
+        io::stdin().read_line(&mut input)?;
+        match input.trim().to_lowercase().as_str() {
+            "y" | "yes" => return Ok(Some(PromptResult::Yes)),
+            "n" | "no" => return Ok(Some(PromptResult::No)),
+            "p" | "print" => return Ok(Some(PromptResult::Print)),
+            "" => return Ok(None),
+            _ => {
+                eprintln!("error: unrecognized option '{}'", input.trim());
+                eprintln!("note: press Ctrl+C to exit");
+            }
+        };
+    }
+}
+
 // install a git hook to automatically run tidy, if they want
 fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
     let git = t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
@@ -363,43 +403,98 @@ fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
         return Ok(());
     }
 
-    let mut input = String::new();
-    println!();
     println!(
-        "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
+        "\nRust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
 If you'd like, x.py can install a git hook for you that will automatically run `test tidy` before
 pushing your code to ensure your code is up to par. If you decide later that this behavior is
 undesirable, simply delete the `pre-push` file from .git/hooks."
     );
 
-    let should_install = loop {
-        print!("Would you like to install the git hook?: [y/N] ");
-        io::stdout().flush()?;
-        input.clear();
-        io::stdin().read_line(&mut input)?;
-        break match input.trim().to_lowercase().as_str() {
-            "y" | "yes" => true,
-            "n" | "no" | "" => false,
-            _ => {
-                eprintln!("error: unrecognized option '{}'", input.trim());
-                eprintln!("note: press Ctrl+C to exit");
-                continue;
-            }
-        };
-    };
-
-    if should_install {
-        let src = config.src.join("src").join("etc").join("pre-push.sh");
-        match fs::hard_link(src, &dst) {
-            Err(e) => eprintln!(
+    if prompt_user("Would you like to install the git hook?: [y/N]")? != Some(PromptResult::Yes) {
+        println!("Ok, skipping installation!");
+        return Ok(());
+    }
+    let src = config.src.join("src").join("etc").join("pre-push.sh");
+    match fs::hard_link(src, &dst) {
+        Err(e) => {
+            eprintln!(
                 "error: could not create hook {}: do you already have the git hook installed?\n{}",
                 dst.display(),
                 e
-            ),
-            Ok(_) => println!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"),
+            );
+            return Err(e);
+        }
+        Ok(_) => println!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"),
+    };
+    Ok(())
+}
+
+/// Create a `.vscode/settings.json` file for rustc development, or just print it
+fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> {
+    let (current_hash, historical_hashes) = SETTINGS_HASHES.split_last().unwrap();
+    let vscode_settings = config.src.join(".vscode").join("settings.json");
+    // If None, no settings.json exists
+    // If Some(true), is a previous version of settings.json
+    // If Some(false), is not a previous version (i.e. user modified)
+    // If it's up to date we can just skip this
+    let mut mismatched_settings = None;
+    if let Ok(current) = fs::read_to_string(&vscode_settings) {
+        let mut hasher = sha2::Sha256::new();
+        hasher.update(&current);
+        let hash = hex::encode(hasher.finalize().as_slice());
+        if hash == *current_hash {
+            return Ok(());
+        } else if historical_hashes.contains(&hash.as_str()) {
+            mismatched_settings = Some(true);
+        } else {
+            mismatched_settings = Some(false);
+        }
+    }
+    println!(
+        "\nx.py can automatically install the recommended `.vscode/settings.json` file for rustc development"
+    );
+    match mismatched_settings {
+        Some(true) => eprintln!(
+            "warning: existing `.vscode/settings.json` is out of date, x.py will update it"
+        ),
+        Some(false) => eprintln!(
+            "warning: existing `.vscode/settings.json` has been modified by user, x.py will back it up and replace it"
+        ),
+        _ => (),
+    }
+    let should_create = match prompt_user(
+        "Would you like to create/update `settings.json`, or only print suggested settings?: [y/p/N]",
+    )? {
+        Some(PromptResult::Yes) => true,
+        Some(PromptResult::Print) => false,
+        _ => {
+            println!("Ok, skipping settings!");
+            return Ok(());
+        }
+    };
+    if should_create {
+        let path = config.src.join(".vscode");
+        if !path.exists() {
+            fs::create_dir(&path)?;
+        }
+        let verb = match mismatched_settings {
+            // exists but outdated, we can replace this
+            Some(true) => "Updated",
+            // exists but user modified, back it up
+            Some(false) => {
+                // exists and is not current version or outdated, so back it up
+                let mut backup = vscode_settings.clone();
+                backup.set_extension("bak");
+                eprintln!("warning: copying `settings.json` to `settings.json.bak`");
+                fs::copy(&vscode_settings, &backup)?;
+                "Updated"
+            }
+            _ => "Created",
         };
+        fs::write(&vscode_settings, &VSCODE_SETTINGS)?;
+        println!("{verb} `.vscode/settings.json`");
     } else {
-        println!("Ok, skipping installation!");
+        println!("\n{VSCODE_SETTINGS}");
     }
     Ok(())
 }
diff --git a/src/bootstrap/setup/tests.rs b/src/bootstrap/setup/tests.rs
new file mode 100644 (file)
index 0000000..dcf9d18
--- /dev/null
@@ -0,0 +1,14 @@
+use super::{SETTINGS_HASHES, VSCODE_SETTINGS};
+use sha2::Digest;
+
+#[test]
+fn check_matching_settings_hash() {
+    let mut hasher = sha2::Sha256::new();
+    hasher.update(&VSCODE_SETTINGS);
+    let hash = hex::encode(hasher.finalize().as_slice());
+    assert_eq!(
+        &hash,
+        SETTINGS_HASHES.last().unwrap(),
+        "Update `SETTINGS_HASHES` with the new hash of `src/etc/vscode_settings.json`"
+    );
+}
index 6078e39ac9d3b8af5a7214921d91edff4c238385..8a0c532cfb02fe5c29132adb7cb6a2757728696a 100644 (file)
@@ -1114,9 +1114,6 @@ fn run(self, builder: &Builder<'_>) {
             cmd.arg("--bless");
         }
 
-        builder.info("tidy check");
-        try_run(builder, &mut cmd);
-
         if builder.config.channel == "dev" || builder.config.channel == "nightly" {
             builder.info("fmt check");
             if builder.initial_rustfmt().is_none() {
@@ -1134,6 +1131,11 @@ fn run(self, builder: &Builder<'_>) {
             }
             crate::format::format(&builder, !builder.config.cmd.bless(), &[]);
         }
+
+        builder.info("tidy check");
+        try_run(builder, &mut cmd);
+
+        builder.ensure(ExpandYamlAnchors {});
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
index c0a1341ebca5c3b24347e2705368444df8a77d73..3c128c0ca251b514142c020fbc7c6409ee843a06 100644 (file)
@@ -307,8 +307,6 @@ jobs:
           - name: x86_64-gnu-tools
             <<: *job-linux-xl
             tidy: false
-            env:
-              CI_ONLY_WHEN_SUBMODULES_CHANGED: 1
 
   auto:
     permissions:
index 85d772253808ae5a6cdfe74ad6b336f214aec102..48127166ad0809b644ba4b533b042588ab0eec7a 100755 (executable)
@@ -1,46 +1,11 @@
 #!/bin/bash
-# Set the SKIP_JOB environment variable if this job is supposed to only run
-# when submodules are updated and they were not. The following time consuming
-# tasks will be skipped when the environment variable is present.
+# Set the SKIP_JOB environment variable if this job is not supposed to run on the current builder.
 
 set -euo pipefail
 IFS=$'\n\t'
 
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
-if [[ -n "${CI_ONLY_WHEN_SUBMODULES_CHANGED-}" ]]; then
-    git fetch "https://github.com/$GITHUB_REPOSITORY" "$GITHUB_BASE_REF"
-    BASE_COMMIT="$(git merge-base FETCH_HEAD HEAD)"
-
-    echo "Searching for toolstate changes between $BASE_COMMIT and $(git rev-parse HEAD)"
-
-    if git diff "$BASE_COMMIT" | grep --quiet "^index .* 160000"; then
-        # Submodules pseudo-files inside git have the 160000 permissions, so when
-        # those files are present in the diff a submodule was updated.
-        echo "Submodules were updated"
-    elif ! (git diff --quiet "$BASE_COMMIT" -- \
-             src/tools/clippy src/tools/rustfmt src/tools/miri \
-             library/std/src/sys); then
-        # There is not an easy blanket search for subtrees. For now, manually list
-        # the subtrees.
-        # Also run this when the platform-specific parts of std change, in case
-        # that breaks Miri.
-        echo "Tool subtrees were updated"
-    elif ! (git diff --quiet "$BASE_COMMIT" -- \
-             tests/rustdoc-gui \
-             src/librustdoc \
-             src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile \
-             src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version \
-             src/tools/rustdoc-gui); then
-        # There was a change in either rustdoc or in its GUI tests.
-        echo "Rustdoc was updated"
-    else
-        echo "Not executing this job since no submodules nor subtrees were updated"
-        ciCommandSetEnv SKIP_JOB 1
-        exit 0
-    fi
-fi
-
 if [[ -n "${CI_ONLY_WHEN_CHANNEL-}" ]]; then
     if [[ "${CI_ONLY_WHEN_CHANNEL}" = "$(cat src/ci/channel)" ]]; then
         echo "The channel is the expected one"
index 372350403e28151158e7fb99e309614af90bd960..cea6033ede208f7ce091ba1f800aa1c151f9ce19 100644 (file)
@@ -5,3 +5,4 @@ title = "The rustc book"
 
 [output.html]
 git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustc"
+edit-url-template = "https://github.com/rust-lang/rust/edit/master/src/doc/rustc/{path}"
index 7e355b7fccfc4485a5f11e11d10165ce8148f607..1770c121a0e73064d6db671d6bf3b50b10784e5a 100644 (file)
@@ -562,7 +562,7 @@ Supported values for this option are:
 * `v0` — The "v0" mangling scheme. The specific format is not specified at
   this time.
 
-The default if not specified will use a compiler-chosen default which may
+The default, if not specified, will use a compiler-chosen default which may
 change in the future.
 
 [name mangling]: https://en.wikipedia.org/wiki/Name_mangling
diff --git a/src/etc/vscode_settings.json b/src/etc/vscode_settings.json
new file mode 100644 (file)
index 0000000..cd61a38
--- /dev/null
@@ -0,0 +1,26 @@
+{
+    "rust-analyzer.checkOnSave.overrideCommand": [
+        "python3",
+        "x.py",
+        "check",
+        "--json-output"
+    ],
+    "rust-analyzer.linkedProjects": ["src/bootstrap/Cargo.toml", "Cargo.toml"],
+    "rust-analyzer.rustfmt.overrideCommand": [
+        "./build/host/rustfmt/bin/rustfmt",
+        "--edition=2021"
+    ],
+    "rust-analyzer.procMacro.server": "./build/host/stage0/libexec/rust-analyzer-proc-macro-srv",
+    "rust-analyzer.procMacro.enable": true,
+    "rust-analyzer.cargo.buildScripts.enable": true,
+    "rust-analyzer.cargo.buildScripts.invocationLocation": "root",
+    "rust-analyzer.cargo.buildScripts.invocationStrategy": "once",
+    "rust-analyzer.cargo.buildScripts.overrideCommand": [
+        "python3",
+        "x.py",
+        "check",
+        "--json-output"
+    ],
+    "rust-analyzer.cargo.sysroot": "./build/host/stage0-sysroot",
+    "rust-analyzer.rustc.source": "./Cargo.toml"
+}
index a59cfbea8853e5428f4a4adf1682eea10d7a0fef..8a7a8ea5fd1f268a69c6e7f39eb319030f032896 100644 (file)
@@ -289,7 +289,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
                 if f.alternate() {
                     f.write_str(" ")?;
                 } else {
-                    f.write_str("<br>")?;
+                    f.write_str("\n")?;
                 }
 
                 match pred {
@@ -352,7 +352,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
             }
         } else {
             let mut br_with_padding = String::with_capacity(6 * indent + 28);
-            br_with_padding.push_str("<br>");
+            br_with_padding.push_str("\n");
 
             let padding_amout =
                 if ending == Ending::Newline { indent + 4 } else { indent + "fn where ".len() };
@@ -360,16 +360,16 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
             for _ in 0..padding_amout {
                 br_with_padding.push_str(" ");
             }
-            let where_preds = where_preds.to_string().replace("<br>", &br_with_padding);
+            let where_preds = where_preds.to_string().replace("\n", &br_with_padding);
 
             if ending == Ending::Newline {
                 let mut clause = " ".repeat(indent.saturating_sub(1));
                 write!(clause, "<span class=\"where fmt-newline\">where{where_preds},</span>")?;
                 clause
             } else {
-                // insert a <br> tag after a single space but before multiple spaces at the start
+                // insert a newline after a single space but before multiple spaces at the start
                 if indent == 0 {
-                    format!("<br><span class=\"where\">where{where_preds}</span>")
+                    format!("\n<span class=\"where\">where{where_preds}</span>")
                 } else {
                     // put the first one on the same line as the 'where' keyword
                     let where_preds = where_preds.replacen(&br_with_padding, " ", 1);
@@ -1315,7 +1315,8 @@ pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
 
     /// * `header_len`: The length of the function header and name. In other words, the number of
     ///   characters in the function declaration up to but not including the parentheses.
-    ///   <br>Used to determine line-wrapping.
+    ///   This is expected to go into a `<pre>`/`code-header` block, so indentation and newlines
+    ///   are preserved.
     /// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is
     ///   necessary.
     pub(crate) fn full_print<'a, 'tcx: 'a>(
@@ -1363,7 +1364,7 @@ fn inner_full_print(
                 }
             } else {
                 if i > 0 {
-                    args.push_str("<br>");
+                    args.push_str("\n");
                 }
                 if input.is_const {
                     args.push_str("const ");
@@ -1389,7 +1390,7 @@ fn inner_full_print(
         let mut args = args.into_inner();
 
         if self.c_variadic {
-            args.push_str(",<br> ...");
+            args.push_str(",\n ...");
             args_plain.push_str(", ...");
         }
 
@@ -1399,24 +1400,20 @@ fn inner_full_print(
 
         let declaration_len = header_len + args_plain.len() + arrow_plain.len();
         let output = if declaration_len > 80 {
-            let full_pad = format!("<br>{}", " ".repeat(indent + 4));
-            let close_pad = format!("<br>{}", " ".repeat(indent));
+            let full_pad = format!("\n{}", " ".repeat(indent + 4));
+            let close_pad = format!("\n{}", " ".repeat(indent));
             format!(
                 "({pad}{args}{close}){arrow}",
                 pad = if self.inputs.values.is_empty() { "" } else { &full_pad },
-                args = args.replace("<br>", &full_pad),
+                args = args.replace("\n", &full_pad),
                 close = close_pad,
                 arrow = arrow
             )
         } else {
-            format!("({args}){arrow}", args = args.replace("<br>", " "), arrow = arrow)
+            format!("({args}){arrow}", args = args.replace("\n", " "), arrow = arrow)
         };
 
-        if f.alternate() {
-            write!(f, "{}", output.replace("<br>", "\n"))
-        } else {
-            write!(f, "{}", output)
-        }
+        write!(f, "{}", output)
     }
 }
 
index 8540ee6631934c7d163644fd17e52553b9f5b1a2..7690d8f251f7485a04affbcb445b9b6ca7486687 100644 (file)
     {%- for theme in themes -%}
         <link rel="stylesheet" disabled href="{{page.root_path|safe}}{{theme}}{{page.resource_suffix}}.css"> {#- -#}
     {%- endfor -%}
+    {%- if !layout.default_settings.is_empty() -%}
     <script id="default-settings" {# -#}
       {% for (k, v) in layout.default_settings %}
         data-{{k}}="{{v}}"
       {%- endfor -%}
     ></script> {#- -#}
+    {%- endif -%}
     <script src="{{static_root_path|safe}}{{files.storage_js}}"></script> {#- -#}
     {%- if page.css_class.contains("crate") -%}
     <script defer src="{{page.root_path|safe}}crates{{page.resource_suffix}}.js"></script> {#- -#}
index e84a7928d93a31f284b497c214a2ece69b4d7719..82c3bb79e3a19a5164e33819ef81bfc2c984bc56 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e84a7928d93a31f284b497c214a2ece69b4d7719
+Subproject commit 82c3bb79e3a19a5164e33819ef81bfc2c984bc56
index 8992d165d5d504a783e6a5bf3f25f1fd7150598a..3fc72ecbbc484ffd2b9e292b00585fcbedeeb392 100644 (file)
@@ -51,7 +51,7 @@ fn from_args() -> Result<Self, Box<dyn Error>> {
             ["generate", ref base] => (Mode::Generate, PathBuf::from(base)),
             ["check", ref base] => (Mode::Check, PathBuf::from(base)),
             _ => {
-                eprintln!("usage: expand-yaml-anchors <source-dir> <dest-dir>");
+                eprintln!("usage: expand-yaml-anchors <generate|check> <base-dir>");
                 std::process::exit(1);
             }
         };
index ec555ba2895c8468b82bcaae0008fcfb34b13ad0..106e93751d21904c363c07bf26413a75505c78a7 100644 (file)
@@ -81,21 +81,18 @@ fn from_ref_ty<'tcx>(
                         protector: None,
                     }
                 } else if pointee.is_unpin(*cx.tcx, cx.param_env()) {
-                    // A regular full mutable reference.
+                    // A regular full mutable reference. On `FnEntry` this is `noalias` and `dereferenceable`.
                     NewPermission::Uniform {
                         perm: Permission::Unique,
                         access: Some(AccessKind::Write),
                         protector,
                     }
                 } else {
+                    // `!Unpin` dereferences do not get `noalias` nor `dereferenceable`.
                     NewPermission::Uniform {
                         perm: Permission::SharedReadWrite,
-                        // FIXME: We emit `dereferenceable` for `!Unpin` mutable references, so we
-                        // should do fake accesses here. But then we run into
-                        // <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>, so for now
-                        // we don't do that.
                         access: None,
-                        protector,
+                        protector: None,
                     }
                 }
             }
@@ -109,6 +106,7 @@ fn from_ref_ty<'tcx>(
                 }
             }
             ty::Ref(_, _pointee, Mutability::Not) => {
+                // Shared references. If frozen, these get `noalias` and `dereferenceable`; otherwise neither.
                 NewPermission::FreezeSensitive {
                     freeze_perm: Permission::SharedReadOnly,
                     freeze_access: Some(AccessKind::Read),
@@ -137,6 +135,32 @@ fn from_ref_ty<'tcx>(
         }
     }
 
+    fn from_box_ty<'tcx>(
+        ty: Ty<'tcx>,
+        kind: RetagKind,
+        cx: &crate::MiriInterpCx<'_, 'tcx>,
+    ) -> Self {
+        // `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling).
+        let pointee = ty.builtin_deref(true).unwrap().ty;
+        if pointee.is_unpin(*cx.tcx, cx.param_env()) {
+            // A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only
+            // a weak protector).
+            NewPermission::Uniform {
+                perm: Permission::Unique,
+                access: Some(AccessKind::Write),
+                protector: (kind == RetagKind::FnEntry)
+                    .then_some(ProtectorKind::WeakProtector),
+            }
+        } else {
+            // `!Unpin` boxes do not get `noalias` nor `dereferenceable`.
+            NewPermission::Uniform {
+                perm: Permission::SharedReadWrite,
+                access: None,
+                protector: None,
+            }
+        }
+    }
+
     fn protector(&self) -> Option<ProtectorKind> {
         match self {
             NewPermission::Uniform { protector, .. } => *protector,
@@ -916,12 +940,7 @@ fn ecx(&mut self) -> &mut MiriInterpCx<'mir, 'tcx> {
 
             fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
                 // Boxes get a weak protectors, since they may be deallocated.
-                let new_perm = NewPermission::Uniform {
-                    perm: Permission::Unique,
-                    access: Some(AccessKind::Write),
-                    protector: (self.kind == RetagKind::FnEntry)
-                        .then_some(ProtectorKind::WeakProtector),
-                };
+                let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx);
                 self.retag_ptr_inplace(place, new_perm, self.retag_cause)
             }
 
index 618cf9df7f3f0f54e9e28dc71046965d3e3fc5cb..dcb1879042041daa9e9a0d520c4ef7d7265db366 100644 (file)
@@ -162,11 +162,14 @@ pub fn ptr_from_addr_cast(
         Ok(Pointer::new(Some(Provenance::Wildcard), Size::from_bytes(addr)))
     }
 
-    fn alloc_base_addr(ecx: &MiriInterpCx<'mir, 'tcx>, alloc_id: AllocId) -> u64 {
+    fn alloc_base_addr(
+        ecx: &MiriInterpCx<'mir, 'tcx>,
+        alloc_id: AllocId,
+    ) -> InterpResult<'tcx, u64> {
         let mut global_state = ecx.machine.intptrcast.borrow_mut();
         let global_state = &mut *global_state;
 
-        match global_state.base_addr.entry(alloc_id) {
+        Ok(match global_state.base_addr.entry(alloc_id) {
             Entry::Occupied(entry) => *entry.get(),
             Entry::Vacant(entry) => {
                 // There is nothing wrong with a raw pointer being cast to an integer only after
@@ -181,7 +184,10 @@ fn alloc_base_addr(ecx: &MiriInterpCx<'mir, 'tcx>, alloc_id: AllocId) -> u64 {
                     rng.gen_range(0..16)
                 };
                 // From next_base_addr + slack, round up to adjust for alignment.
-                let base_addr = global_state.next_base_addr.checked_add(slack).unwrap();
+                let base_addr = global_state
+                    .next_base_addr
+                    .checked_add(slack)
+                    .ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
                 let base_addr = Self::align_addr(base_addr, align.bytes());
                 entry.insert(base_addr);
                 trace!(
@@ -197,24 +203,33 @@ fn alloc_base_addr(ecx: &MiriInterpCx<'mir, 'tcx>, alloc_id: AllocId) -> u64 {
                 // of at least 1 to avoid two allocations having the same base address.
                 // (The logic in `alloc_id_from_addr` assumes unique addresses, and different
                 // function/vtable pointers need to be distinguishable!)
-                global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap();
+                global_state.next_base_addr = base_addr
+                    .checked_add(max(size.bytes(), 1))
+                    .ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
+                // Even if `Size` didn't overflow, we might still have filled up the address space.
+                if global_state.next_base_addr > ecx.machine_usize_max() {
+                    throw_exhaust!(AddressSpaceFull);
+                }
                 // Given that `next_base_addr` increases in each allocation, pushing the
                 // corresponding tuple keeps `int_to_ptr_map` sorted
                 global_state.int_to_ptr_map.push((base_addr, alloc_id));
 
                 base_addr
             }
-        }
+        })
     }
 
     /// Convert a relative (tcx) pointer to an absolute address.
-    pub fn rel_ptr_to_addr(ecx: &MiriInterpCx<'mir, 'tcx>, ptr: Pointer<AllocId>) -> u64 {
+    pub fn rel_ptr_to_addr(
+        ecx: &MiriInterpCx<'mir, 'tcx>,
+        ptr: Pointer<AllocId>,
+    ) -> InterpResult<'tcx, u64> {
         let (alloc_id, offset) = ptr.into_parts(); // offset is relative (AllocId provenance)
-        let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id);
+        let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id)?;
 
         // Add offset with the right kind of pointer-overflowing arithmetic.
         let dl = ecx.data_layout();
-        dl.overflowing_offset(base_addr, offset.bytes()).0
+        Ok(dl.overflowing_offset(base_addr, offset.bytes()).0)
     }
 
     /// When a pointer is used for a memory access, this computes where in which allocation the
@@ -232,7 +247,9 @@ pub fn abs_ptr_to_rel(
             GlobalStateInner::alloc_id_from_addr(ecx, addr.bytes())?
         };
 
-        let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id);
+        // This cannot fail: since we already have a pointer with that provenance, rel_ptr_to_addr
+        // must have been called in the past.
+        let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id).unwrap();
 
         // Wrapping "addr - base_addr"
         let dl = ecx.data_layout();
index 01a3d7550e2e0c480b5bb545ef77782837471924..8e44d4d7adec8465607827b6ba9f06529a623ce3 100644 (file)
@@ -971,7 +971,7 @@ fn adjust_allocation<'b>(
     fn adjust_alloc_base_pointer(
         ecx: &MiriInterpCx<'mir, 'tcx>,
         ptr: Pointer<AllocId>,
-    ) -> Pointer<Provenance> {
+    ) -> InterpResult<'tcx, Pointer<Provenance>> {
         if cfg!(debug_assertions) {
             // The machine promises to never call us on thread-local or extern statics.
             let alloc_id = ptr.provenance;
@@ -985,17 +985,17 @@ fn adjust_alloc_base_pointer(
                 _ => {}
             }
         }
-        let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr);
+        let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr)?;
         let tag = if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
             borrow_tracker.borrow_mut().base_ptr_tag(ptr.provenance, &ecx.machine)
         } else {
             // Value does not matter, SB is disabled
             BorTag::default()
         };
-        Pointer::new(
+        Ok(Pointer::new(
             Provenance::Concrete { alloc_id: ptr.provenance, tag },
             Size::from_bytes(absolute_addr),
-        )
+        ))
     }
 
     #[inline(always)]
index 15987eee537fd72372cab58e2c654ab206631c9e..ed1c6ebfece76ceed96988a2385a21c6d0145065 100644 (file)
@@ -190,9 +190,9 @@ fn handle_miri_resolve_frame(
             0 => {
                 // These are "mutable" allocations as we consider them to be owned by the callee.
                 let name_alloc =
-                    this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut);
+                    this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
                 let filename_alloc =
-                    this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut);
+                    this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
 
                 this.write_immediate(
                     name_alloc.to_ref(this),
index db3e42facadd03958c1d8725b7c44be4645692db..0ea1137200b9d98177de5a0770fa040a7fd19471 100644 (file)
@@ -172,7 +172,7 @@ fn start_panic(&mut self, msg: &str, unwind: StackPopUnwind) -> InterpResult<'tc
         let this = self.eval_context_mut();
 
         // First arg: message.
-        let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not);
+        let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not)?;
 
         // Call the lang item.
         let panic = this.tcx.lang_items().panic_fn().unwrap();
diff --git a/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector2.rs b/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector2.rs
deleted file mode 100644 (file)
index fd67dcc..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-//@error-pattern: /deallocating while item \[SharedReadWrite for .*\] is strongly protected/
-use std::marker::PhantomPinned;
-
-pub struct NotUnpin(i32, PhantomPinned);
-
-fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) {
-    // `f` may mutate, but it may not deallocate!
-    f(x)
-}
-
-fn main() {
-    inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
-        let raw = x as *mut _;
-        drop(unsafe { Box::from_raw(raw) });
-    });
-}
diff --git a/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector2.stderr b/src/tools/miri/tests/fail/stacked_borrows/deallocate_against_protector2.stderr
deleted file mode 100644 (file)
index 47cfa0d..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-error: Undefined Behavior: deallocating while item [SharedReadWrite for <TAG>] is strongly protected by call ID
-  --> RUSTLIB/alloc/src/alloc.rs:LL:CC
-   |
-LL |     unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [SharedReadWrite for <TAG>] is strongly protected by call ID
-   |
-   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
-   = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
-   = note: BACKTRACE:
-   = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `alloc::alloc::box_free::<NotUnpin, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC
-   = note: inside `std::ptr::drop_in_place::<std::boxed::Box<NotUnpin>> - shim(Some(std::boxed::Box<NotUnpin>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC
-   = note: inside `std::mem::drop::<std::boxed::Box<NotUnpin>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
-note: inside closure
-  --> $DIR/deallocate_against_protector2.rs:LL:CC
-   |
-LL |         drop(unsafe { Box::from_raw(raw) });
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: inside `<[closure@$DIR/deallocate_against_protector2.rs:LL:CC] as std::ops::FnOnce<(&mut NotUnpin,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC
-note: inside `inner`
-  --> $DIR/deallocate_against_protector2.rs:LL:CC
-   |
-LL |     f(x)
-   |     ^^^^
-note: inside `main`
-  --> $DIR/deallocate_against_protector2.rs:LL:CC
-   |
-LL | /     inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
-LL | |         let raw = x as *mut _;
-LL | |         drop(unsafe { Box::from_raw(raw) });
-LL | |     });
-   | |______^
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to previous error
-
index 96fc0be344dbfea2f8065c503b4df6b3057d0a7c..6994def16a1da3f537c9fb78bdc4a8622c2d13d5 100644 (file)
@@ -26,6 +26,19 @@ fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
     }
 }
 
+fn mk_waker() -> Waker {
+    use std::sync::Arc;
+
+    struct MyWaker;
+    impl Wake for MyWaker {
+        fn wake(self: Arc<Self>) {
+            unimplemented!()
+        }
+    }
+
+    Waker::from(Arc::new(MyWaker))
+}
+
 async fn do_stuff() {
     (&mut Delay::new(1)).await;
 }
@@ -73,16 +86,7 @@ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
 }
 
 fn run_fut<T>(fut: impl Future<Output = T>) -> T {
-    use std::sync::Arc;
-
-    struct MyWaker;
-    impl Wake for MyWaker {
-        fn wake(self: Arc<Self>) {
-            unimplemented!()
-        }
-    }
-
-    let waker = Waker::from(Arc::new(MyWaker));
+    let waker = mk_waker();
     let mut context = Context::from_waker(&waker);
 
     let mut pinned = pin!(fut);
@@ -94,7 +98,37 @@ fn wake(self: Arc<Self>) {
     }
 }
 
+fn self_referential_box() {
+    let waker = mk_waker();
+    let cx = &mut Context::from_waker(&waker);
+
+    async fn my_fut() -> i32 {
+        let val = 10;
+        let val_ref = &val;
+
+        let _ = Delay::new(1).await;
+
+        *val_ref
+    }
+
+    fn box_poll<F: Future>(
+        mut f: Pin<Box<F>>,
+        cx: &mut Context<'_>,
+    ) -> (Pin<Box<F>>, Poll<F::Output>) {
+        let p = f.as_mut().poll(cx);
+        (f, p)
+    }
+
+    let my_fut = Box::pin(my_fut());
+    let (my_fut, p1) = box_poll(my_fut, cx);
+    assert!(p1.is_pending());
+    let (my_fut, p2) = box_poll(my_fut, cx);
+    assert!(p2.is_ready());
+    drop(my_fut);
+}
+
 fn main() {
     run_fut(do_stuff());
     run_fut(DoStuff::new());
+    self_referential_box();
 }
index ef6eb346c17b12804cb9c92dd5caaa424d35dbec..8e78efa73c751578c9c3b7849553bb62fcd32e31 100644 (file)
@@ -19,6 +19,7 @@ fn main() {
     array_casts();
     mut_below_shr();
     wide_raw_ptr_in_tuple();
+    not_unpin_not_protected();
 }
 
 // Make sure that reading from an `&mut` does, like reborrowing to `&`,
@@ -219,3 +220,22 @@ fn wide_raw_ptr_in_tuple() {
     // Make sure the fn ptr part of the vtable is still fine.
     r.type_id();
 }
+
+fn not_unpin_not_protected() {
+    // `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also
+    // don't add protectors. (We could, but until we have a better idea for where we want to go with
+    // the self-referntial-generator situation, it does not seem worth the potential trouble.)
+    use std::marker::PhantomPinned;
+
+    pub struct NotUnpin(i32, PhantomPinned);
+
+    fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) {
+        // `f` may mutate, but it may not deallocate!
+        f(x)
+    }
+
+    inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
+        let raw = x as *mut _;
+        drop(unsafe { Box::from_raw(raw) });
+    });
+}
index 5b2eee7eed72b4894909c5eecbf014ea0b5ad995..9981e4d1ea6ac0992ff21be5514d4230dc77548b 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5b2eee7eed72b4894909c5eecbf014ea0b5ad995
+Subproject commit 9981e4d1ea6ac0992ff21be5514d4230dc77548b
index 6bb4d32f87d0a25bd2b5a065741ce3e3fc5e6cb8..dd2fd1911f227c162b9b249b5a0e2c268dc538b8 100644 (file)
@@ -31,7 +31,7 @@
 
 // Error codes that don't yet have a UI test. This list will eventually be removed.
 const IGNORE_UI_TEST_CHECK: &[&str] =
-    &["E0461", "E0465", "E0476", "E0514", "E0523", "E0554", "E0640", "E0717", "E0729"];
+    &["E0461", "E0465", "E0476", "E0514", "E0554", "E0640", "E0717", "E0729"];
 
 macro_rules! verbose_print {
     ($verbose:expr, $($fmt:tt)*) => {
index 806e84025c4a28cb37b5f841f70e6580e27d1bcc..83551a1d820abe0c5c30ce395dd968100f813638 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 = 1998;
+const ISSUES_ENTRY_LIMIT: usize = 2001;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     for dir in Walk::new(&path.join("ui")) {
index ff76405a4ea323338c45c98751756216f76f4f30..0c62e0d35e36d91624e2ac519e56f1cc72d9c91e 100644 (file)
@@ -29,6 +29,12 @@ pub fn borrow(x: &i32) -> &i32 {
   x
 }
 
+// CHECK: align 4 {{i32\*|ptr}} @borrow_mut({{i32\*|ptr}} align 4 %x)
+#[no_mangle]
+pub fn borrow_mut(x: &mut i32) -> &mut i32 {
+  x
+}
+
 // CHECK-LABEL: @borrow_call
 #[no_mangle]
 pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 {
index 1f979d7b90a70b08b7a5edd95028777218481772..96dfde18683e34b2c3ab452a79920edd040a72a1 100644 (file)
@@ -85,6 +85,12 @@ pub fn option_nonzero_int(x: Option<NonZeroU64>) -> Option<NonZeroU64> {
 pub fn readonly_borrow(_: &i32) {
 }
 
+// CHECK: noundef align 4 dereferenceable(4) {{i32\*|ptr}} @readonly_borrow_ret()
+#[no_mangle]
+pub fn readonly_borrow_ret() -> &'static i32 {
+  loop {}
+}
+
 // CHECK: @static_borrow({{i32\*|ptr}} noalias noundef readonly align 4 dereferenceable(4) %_1)
 // static borrow may be captured
 #[no_mangle]
@@ -115,9 +121,17 @@ pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
 pub fn mutable_borrow(_: &mut i32) {
 }
 
+// CHECK: noundef align 4 dereferenceable(4) {{i32\*|ptr}} @mutable_borrow_ret()
+#[no_mangle]
+pub fn mutable_borrow_ret() -> &'static mut i32 {
+  loop {}
+}
+
 #[no_mangle]
-// CHECK: @mutable_notunpin_borrow({{i32\*|ptr}} noundef align 4 dereferenceable(4) %_1)
+// CHECK: @mutable_notunpin_borrow({{i32\*|ptr}} noundef nonnull align 4 %_1)
 // This one is *not* `noalias` because it might be self-referential.
+// It is also not `dereferenceable` due to
+// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>.
 pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {
 }
 
@@ -167,6 +181,12 @@ pub fn _box(x: Box<i32>) -> Box<i32> {
   x
 }
 
+// CHECK: noundef nonnull align 4 {{i32\*|ptr}} @notunpin_box({{i32\*|ptr}} noundef nonnull align 4 %x)
+#[no_mangle]
+pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
+  x
+}
+
 // CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) dereferenceable(32){{( %0)?}})
 #[no_mangle]
 pub fn struct_return() -> S {
@@ -233,12 +253,12 @@ pub fn trait_raw(_: *const dyn Drop) {
 
 // CHECK: @trait_box({{\{\}\*|ptr}} noalias noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}})
 #[no_mangle]
-pub fn trait_box(_: Box<dyn Drop>) {
+pub fn trait_box(_: Box<dyn Drop + Unpin>) {
 }
 
 // CHECK: { {{i8\*|ptr}}, {{i8\*|ptr}} } @trait_option({{i8\*|ptr}} noalias noundef align 1 %x.0, {{i8\*|ptr}} %x.1)
 #[no_mangle]
-pub fn trait_option(x: Option<Box<dyn Drop>>) -> Option<Box<dyn Drop>> {
+pub fn trait_option(x: Option<Box<dyn Drop + Unpin>>) -> Option<Box<dyn Drop + Unpin>> {
   x
 }
 
diff --git a/tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff b/tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff
new file mode 100644 (file)
index 0000000..02308be
--- /dev/null
@@ -0,0 +1,31 @@
+- // MIR for `f` before CopyProp
++ // MIR for `f` after CopyProp
+  
+  fn f(_1: Foo) -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/move_projection.rs:+0:17: +0:21
+      let mut _2: Foo;                     // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+      let mut _3: u8;                      // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+  
+      bb0: {
+-         _2 = _1;                         // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+-         _3 = move (_2.0: u8);            // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+-         _0 = opaque::<Foo>(move _1) -> bb1; // scope 0 at $DIR/move_projection.rs:+6:13: +6:44
++         _3 = (_1.0: u8);                 // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
++         _0 = opaque::<Foo>(_1) -> bb1;   // scope 0 at $DIR/move_projection.rs:+6:13: +6:44
+                                           // mir::Constant
+                                           // + span: $DIR/move_projection.rs:19:28: 19:34
+                                           // + literal: Const { ty: fn(Foo) -> bool {opaque::<Foo>}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          _0 = opaque::<u8>(move _3) -> bb2; // scope 0 at $DIR/move_projection.rs:+9:13: +9:44
+                                           // mir::Constant
+                                           // + span: $DIR/move_projection.rs:22:28: 22:34
+                                           // + literal: Const { ty: fn(u8) -> bool {opaque::<u8>}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          return;                          // scope 0 at $DIR/move_projection.rs:+12:13: +12:21
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/move_projection.rs b/tests/mir-opt/copy-prop/move_projection.rs
new file mode 100644 (file)
index 0000000..2a1bbae
--- /dev/null
@@ -0,0 +1,34 @@
+// unit-test: CopyProp
+
+#![feature(custom_mir, core_intrinsics)]
+#![allow(unused_assignments)]
+extern crate core;
+use core::intrinsics::mir::*;
+
+fn opaque(_: impl Sized) -> bool { true }
+
+struct Foo(u8);
+
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn f(a: Foo) -> bool {
+    mir!(
+        {
+            let b = a;
+            // This is a move out of a copy, so must become a copy of `a.0`.
+            let c = Move(b.0);
+            Call(RET, bb1, opaque(Move(a)))
+        }
+        bb1 = {
+            Call(RET, ret, opaque(Move(c)))
+        }
+        ret = {
+            Return()
+        }
+    )
+}
+
+fn main() {
+    assert!(f(Foo(0)));
+}
+
+// EMIT_MIR move_projection.f.CopyProp.diff
index e338f15b4853144be1b1019369f36759a6572516..66ba4df767ccf2ff004604ac17d3070affa706c1 100644 (file)
@@ -34,7 +34,7 @@ fn ezmap(_1: Option<i32>) -> Option<i32> {
     }
 
     bb3: {
-        _4 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
+        _4 = ((_1 as Some).0: i32);      // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
         StorageLive(_5);                 // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
         _5 = Add(_4, const 1_i32);       // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
         _0 = Option::<i32>::Some(move _5); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
index 3db344af67439c5c877b2d532dfc538eea9623d5..70bcbcb6ff44ae3d5851a71b6f729950a41c4795 100644 (file)
@@ -77,7 +77,7 @@ struct AsyncFdReadyGuard<'a, T> { x: &'a T }
 
 impl Foo {
     // @has async_fn/struct.Foo.html
-    // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+    // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar ) -> impl Iterator<Item = &usize>'
     pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
     // taken from `tokio` as an example of a method that was particularly bad before
     // @has - '//*[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
index ade70bbe80d923a1b5f02467eecd13e6e4b5916e..cbda095424b7d1536c6ea359a48c86b76c11ecee 100644 (file)
@@ -31,7 +31,7 @@ impl Trait<{1 + 2}> for u8 {}
 impl<const N: usize> Trait<N> for [u8; N] {}
 
 // @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \
-//      'pub struct Foo<const N: usize>where u8: Trait<N>'
+//      'pub struct Foo<const N: usize> where u8: Trait<N>'
 pub struct Foo<const N: usize> where u8: Trait<N>;
 // @has foo/struct.Bar.html '//pre[@class="rust item-decl"]' 'pub struct Bar<T, const N: usize>(_)'
 pub struct Bar<T, const N: usize>([T; N]);
index a2500de79a0968b37420318d6e18dbbd929cdda3..d73393633f3b8c97b1ea04eee609a46ce59a4d50 100644 (file)
@@ -1,9 +1,23 @@
 <code>pub trait Write {
     // Required methods
-    fn <a href="#tymethod.poll_write" class="fn">poll_write</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;buf: &amp;mut [<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
-<span class="item-spacer" />    fn <a href="#tymethod.poll_flush" class="fn">poll_flush</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
-<span class="item-spacer" />    fn <a href="#tymethod.poll_close" class="fn">poll_close</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
+    fn <a href="#tymethod.poll_write" class="fn">poll_write</a>(
+        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,
+        cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,
+        buf: &amp;mut [<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]
+    ) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
+<span class="item-spacer" />    fn <a href="#tymethod.poll_flush" class="fn">poll_flush</a>(
+        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,
+        cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;
+    ) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
+<span class="item-spacer" />    fn <a href="#tymethod.poll_close" class="fn">poll_close</a>(
+        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,
+        cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;
+    ) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
 
     // Provided method
-    fn <a href="#method.poll_write_vectored" class="fn">poll_write_vectored</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;bufs: &amp;[<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt; { ... }
-}</code>
+    fn <a href="#method.poll_write_vectored" class="fn">poll_write_vectored</a>(
+        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,
+        cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,
+        bufs: &amp;[<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]
+    ) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt; { ... }
+}</code>
\ No newline at end of file
index bcead3115fef42f58086ee604ba1017b2230f0f4..7ab82bb582965909480eee1defb38a96fe149ec6 100644 (file)
@@ -2,7 +2,7 @@
 
 // @has foo/trait.LendingIterator.html
 pub trait LendingIterator {
-    // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a>where Self: 'a"
+    // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a"
     type Item<'a> where Self: 'a;
 
     // @has - '//*[@id="tymethod.next"]//h4[@class="code-header"]' \
@@ -23,7 +23,7 @@ fn next<'a>(&self) -> () {}
 pub struct Infinite<T>(T);
 
 // @has foo/trait.LendingIterator.html
-// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a>where Self: 'a = &'a T"
+// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a = &'a T"
 impl<T> LendingIterator for Infinite<T> {
     type Item<'a> where Self: 'a = &'a T;
 
index 7d810ab4813720120026e9f21a4c8fd0f15d0561..b6a1552bc00caccca655c5439f64878f9567d8d4 100644 (file)
@@ -11,7 +11,7 @@
 // @has impl_trait/fn.func2.html
 // @has - '//pre[@class="rust item-decl"]' "func2<T>("
 // @has - '//pre[@class="rust item-decl"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>,"
-// @has - '//pre[@class="rust item-decl"]' "_y: impl Iterator<Item = u8>)"
+// @has - '//pre[@class="rust item-decl"]' "_y: impl Iterator<Item = u8> )"
 // @!has - '//pre[@class="rust item-decl"]' 'where'
 pub use impl_trait_aux::func2;
 
index 91b67757453d2e788343eb82a15fa1d26313d309..4184086f622abaff7f57fb211360c358ccfe15c8 100644 (file)
@@ -2,5 +2,5 @@
 
 pub trait Bar {}
 
-// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T)where T: Bar;'
+// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T) where T: Bar;'
 pub struct Foo<T>(pub T) where T: Bar;
index 84ea4ad2c9ef30ea8fbb08b948661821ce29cbbe..571d7f06fdc62e401f5b5c161b9a7f79247f4e44 100644 (file)
@@ -98,7 +98,7 @@ pub mod inner {
         pub use reexports::foo;
         // @has 'foo/outer/inner/fn.foo_crate.html' '//pre[@class="rust item-decl"]' 'pub(crate) fn foo_crate()'
         pub(crate) use reexports::foo_crate;
-        // @has 'foo/outer/inner/fn.foo_super.html' '//pre[@class="rust item-decl"]' 'pub(in outer) fn foo_super()'
+        // @has 'foo/outer/inner/fn.foo_super.html' '//pre[@class="rust item-decl"]' 'pub(in outer) fn foo_super( )'
         pub(super) use::reexports::foo_super;
         // @!has 'foo/outer/inner/fn.foo_self.html'
         pub(self) use reexports::foo_self;
index 6f151f2328e4f69878f096086df403ef0610e6fa..ef4294c8f76d3c397131c17862c091e2de5f19f8 100644 (file)
@@ -1 +1,3 @@
-<pre class="rust item-decl"><code>pub struct Simd&lt;T&gt;(_)<br /><span class="where">where<br />&#160;&#160;&#160;&#160;T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre>
\ No newline at end of file
+<pre class="rust item-decl"><code>pub struct Simd&lt;T&gt;(_)
+<span class="where">where
+         T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre>
\ No newline at end of file
index 858bc142f66e136ae65a8c9de67afc8d8a26e4c7..e8ab061e679dd09f7f39d99ac6a5d397fa770da6 100644 (file)
@@ -1,8 +1,13 @@
 <pre class="rust item-decl"><code>pub trait TraitWhere {
-    type <a href="#associatedtype.Item" class="associatedtype">Item</a>&lt;'a&gt;<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span class="where">where Self: 'a</span>;
+    type <a href="#associatedtype.Item" class="associatedtype">Item</a>&lt;'a&gt;
+       <span class="where">where Self: 'a</span>;
 
     // Provided methods
-    fn <a href="#method.func" class="fn">func</a>(self)<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
-<span class="item-spacer" />    fn <a href="#method.lines" class="fn">lines</a>(self) -&gt; <a class="struct" href="{{channel}}/std/io/struct.Lines.html" title="struct std::io::Lines">Lines</a>&lt;Self&gt;<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
-<span class="item-spacer" />    fn <a href="#method.merge" class="fn">merge</a>&lt;T&gt;(self, a: T)<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;T: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
+    fn <a href="#method.func" class="fn">func</a>(self)
+       <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
+<span class="item-spacer" />    fn <a href="#method.lines" class="fn">lines</a>(self) -&gt; <a class="struct" href="{{channel}}/std/io/struct.Lines.html" title="struct std::io::Lines">Lines</a>&lt;Self&gt;
+       <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
+<span class="item-spacer" />    fn <a href="#method.merge" class="fn">merge</a>&lt;T&gt;(self, a: T)
+       <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,
+             T: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
 }</code></pre>
\ No newline at end of file
index af3239b69470c3b24e1c562c8b26a5f7e5accf14..8b8a126e89dd524c1364280c2f97445332bd1a98 100644 (file)
@@ -4,7 +4,7 @@
 
 pub trait MyTrait { fn dummy(&self) { } }
 
-// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_)where A: MyTrait"
+// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_) where A: MyTrait"
 pub struct Alpha<A>(A) where A: MyTrait;
 // @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B>where B: MyTrait"
 pub trait Bravo<B> where B: MyTrait { fn get(&self, B: B); }
index 904d461103617eefdc2fdc39f3db10c064c440cf..20b60b68e88cfed63dc3f9deb4a1c59fc19f2488 100644 (file)
@@ -1,4 +1,5 @@
-<pre class="rust item-decl"><code>pub enum Cow&lt;'a, B&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub enum Cow&lt;'a, B&gt;<span class="where fmt-newline">where
+    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
     Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a B</a>),
     Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
 }</code></pre>
\ No newline at end of file
index 54faee9e4052bc0da60e9db96d78e6fbd5a4bf6d..948ddc499da8ad9c8c2b24fc43eb1ab3ba87d1ee 100644 (file)
@@ -1,4 +1,5 @@
-<pre class="rust item-decl"><code>pub struct Struct&lt;'a, B&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub struct Struct&lt;'a, B&gt;<span class="where fmt-newline">where
+    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
     pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a B</a>,
     pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
 }</code></pre>
\ No newline at end of file
index 8a78e82dc71dca19394f518048d88da1eaffedb0..0928b48e6b64cf9b9b1d1e8f998e32532cde13ac 100644 (file)
@@ -1,4 +1,5 @@
-<pre class="rust item-decl"><code>pub trait ToOwned&lt;T&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</span>{
+<pre class="rust item-decl"><code>pub trait ToOwned&lt;T&gt;<span class="where fmt-newline">where
+    T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</span>{
     type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>;
 
     // Required methods
index 03a26280ba2cf9f5eb27e848f8651138227c8413..38b6cb8b5c6131ddc25fac5f75acd81eb9eb0550 100644 (file)
@@ -1,3 +1,4 @@
-<pre class="rust item-decl"><code>pub union Union&lt;'a, B&gt;<span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub union Union&lt;'a, B&gt;<span class="where fmt-newline">where
+    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
     /* private fields */
 }</code></pre>
\ No newline at end of file
index a65f84ae58eadd479dffcd1d22aac7e643993330..2281d9419b461e03853b2b3b03e348501cb1271e 100644 (file)
@@ -16,8 +16,8 @@ LL |     for<'b> <Self as UnsafeCopy<'b, T>>::Item: std::ops::Deref<Target = T>,
    |                                                                ^^^^^^^^^^ required by this bound in `UnsafeCopy`
 help: consider further restricting this bound
    |
-LL | impl<T: Copy + std::ops::Deref + Deref<Target = T>> UnsafeCopy<'_, T> for T {
-   |                                +++++++++++++++++++
+LL | impl<T: Copy + std::ops::Deref<Target = T>> UnsafeCopy<'_, T> for T {
+   |                               ++++++++++++
 
 error: aborting due to previous error
 
diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.rs b/tests/ui/async-await/future-sizes/async-awaiting-fut.rs
new file mode 100644 (file)
index 0000000..1816d84
--- /dev/null
@@ -0,0 +1,24 @@
+// compile-flags: -Z print-type-sizes --crate-type lib
+// edition:2021
+// build-pass
+// ignore-pass
+
+async fn wait() {}
+
+async fn big_fut(arg: [u8; 1024]) {}
+
+async fn calls_fut(fut: impl std::future::Future<Output = ()>) {
+    loop {
+        wait().await;
+        if true {
+            return fut.await;
+        } else {
+            wait().await;
+        }
+    }
+}
+
+pub async fn test() {
+    let fut = big_fut([0u8; 1024]);
+    calls_fut(fut).await;
+}
diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
new file mode 100644 (file)
index 0000000..eaf3e4b
--- /dev/null
@@ -0,0 +1,72 @@
+print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:21:21: 24:2]`: 3078 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 0 bytes
+print-type-size     variant `Suspend0`: 3077 bytes
+print-type-size         local `.__awaitee`: 3077 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Returned`: 0 bytes
+print-type-size     variant `Panicked`: 0 bytes
+print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]`: 3077 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 2051 bytes
+print-type-size         padding: 1026 bytes
+print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size     variant `Suspend0`: 2052 bytes
+print-type-size         local `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         local `..generator_field4`: 1 bytes
+print-type-size         padding: 1 bytes
+print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size         local `.__awaitee`: 1 bytes
+print-type-size     variant `Suspend1`: 3076 bytes
+print-type-size         padding: 1024 bytes
+print-type-size         local `..generator_field4`: 1 bytes, alignment: 1 bytes
+print-type-size         padding: 1 bytes
+print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size         local `.__awaitee`: 1025 bytes
+print-type-size     variant `Suspend2`: 2052 bytes
+print-type-size         local `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size         local `..generator_field4`: 1 bytes
+print-type-size         padding: 1 bytes
+print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size         local `.__awaitee`: 1 bytes
+print-type-size     variant `Returned`: 2051 bytes
+print-type-size         padding: 1026 bytes
+print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size     variant `Panicked`: 2051 bytes
+print-type-size         padding: 1026 bytes
+print-type-size         upvar `.fut`: 1025 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]>`: 3077 bytes, alignment: 1 bytes
+print-type-size     field `.value`: 3077 bytes
+print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2]>`: 3077 bytes, alignment: 1 bytes
+print-type-size     variant `MaybeUninit`: 3077 bytes
+print-type-size         field `.uninit`: 0 bytes
+print-type-size         field `.value`: 3077 bytes
+print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]`: 1025 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 1024 bytes
+print-type-size         upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Returned`: 1024 bytes
+print-type-size         upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size     variant `Panicked`: 1024 bytes
+print-type-size         upvar `.arg`: 1024 bytes, offset: 0 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]>`: 1025 bytes, alignment: 1 bytes
+print-type-size     field `.value`: 1025 bytes
+print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37]>`: 1025 bytes, alignment: 1 bytes
+print-type-size     variant `MaybeUninit`: 1025 bytes
+print-type-size         field `.uninit`: 0 bytes
+print-type-size         field `.value`: 1025 bytes
+print-type-size type: `[async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19]`: 1 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Unresumed`: 0 bytes
+print-type-size     variant `Returned`: 0 bytes
+print-type-size     variant `Panicked`: 0 bytes
+print-type-size type: `std::mem::ManuallyDrop<bool>`: 1 bytes, alignment: 1 bytes
+print-type-size     field `.value`: 1 bytes
+print-type-size type: `std::mem::MaybeUninit<bool>`: 1 bytes, alignment: 1 bytes
+print-type-size     variant `MaybeUninit`: 1 bytes
+print-type-size         field `.uninit`: 0 bytes
+print-type-size         field `.value`: 1 bytes
+print-type-size type: `std::task::Poll<()>`: 1 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Ready`: 0 bytes
+print-type-size         field `.0`: 0 bytes
+print-type-size     variant `Pending`: 0 bytes
index 8f8a8cee3a0ccfbed0c1d5b6e54ee94f29f0df00..81f28c1755deb452976804391ac6d6b5f9ce0d0b 100644 (file)
@@ -1,8 +1,7 @@
 // compile-flags: -Ztreat-err-as-bug=1
 // failure-status: 101
 // rustc-env:RUST_BACKTRACE=1
-// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
-// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "\nerror: .*unexpectedly panicked.*\n\n" -> ""
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
index b97975c4cd9e54b119b7165d38df8697949f9972..01fb8153cf3846c9be84c82096379456d5c275fc 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const-eval-query-stack.rs:17:16
+  --> $DIR/const-eval-query-stack.rs:16:16
    |
 LL | const X: i32 = 1 / 0;
    |                ^^^^^ attempt to divide `1_i32` by zero
index 62e28efab5820f73b90931e1041d45264a839d0a..0365d87a6f82aae88f3b23ce85dd8f398d69b2a1 100644 (file)
@@ -7,13 +7,13 @@ LL | #![feature(dyn_star)]
    = 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
+error[E0277]: `AlignedUsize` needs to have the same alignment and size as a pointer
   --> $DIR/align.rs:15:13
    |
 LL |     let x = AlignedUsize(12) as dyn* Debug;
-   |             ^^^^^^^^^^^^^^^^ `AlignedUsize` needs to be a pointer-sized type
+   |             ^^^^^^^^^^^^^^^^ `AlignedUsize` needs to be a pointer-like type
    |
-   = help: the trait `PointerSized` is not implemented for `AlignedUsize`
+   = help: the trait `PointerLike` is not implemented for `AlignedUsize`
 
 error: aborting due to previous error; 1 warning emitted
 
index fb41a05a0660ba19e45dc5f652b43fdf0f856111..6679997a9402917a5e269ce9ff576be23a481f07 100644 (file)
@@ -13,5 +13,5 @@
 
 fn main() {
     let x = AlignedUsize(12) as dyn* Debug;
-    //[over_aligned]~^ ERROR `AlignedUsize` needs to be a pointer-sized type
+    //[over_aligned]~^ ERROR `AlignedUsize` needs to have the same alignment and size as a pointer
 }
index e19e36cc7d7b5a7ed70400259361b3d009e3f5a8..85749aa7b00e2a886db52603620c04cdd4e05662 100644 (file)
@@ -9,7 +9,7 @@ fn dyn_debug(_: (dyn* Debug + '_)) {
 
 fn polymorphic<T: Debug + ?Sized>(t: &T) {
     dyn_debug(t);
-    //~^ ERROR `&T` needs to be a pointer-sized type
+    //~^ ERROR `&T` needs to have the same alignment and size as a pointer
 }
 
 fn main() {}
index 53ccbe43dcc9eea389cb3712f2e88028d378a8b6..350630f794138d31a4c28ffe45ed5c0bb0e29fb4 100644 (file)
@@ -1,14 +1,14 @@
-error[E0277]: `&T` needs to be a pointer-sized type
+error[E0277]: `&T` needs to have the same alignment and size as a pointer
   --> $DIR/check-size-at-cast-polymorphic-bad.rs:11:15
    |
 LL |     dyn_debug(t);
-   |               ^ `&T` needs to be a pointer-sized type
+   |               ^ `&T` needs to be a pointer-like type
    |
-   = help: the trait `PointerSized` is not implemented for `&T`
+   = help: the trait `PointerLike` is not implemented for `&T`
 help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
-LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerSized {
-   |                                          ++++++++++++++++++++++
+LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike {
+   |                                          +++++++++++++++++++++
 
 error: aborting due to previous error
 
index 1f22f798361541600bc877d8ee90fe2fe0565d2c..17bc4f303bffabd1ad541756d76b45e791fa61c4 100644 (file)
@@ -5,6 +5,6 @@
 
 fn main() {
     let i = [1, 2, 3, 4] as dyn* Debug;
-    //~^ ERROR `[i32; 4]` needs to be a pointer-sized type
+    //~^ ERROR `[i32; 4]` needs to have the same alignment and size as a pointer
     dbg!(i);
 }
index af2a1ccf71c6d6e7851c389a030aa4a0d43e2c0f..19700b40644006df9e1b388ade33cc10dad87b38 100644 (file)
@@ -1,10 +1,10 @@
-error[E0277]: `[i32; 4]` needs to be a pointer-sized type
+error[E0277]: `[i32; 4]` needs to have the same alignment and size as a pointer
   --> $DIR/check-size-at-cast.rs:7:13
    |
 LL |     let i = [1, 2, 3, 4] as dyn* Debug;
-   |             ^^^^^^^^^^^^ `[i32; 4]` needs to be a pointer-sized type
+   |             ^^^^^^^^^^^^ `[i32; 4]` needs to be a pointer-like type
    |
-   = help: the trait `PointerSized` is not implemented for `[i32; 4]`
+   = help: the trait `PointerLike` is not implemented for `[i32; 4]`
 
 error: aborting due to previous error
 
index 74ccd6a1889cd22c7028bb3f260b0f3c412f1bfd..e60144fea74c348aa3a425f99581d59b3f4f5bfd 100644 (file)
@@ -7,13 +7,13 @@ LL | #![feature(dyn_star, trait_upcasting)]
    = 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
+error[E0277]: `dyn* Foo` needs to have the same alignment and size as a pointer
   --> $DIR/upcast.rs:30:23
    |
 LL |     let w: dyn* Bar = w;
-   |                       ^ `dyn* Foo` needs to be a pointer-sized type
+   |                       ^ `dyn* Foo` needs to be a pointer-like type
    |
-   = help: the trait `PointerSized` is not implemented for `dyn* Foo`
+   = help: the trait `PointerLike` is not implemented for `dyn* Foo`
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/tests/ui/error-codes/E0523.rs b/tests/ui/error-codes/E0523.rs
new file mode 100644 (file)
index 0000000..47717fb
--- /dev/null
@@ -0,0 +1,14 @@
+// aux-build:crateresolve1-1.rs
+// aux-build:crateresolve1-2.rs
+// aux-build:crateresolve1-3.rs
+
+// normalize-stderr-test: "\.nll/" -> "/"
+// normalize-stderr-test: "\\\?\\" -> ""
+// normalize-stderr-test: "(lib)?crateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$2.somelib"
+
+// NOTE: This test is duplicated from `tests/ui/crate-loading/crateresolve1.rs`.
+
+extern crate crateresolve1;
+//~^ ERROR multiple candidates for `rlib` dependency `crateresolve1` found
+
+fn main() {}
diff --git a/tests/ui/error-codes/E0523.stderr b/tests/ui/error-codes/E0523.stderr
new file mode 100644 (file)
index 0000000..8e3eb21
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0464]: multiple candidates for `rlib` dependency `crateresolve1` found
+  --> $DIR/E0523.rs:11:1
+   |
+LL | extern crate crateresolve1;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: candidate #1: $TEST_BUILD_DIR/error-codes/E0523/auxiliary/libcrateresolve1-1.somelib
+   = note: candidate #2: $TEST_BUILD_DIR/error-codes/E0523/auxiliary/libcrateresolve1-2.somelib
+   = note: candidate #3: $TEST_BUILD_DIR/error-codes/E0523/auxiliary/libcrateresolve1-3.somelib
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0464`.
index bb741c0ef93fa8bf0d523f610c767200256fdece..5a18983a3fa709b892d0efa52feae2183d90a4aa 100644 (file)
@@ -3,7 +3,7 @@
 // known-bug: #106191
 // unset-rustc-env:RUST_BACKTRACE
 // had to be reverted
-// error-pattern:internal compiler error
+// error-pattern:unexpectedly panicked
 // failure-status:101
 // dont-check-compiler-stderr
 
index e8770aedfa1c7940318acbd9200731fa2a91b362..f0212e985a92cdd95e411b4fcc777ff8a6e859dc 100644 (file)
@@ -15,8 +15,8 @@ LL |     type Item<'a>: std::ops::Deref<Target = T>;
    |                                    ^^^^^^^^^^ required by this bound in `UnsafeCopy::Item`
 help: consider further restricting this bound
    |
-LL | impl<T: Copy + std::ops::Deref + Deref<Target = T>> UnsafeCopy<T> for T {
-   |                                +++++++++++++++++++
+LL | impl<T: Copy + std::ops::Deref<Target = T>> UnsafeCopy<T> for T {
+   |                               ++++++++++++
 
 error: aborting due to previous error
 
index ee758f19ec105345066f5437ce2e17aaf125cc63..054adbffbeafb66317e041b162ed5520584b4c3a 100644 (file)
@@ -4,7 +4,7 @@ use std::ops::Add;
 
 struct A<B>(B);
 
-impl<B> Add for A<B> where B: Add + Add<Output = B> {
+impl<B> Add for A<B> where B: Add<Output = B> {
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
@@ -14,7 +14,7 @@ impl<B> Add for A<B> where B: Add + Add<Output = B> {
 
 struct C<B>(B);
 
-impl<B: Add + Add<Output = B>> Add for C<B> {
+impl<B: Add<Output = B>> Add for C<B> {
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
@@ -34,7 +34,7 @@ impl<B: std::ops::Add<Output = B>> Add for D<B> {
 
 struct E<B>(B);
 
-impl<B: Add + Add<Output = B>> Add for E<B> where B: Add<Output = B> {
+impl<B: Add<Output = B>> Add for E<B> where B: Add<Output = B> {
     //~^ ERROR equality constraints are not yet supported in `where` clauses
     type Output = Self;
 
index 9f669b9a5214b1694bb3c42331ca48480826526f..535edec575a7d715f1e061740db25993337a3ac4 100644 (file)
@@ -37,8 +37,8 @@ LL | struct A<B>(B);
    |        ^
 help: consider further restricting this bound
    |
-LL | impl<B> Add for A<B> where B: Add + Add<Output = B> {
-   |                                   +++++++++++++++++
+LL | impl<B> Add for A<B> where B: Add<Output = B> {
+   |                                  ++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/missing-bounds.rs:21:14
@@ -60,8 +60,8 @@ LL | struct C<B>(B);
    |        ^
 help: consider further restricting this bound
    |
-LL | impl<B: Add + Add<Output = B>> Add for C<B> {
-   |             +++++++++++++++++
+LL | impl<B: Add<Output = B>> Add for C<B> {
+   |            ++++++++++++
 
 error[E0369]: cannot add `B` to `B`
   --> $DIR/missing-bounds.rs:31:21
@@ -96,8 +96,8 @@ LL | struct E<B>(B);
    |        ^
 help: consider further restricting this bound
    |
-LL | impl<B: Add + Add<Output = B>> Add for E<B> where <B as Add>::Output = B {
-   |             +++++++++++++++++
+LL | impl<B: Add<Output = B>> Add for E<B> where <B as Add>::Output = B {
+   |            ++++++++++++
 
 error: aborting due to 5 previous errors
 
index 6c4aa35679d5bc9f57abb1df07a1ace6a64f70d7..f3a773837785e3a98f80e9fcc421b06006b29cb4 100644 (file)
@@ -9,9 +9,7 @@ LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResu
 
 stack backtrace:
 
-error: internal compiler error: unexpected panic
-
-
+error: the compiler unexpectedly panicked. this is a bug.
 
 
 
diff --git a/tests/ui/issues/issue-92741.fixed b/tests/ui/issues/issue-92741.fixed
new file mode 100644 (file)
index 0000000..d07aeb6
--- /dev/null
@@ -0,0 +1,13 @@
+// run-rustfix
+fn main() {}
+fn _foo() -> bool {
+    if true { true } else { false }
+}
+
+fn _bar() -> bool {
+    if true { true } else { false }
+}
+
+fn _baz() -> bool {
+    if true { true } else { false }
+}
diff --git a/tests/ui/issues/issue-92741.rs b/tests/ui/issues/issue-92741.rs
new file mode 100644 (file)
index 0000000..413d5bf
--- /dev/null
@@ -0,0 +1,17 @@
+// run-rustfix
+fn main() {}
+fn _foo() -> bool {
+    &  //~ ERROR 4:5: 6:36: mismatched types [E0308]
+    mut
+    if true { true } else { false }
+}
+
+fn _bar() -> bool {
+    &  //~ ERROR 10:5: 11:40: mismatched types [E0308]
+    mut if true { true } else { false }
+}
+
+fn _baz() -> bool {
+    & mut //~ ERROR 15:5: 16:36: mismatched types [E0308]
+    if true { true } else { false }
+}
diff --git a/tests/ui/issues/issue-92741.stderr b/tests/ui/issues/issue-92741.stderr
new file mode 100644 (file)
index 0000000..49315e7
--- /dev/null
@@ -0,0 +1,49 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-92741.rs:4:5
+   |
+LL |   fn _foo() -> bool {
+   |                ---- expected `bool` because of return type
+LL | /     &
+LL | |     mut
+LL | |     if true { true } else { false }
+   | |___________________________________^ expected `bool`, found `&mut bool`
+   |
+help: consider removing the borrow
+   |
+LL -     &
+LL -     mut
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/issue-92741.rs:10:5
+   |
+LL |   fn _bar() -> bool {
+   |                ---- expected `bool` because of return type
+LL | /     &
+LL | |     mut if true { true } else { false }
+   | |_______________________________________^ expected `bool`, found `&mut bool`
+   |
+help: consider removing the borrow
+   |
+LL -     &
+LL -     mut if true { true } else { false }
+LL +     if true { true } else { false }
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/issue-92741.rs:15:5
+   |
+LL |   fn _baz() -> bool {
+   |                ---- expected `bool` because of return type
+LL | /     & mut
+LL | |     if true { true } else { false }
+   | |___________________________________^ expected `bool`, found `&mut bool`
+   |
+help: consider removing the borrow
+   |
+LL -     & mut
+   |
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 7398f01643f6eb9f35957c0fb07c9968ac0f54af..a3a514fb830958beb540e7452e46f0733f02c019 100644 (file)
@@ -1,4 +1,4 @@
-error: internal compiler error: unexpected panic
+error: the compiler unexpectedly panicked. this is a bug.
 
 query stack during panic:
 #0 [layout_of] computing layout of `Foo`
diff --git a/tests/ui/mir/issue-107678-projection-with-lifetime.rs b/tests/ui/mir/issue-107678-projection-with-lifetime.rs
new file mode 100644 (file)
index 0000000..14a4568
--- /dev/null
@@ -0,0 +1,20 @@
+// build-pass
+
+#![crate_type = "lib"]
+
+pub trait StreamOnce {
+    type Error;
+}
+
+pub trait ResetStream: StreamOnce {
+    fn reset(&mut self) -> Result<(), Self::Error>;
+}
+
+impl<'a> ResetStream for &'a str
+    where Self: StreamOnce
+{
+    #[inline]
+    fn reset(&mut self) -> Result<(), Self::Error> {
+        Ok(())
+    }
+}
diff --git a/tests/ui/mir/issue-107691.rs b/tests/ui/mir/issue-107691.rs
new file mode 100644 (file)
index 0000000..517a172
--- /dev/null
@@ -0,0 +1,42 @@
+// build-pass
+// compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+
+pub trait Archive {
+    type Archived;
+    type Resolver;
+
+    fn resolve(resolver: Self::Resolver, out: *mut Self::Archived);
+}
+
+pub type Archived<T> = <T as Archive>::Archived;
+pub type Resolver<T> = <T as Archive>::Resolver;
+
+pub struct Record<'a> {
+    _payload: &'a [u8],
+}
+
+pub struct ArchivedRecord<'a>
+where
+    &'a [u8]: Archive,
+{
+    _payload: Archived<&'a [u8]>,
+}
+
+pub struct RecordResolver<'a>
+where
+    &'a [u8]: Archive,
+{
+    _payload: Resolver<&'a [u8]>,
+}
+
+impl<'a> Archive for Record<'a>
+where
+    &'a [u8]: Archive,
+{
+    type Archived = ArchivedRecord<'a>;
+    type Resolver = RecordResolver<'a>;
+
+    fn resolve(_resolver: Self::Resolver, _out: *mut Self::Archived) {}
+}
index a0025d7e221ae1f35b764f596f68b6449976be92..7bf08bee9222465b3d01f963615c1fc7da3ba0aa 100644 (file)
@@ -4,9 +4,7 @@ LL | fn main() { missing_ident; }
 
 stack backtrace:
 
-error: internal compiler error: unexpected panic
-
-
+error: the compiler unexpectedly panicked. this is a bug.
 
 
 
index dde8ad1b6b327615fe66c1c2c75a644275dd3477..64683ae3a6ebd13c175e91fb9dce51109f22c756 100644 (file)
@@ -9,9 +9,11 @@ LL |     func(&mut iter.map(|x| x + 1))
    = help: a `loop` may express intention better if this is on purpose
    = note: `#[warn(unconditional_recursion)]` on by default
 
-error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<..., ...>, ...>, ...>, ...>: Iterator`
+error[E0275]: overflow evaluating the requirement `Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:12:24: 12:27]>: Iterator`
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`)
+   = note: required for `&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:12:24: 12:27]>` to implement `Iterator`
+   = note: 65 redundant requirements hidden
    = note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<..., ...>, ...>, ...>, ...>, ...>, ...>, ...>` to implement `Iterator`
    = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-83150/issue-83150.long-type-hash.txt'
 
diff --git a/tests/ui/suggestions/restrict-existing-type-bounds.rs b/tests/ui/suggestions/restrict-existing-type-bounds.rs
new file mode 100644 (file)
index 0000000..07712ce
--- /dev/null
@@ -0,0 +1,30 @@
+pub trait TryAdd<Rhs = Self> {
+    type Error;
+    type Output;
+
+    fn try_add(self, rhs: Rhs) -> Result<Self::Output, Self::Error>;
+}
+
+impl<T: TryAdd> TryAdd for Option<T> {
+    type Error = <T as TryAdd>::Error;
+    type Output = Option<<T as TryAdd>::Output>;
+
+    fn try_add(self, rhs: Self) -> Result<Self::Output, Self::Error> {
+        Ok(self) //~ ERROR mismatched types
+    }
+}
+
+struct Other<A>(A);
+
+struct X;
+
+impl<T: TryAdd<Error = X>> TryAdd for Other<T> {
+    type Error = <T as TryAdd>::Error;
+    type Output = Other<<T as TryAdd>::Output>;
+
+    fn try_add(self, rhs: Self) -> Result<Self::Output, Self::Error> {
+        Ok(self) //~ ERROR mismatched types
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/restrict-existing-type-bounds.stderr b/tests/ui/suggestions/restrict-existing-type-bounds.stderr
new file mode 100644 (file)
index 0000000..14a244b
--- /dev/null
@@ -0,0 +1,57 @@
+error[E0308]: mismatched types
+  --> $DIR/restrict-existing-type-bounds.rs:13:12
+   |
+LL | impl<T: TryAdd> TryAdd for Option<T> {
+   |      - this type parameter
+...
+LL |         Ok(self)
+   |         -- ^^^^ expected `Option<<T as TryAdd>::Output>`, found `Option<T>`
+   |         |
+   |         arguments to this enum variant are incorrect
+   |
+   = note: expected enum `Option<<T as TryAdd>::Output>`
+              found enum `Option<T>`
+help: the type constructed contains `Option<T>` due to the type of the argument passed
+  --> $DIR/restrict-existing-type-bounds.rs:13:9
+   |
+LL |         Ok(self)
+   |         ^^^----^
+   |            |
+   |            this argument influences the type of `Ok`
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+help: consider further restricting this bound
+   |
+LL | impl<T: TryAdd<Output = T>> TryAdd for Option<T> {
+   |               ++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/restrict-existing-type-bounds.rs:26:12
+   |
+LL | impl<T: TryAdd<Error = X>> TryAdd for Other<T> {
+   |      - this type parameter
+...
+LL |         Ok(self)
+   |         -- ^^^^ expected `Other<<T as TryAdd>::Output>`, found `Other<T>`
+   |         |
+   |         arguments to this enum variant are incorrect
+   |
+   = note: expected struct `Other<<T as TryAdd>::Output>`
+              found struct `Other<T>`
+help: the type constructed contains `Other<T>` due to the type of the argument passed
+  --> $DIR/restrict-existing-type-bounds.rs:26:9
+   |
+LL |         Ok(self)
+   |         ^^^----^
+   |            |
+   |            this argument influences the type of `Ok`
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+help: consider further restricting this bound
+   |
+LL | impl<T: TryAdd<Error = X, Output = T>> TryAdd for Other<T> {
+   |                         ++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 34199f8c37c101d2d7236a45ece953407427910d..80cd2ca7dfc9afd0e7f732c47ed84f8d61b2af9c 100644 (file)
@@ -12,7 +12,19 @@ fn main() {
     //~^ ERROR: mismatched types [E0308]
     //~| HELP: if you meant to write a byte literal, prefix with `b`
 
+    let _a: u8 = '\x20';
+    //~^ ERROR: mismatched types [E0308]
+    //~| HELP: if you meant to write a byte literal, prefix with `b`
+
+    // Do not issue the suggestion if the char literal is a Unicode escape
+    foo('\u{0080}');
+    //~^ ERROR: mismatched types [E0308]
+
     // Do not issue the suggestion if the char literal isn't ASCII
     let _t: u8 = '€';
     //~^ ERROR: mismatched types [E0308]
+
+    // Do not issue the suggestion if the char literal isn't ASCII
+    foo('\u{1f980}');
+    //~^ ERROR: mismatched types [E0308]
 }
index c9c2e7498d058c7953160e03f43494977bfa6deb..3d27149f0dcf13704a737b6541e94009b4800c7c 100644 (file)
@@ -30,13 +30,54 @@ LL |     foo(b'#');
    |         ~~~~
 
 error[E0308]: mismatched types
-  --> $DIR/type-mismatch-byte-literal.rs:16:18
+  --> $DIR/type-mismatch-byte-literal.rs:15:18
+   |
+LL |     let _a: u8 = '\x20';
+   |             --   ^^^^^^ expected `u8`, found `char`
+   |             |
+   |             expected due to this
+   |
+help: if you meant to write a byte literal, prefix with `b`
+   |
+LL |     let _a: u8 = b'\x20';
+   |                  ~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch-byte-literal.rs:20:9
+   |
+LL |     foo('\u{0080}');
+   |     --- ^^^^^^^^^^ expected `u8`, found `char`
+   |     |
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/type-mismatch-byte-literal.rs:4:4
+   |
+LL | fn foo(_t: u8) {}
+   |    ^^^ ------
+
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch-byte-literal.rs:24:18
    |
 LL |     let _t: u8 = '€';
    |             --   ^^^ expected `u8`, found `char`
    |             |
    |             expected due to this
 
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch-byte-literal.rs:28:9
+   |
+LL |     foo('\u{1f980}');
+   |     --- ^^^^^^^^^^^ expected `u8`, found `char`
+   |     |
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/type-mismatch-byte-literal.rs:4:4
+   |
+LL | fn foo(_t: u8) {}
+   |    ^^^ ------
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/new-solver/pointer-like.rs b/tests/ui/traits/new-solver/pointer-like.rs
new file mode 100644 (file)
index 0000000..3745a07
--- /dev/null
@@ -0,0 +1,14 @@
+// compile-flags: -Ztrait-solver=next
+
+#![feature(pointer_like_trait)]
+
+use std::marker::PointerLike;
+
+fn require_(_: impl PointerLike) {}
+
+fn main() {
+    require_(1usize);
+    require_(1u16);
+    //~^ ERROR `u16` needs to have the same alignment and size as a pointer
+    require_(&1i16);
+}
diff --git a/tests/ui/traits/new-solver/pointer-like.stderr b/tests/ui/traits/new-solver/pointer-like.stderr
new file mode 100644 (file)
index 0000000..f695e64
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0277]: `u16` needs to have the same alignment and size as a pointer
+  --> $DIR/pointer-like.rs:11:14
+   |
+LL |     require_(1u16);
+   |     -------- ^^^^ the trait `PointerLike` is not implemented for `u16`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: the trait bound `u16: PointerLike` is not satisfied
+note: required by a bound in `require_`
+  --> $DIR/pointer-like.rs:7:21
+   |
+LL | fn require_(_: impl PointerLike) {}
+   |                     ^^^^^^^^^^^ required by this bound in `require_`
+help: consider borrowing here
+   |
+LL |     require_(&1u16);
+   |              +
+LL |     require_(&mut 1u16);
+   |              ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/new-solver/pointer-sized.rs b/tests/ui/traits/new-solver/pointer-sized.rs
deleted file mode 100644 (file)
index 15681cd..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#![feature(pointer_sized_trait)]
-
-use std::marker::PointerSized;
-
-fn require_pointer_sized(_: impl PointerSized) {}
-
-fn main() {
-    require_pointer_sized(1usize);
-    require_pointer_sized(1u16);
-    //~^ ERROR `u16` needs to be a pointer-sized type
-    require_pointer_sized(&1i16);
-}
diff --git a/tests/ui/traits/new-solver/pointer-sized.stderr b/tests/ui/traits/new-solver/pointer-sized.stderr
deleted file mode 100644 (file)
index b250b13..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-error[E0277]: `u16` needs to be a pointer-sized type
-  --> $DIR/pointer-sized.rs:9:27
-   |
-LL |     require_pointer_sized(1u16);
-   |     --------------------- ^^^^ the trait `PointerSized` is not implemented for `u16`
-   |     |
-   |     required by a bound introduced by this call
-   |
-   = note: the trait bound `u16: PointerSized` is not satisfied
-note: required by a bound in `require_pointer_sized`
-  --> $DIR/pointer-sized.rs:5:34
-   |
-LL | fn require_pointer_sized(_: impl PointerSized) {}
-   |                                  ^^^^^^^^^^^^ required by this bound in `require_pointer_sized`
-help: consider borrowing here
-   |
-LL |     require_pointer_sized(&1u16);
-   |                           +
-LL |     require_pointer_sized(&mut 1u16);
-   |                           ++++
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
index e9457c8faff4d349bad987563af0f9862c163cbc..22c6175048a63ecff25877a248f98d99c970b54a 100644 (file)
@@ -4,7 +4,7 @@ error: internal compiler error: delayed span bug triggered by #[rustc_error(dela
 LL | fn main() {}
    | ^^^^^^^^^
 
-error: internal compiler error: unexpected panic
+error: the compiler unexpectedly panicked. this is a bug.
 
 query stack during panic:
 #0 [trigger_delay_span_bug] triggering a delay span bug
index 8f67571c2990ea56a1c2494fd2331fb36cb5423f..3a56445a26b58102caea740bef520fef157f3a00 100644 (file)
@@ -4,7 +4,7 @@ error[E0080]: could not evaluate static initializer
 LL | pub static C: u32 = 0 - 1;
    |                     ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
 
-error: internal compiler error: unexpected panic
+error: the compiler unexpectedly panicked. this is a bug.
 
 query stack during panic:
 #0 [eval_to_allocation_raw] const-evaluating + checking `C`
diff --git a/tests/ui/typeck/issue-107775.rs b/tests/ui/typeck/issue-107775.rs
new file mode 100644 (file)
index 0000000..6fbac2e
--- /dev/null
@@ -0,0 +1,40 @@
+// edition: 2021
+
+use std::collections::HashMap;
+use std::future::Future;
+use std::pin::Pin;
+
+pub trait Trait {
+    fn do_something<'async_trait>(byte: u8)
+    ->
+        Pin<Box<dyn Future<Output = ()> +
+        Send + 'async_trait>>;
+}
+
+pub struct Struct;
+
+impl Trait for Struct {
+    fn do_something<'async_trait>(byte: u8)
+        ->
+            Pin<Box<dyn Future<Output = ()> +
+            Send + 'async_trait>> {
+        Box::pin(
+
+            async move { let byte = byte; let _: () = {}; })
+    }
+}
+
+pub struct Map {
+    map: HashMap<u16, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
+}
+
+impl Map {
+    pub fn new() -> Self {
+        let mut map = HashMap::new();
+        map.insert(1, Struct::do_something);
+        Self { map }
+        //~^ ERROR mismatched types
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/issue-107775.stderr b/tests/ui/typeck/issue-107775.stderr
new file mode 100644 (file)
index 0000000..9ee9c02
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-107775.rs:35:16
+   |
+LL |         map.insert(1, Struct::do_something);
+   |                    -  -------------------- this is of type `fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}`, which causes `map` to be inferred as `HashMap<{integer}, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
+   |                    |
+   |                    this is of type `{integer}`, which causes `map` to be inferred as `HashMap<{integer}, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
+LL |         Self { map }
+   |                ^^^ expected `HashMap<u16, fn(u8) -> Pin<...>>`, found `HashMap<{integer}, ...>`
+   |
+   = note: expected struct `HashMap<u16, fn(_) -> Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>>`
+              found struct `HashMap<{integer}, fn(_) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.