about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs28
-rw-r--r--library/core/src/iter/adapters/array_chunks.rs19
-rw-r--r--library/core/src/iter/adapters/map_while.rs14
-rw-r--r--library/core/src/iter/adapters/mod.rs11
-rw-r--r--library/core/src/iter/adapters/scan.rs14
-rw-r--r--library/core/src/iter/adapters/skip.rs12
-rw-r--r--library/core/src/iter/adapters/take.rs14
-rw-r--r--library/core/src/iter/adapters/take_while.rs14
-rw-r--r--library/core/src/iter/mod.rs23
-rw-r--r--library/core/src/iter/range.rs28
-rw-r--r--library/std/src/io/buffered/bufreader.rs8
-rw-r--r--library/std/src/io/buffered/bufreader/buffer.rs19
-rw-r--r--library/std/src/io/buffered/tests.rs24
-rw-r--r--library/std/src/keyword_docs.rs151
-rwxr-xr-xsrc/ci/scripts/should-skip-this.sh5
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-102768.rs14
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-102768.stderr33
-rw-r--r--src/test/ui/object-safety/issue-102762.rs26
-rw-r--r--src/test/ui/object-safety/issue-102762.stderr20
20 files changed, 319 insertions, 164 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index f8a62c84910..5972f6b8800 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -493,8 +493,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                         },
                         def_id.to_def_id(),
                     );
-                    if let Some(assoc_item) = assoc_item {
-                        tcx.type_of(tcx.generics_of(assoc_item.def_id).params[idx].def_id)
+                    if let Some(param)
+                        = assoc_item.map(|item| &tcx.generics_of(item.def_id).params[idx]).filter(|param| param.kind.is_ty_or_const())
+                    {
+                        tcx.type_of(param.def_id)
                     } else {
                         // FIXME(associated_const_equality): add a useful error message here.
                         tcx.ty_error_with_message(
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 31dd30c5c6a..52ee5e6ea93 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -447,19 +447,6 @@ fn virtual_call_violation_for_method<'tcx>(
         return Some(MethodViolationCode::Generic);
     }
 
-    if tcx
-        .predicates_of(method.def_id)
-        .predicates
-        .iter()
-        // A trait object can't claim to live more than the concrete type,
-        // so outlives predicates will always hold.
-        .cloned()
-        .filter(|(p, _)| p.to_opt_type_outlives().is_none())
-        .any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred))
-    {
-        return Some(MethodViolationCode::WhereClauseReferencesSelf);
-    }
-
     let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
 
     // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
@@ -538,6 +525,21 @@ fn virtual_call_violation_for_method<'tcx>(
         }
     }
 
+    // NOTE: This check happens last, because it results in a lint, and not a
+    // hard error.
+    if tcx
+        .predicates_of(method.def_id)
+        .predicates
+        .iter()
+        // A trait object can't claim to live more than the concrete type,
+        // so outlives predicates will always hold.
+        .cloned()
+        .filter(|(p, _)| p.to_opt_type_outlives().is_none())
+        .any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred))
+    {
+        return Some(MethodViolationCode::WhereClauseReferencesSelf);
+    }
+
     None
 }
 
diff --git a/library/core/src/iter/adapters/array_chunks.rs b/library/core/src/iter/adapters/array_chunks.rs
index 489fb13c0dc..d4fb886101f 100644
--- a/library/core/src/iter/adapters/array_chunks.rs
+++ b/library/core/src/iter/adapters/array_chunks.rs
@@ -1,7 +1,6 @@
 use crate::array;
-use crate::const_closure::ConstFnMutClosure;
 use crate::iter::{ByRefSized, FusedIterator, Iterator};
-use crate::ops::{ControlFlow, NeverShortCircuit, Try};
+use crate::ops::{ControlFlow, Try};
 
 /// An iterator over `N` elements of the iterator at a time.
 ///
@@ -83,13 +82,7 @@ where
         }
     }
 
-    fn fold<B, F>(mut self, init: B, mut f: F) -> B
-    where
-        Self: Sized,
-        F: FnMut(B, Self::Item) -> B,
-    {
-        self.try_fold(init, ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp)).0
-    }
+    impl_fold_via_try_fold! { fold -> try_fold }
 }
 
 #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
@@ -127,13 +120,7 @@ where
         try { acc }
     }
 
-    fn rfold<B, F>(mut self, init: B, mut f: F) -> B
-    where
-        Self: Sized,
-        F: FnMut(B, Self::Item) -> B,
-    {
-        self.try_rfold(init, ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp)).0
-    }
+    impl_fold_via_try_fold! { rfold -> try_rfold }
 }
 
 impl<I, const N: usize> ArrayChunks<I, N>
diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs
index 1e8d6bf3e00..fbdeca4d4ee 100644
--- a/library/core/src/iter/adapters/map_while.rs
+++ b/library/core/src/iter/adapters/map_while.rs
@@ -64,19 +64,7 @@ where
         .into_try()
     }
 
-    #[inline]
-    fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
-    where
-        Self: Sized,
-        Fold: FnMut(Acc, Self::Item) -> Acc,
-    {
-        #[inline]
-        fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
-            move |acc, x| Ok(f(acc, x))
-        }
-
-        self.try_fold(init, ok(fold)).unwrap()
-    }
+    impl_fold_via_try_fold! { fold -> try_fold }
 }
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index de3a534f81b..8cc2b7cec41 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -1,6 +1,5 @@
-use crate::const_closure::ConstFnMutClosure;
 use crate::iter::{InPlaceIterable, Iterator};
-use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, NeverShortCircuit, Residual, Try};
+use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
 
 mod array_chunks;
 mod by_ref_sized;
@@ -204,13 +203,7 @@ where
             .into_try()
     }
 
-    fn fold<B, F>(mut self, init: B, mut fold: F) -> B
-    where
-        Self: Sized,
-        F: FnMut(B, Self::Item) -> B,
-    {
-        self.try_fold(init, ConstFnMutClosure::new(&mut fold, NeverShortCircuit::wrap_mut_2_imp)).0
-    }
+    impl_fold_via_try_fold! { fold -> try_fold }
 }
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
diff --git a/library/core/src/iter/adapters/scan.rs b/library/core/src/iter/adapters/scan.rs
index 80bfd223124..62470512cc7 100644
--- a/library/core/src/iter/adapters/scan.rs
+++ b/library/core/src/iter/adapters/scan.rs
@@ -74,19 +74,7 @@ where
         self.iter.try_fold(init, scan(state, f, fold)).into_try()
     }
 
-    #[inline]
-    fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
-    where
-        Self: Sized,
-        Fold: FnMut(Acc, Self::Item) -> Acc,
-    {
-        #[inline]
-        fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
-            move |acc, x| Ok(f(acc, x))
-        }
-
-        self.try_fold(init, ok(fold)).unwrap()
-    }
+    impl_fold_via_try_fold! { fold -> try_fold }
 }
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs
index dbf0ae9eca3..c6334880db5 100644
--- a/library/core/src/iter/adapters/skip.rs
+++ b/library/core/src/iter/adapters/skip.rs
@@ -206,17 +206,7 @@ where
         if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() }
     }
 
-    fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
-    where
-        Fold: FnMut(Acc, Self::Item) -> Acc,
-    {
-        #[inline]
-        fn ok<Acc, T>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, T) -> Result<Acc, !> {
-            move |acc, x| Ok(f(acc, x))
-        }
-
-        self.try_rfold(init, ok(fold)).unwrap()
-    }
+    impl_fold_via_try_fold! { rfold -> try_rfold }
 
     #[inline]
     fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs
index 2962e0104d1..58a0b9d7bbe 100644
--- a/library/core/src/iter/adapters/take.rs
+++ b/library/core/src/iter/adapters/take.rs
@@ -98,19 +98,7 @@ where
         }
     }
 
-    #[inline]
-    fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
-    where
-        Self: Sized,
-        Fold: FnMut(Acc, Self::Item) -> Acc,
-    {
-        #[inline]
-        fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
-            move |acc, x| Ok(f(acc, x))
-        }
-
-        self.try_fold(init, ok(fold)).unwrap()
-    }
+    impl_fold_via_try_fold! { fold -> try_fold }
 
     #[inline]
     #[rustc_inherit_overflow_checks]
diff --git a/library/core/src/iter/adapters/take_while.rs b/library/core/src/iter/adapters/take_while.rs
index ded216da952..ec66dc3aec3 100644
--- a/library/core/src/iter/adapters/take_while.rs
+++ b/library/core/src/iter/adapters/take_while.rs
@@ -94,19 +94,7 @@ where
         }
     }
 
-    #[inline]
-    fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
-    where
-        Self: Sized,
-        Fold: FnMut(Acc, Self::Item) -> Acc,
-    {
-        #[inline]
-        fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
-            move |acc, x| Ok(f(acc, x))
-        }
-
-        self.try_fold(init, ok(fold)).unwrap()
-    }
+    impl_fold_via_try_fold! { fold -> try_fold }
 }
 
 #[stable(feature = "fused", since = "1.26.0")]
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index 9514466bd0c..ef0f397825b 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -352,6 +352,29 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+// This needs to be up here in order to be usable in the child modules
+macro_rules! impl_fold_via_try_fold {
+    (fold -> try_fold) => {
+        impl_fold_via_try_fold! { @internal fold -> try_fold }
+    };
+    (rfold -> try_rfold) => {
+        impl_fold_via_try_fold! { @internal rfold -> try_rfold }
+    };
+    (@internal $fold:ident -> $try_fold:ident) => {
+        #[inline]
+        fn $fold<AAA, FFF>(mut self, init: AAA, mut fold: FFF) -> AAA
+        where
+            FFF: FnMut(AAA, Self::Item) -> AAA,
+        {
+            use crate::const_closure::ConstFnMutClosure;
+            use crate::ops::NeverShortCircuit;
+
+            let fold = ConstFnMutClosure::new(&mut fold, NeverShortCircuit::wrap_mut_2_imp);
+            self.$try_fold(init, fold).0
+        }
+    };
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::traits::Iterator;
 
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index f7aeee8c9ad..ac7b389b15b 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -1150,19 +1150,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
         self.spec_try_fold(init, f)
     }
 
-    #[inline]
-    fn fold<B, F>(mut self, init: B, f: F) -> B
-    where
-        Self: Sized,
-        F: FnMut(B, Self::Item) -> B,
-    {
-        #[inline]
-        fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
-            move |acc, x| Ok(f(acc, x))
-        }
-
-        self.try_fold(init, ok(f)).unwrap()
-    }
+    impl_fold_via_try_fold! { fold -> try_fold }
 
     #[inline]
     fn last(mut self) -> Option<A> {
@@ -1230,19 +1218,7 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
         self.spec_try_rfold(init, f)
     }
 
-    #[inline]
-    fn rfold<B, F>(mut self, init: B, f: F) -> B
-    where
-        Self: Sized,
-        F: FnMut(B, Self::Item) -> B,
-    {
-        #[inline]
-        fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
-            move |acc, x| Ok(f(acc, x))
-        }
-
-        self.try_rfold(init, ok(f)).unwrap()
-    }
+    impl_fold_via_try_fold! { rfold -> try_rfold }
 }
 
 // Safety: See above implementation for `ops::Range<A>`
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 88ad92d8a98..4f339a18a48 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -224,6 +224,14 @@ impl<R> BufReader<R> {
     }
 }
 
+// This is only used by a test which asserts that the initialization-tracking is correct.
+#[cfg(test)]
+impl<R> BufReader<R> {
+    pub fn initialized(&self) -> usize {
+        self.buf.initialized()
+    }
+}
+
 impl<R: Seek> BufReader<R> {
     /// Seeks relative to the current position. If the new position lies within the buffer,
     /// the buffer will not be flushed, allowing for more efficient seeks.
diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs
index 867c22c6041..e9e29d60ca2 100644
--- a/library/std/src/io/buffered/bufreader/buffer.rs
+++ b/library/std/src/io/buffered/bufreader/buffer.rs
@@ -20,13 +20,19 @@ pub struct Buffer {
     // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are
     // initialized with bytes from a read.
     filled: usize,
+    // This is the max number of bytes returned across all `fill_buf` calls. We track this so that we
+    // can accurately tell `read_buf` how many bytes of buf are initialized, to bypass as much of its
+    // defensive initialization as possible. Note that while this often the same as `filled`, it
+    // doesn't need to be. Calls to `fill_buf` are not required to actually fill the buffer, and
+    // omitting this is a huge perf regression for `Read` impls that do not.
+    initialized: usize,
 }
 
 impl Buffer {
     #[inline]
     pub fn with_capacity(capacity: usize) -> Self {
         let buf = Box::new_uninit_slice(capacity);
-        Self { buf, pos: 0, filled: 0 }
+        Self { buf, pos: 0, filled: 0, initialized: 0 }
     }
 
     #[inline]
@@ -51,6 +57,12 @@ impl Buffer {
         self.pos
     }
 
+    // This is only used by a test which asserts that the initialization-tracking is correct.
+    #[cfg(test)]
+    pub fn initialized(&self) -> usize {
+        self.initialized
+    }
+
     #[inline]
     pub fn discard_buffer(&mut self) {
         self.pos = 0;
@@ -96,13 +108,14 @@ impl Buffer {
             let mut buf = BorrowedBuf::from(&mut *self.buf);
             // SAFETY: `self.filled` bytes will always have been initialized.
             unsafe {
-                buf.set_init(self.filled);
+                buf.set_init(self.initialized);
             }
 
             reader.read_buf(buf.unfilled())?;
 
-            self.filled = buf.len();
             self.pos = 0;
+            self.filled = buf.len();
+            self.initialized = buf.init_len();
         }
         Ok(self.buffer())
     }
diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs
index bd6d95242ad..f4e688eb926 100644
--- a/library/std/src/io/buffered/tests.rs
+++ b/library/std/src/io/buffered/tests.rs
@@ -1039,3 +1039,27 @@ fn single_formatted_write() {
     writeln!(&mut writer, "{}, {}!", "hello", "world").unwrap();
     assert_eq!(writer.get_ref().events, [RecordedEvent::Write("hello, world!\n".to_string())]);
 }
+
+#[test]
+fn bufreader_full_initialize() {
+    struct OneByteReader;
+    impl Read for OneByteReader {
+        fn read(&mut self, buf: &mut [u8]) -> crate::io::Result<usize> {
+            if buf.len() > 0 {
+                buf[0] = 0;
+                Ok(1)
+            } else {
+                Ok(0)
+            }
+        }
+    }
+    let mut reader = BufReader::new(OneByteReader);
+    // Nothing is initialized yet.
+    assert_eq!(reader.initialized(), 0);
+
+    let buf = reader.fill_buf().unwrap();
+    // We read one byte...
+    assert_eq!(buf.len(), 1);
+    // But we initialized the whole buffer!
+    assert_eq!(reader.initialized(), reader.capacity());
+}
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index a4b0522b050..e35145c4ade 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -1867,11 +1867,15 @@ mod type_keyword {}
 /// Code or interfaces whose [memory safety] cannot be verified by the type
 /// system.
 ///
-/// The `unsafe` keyword has two uses: to declare the existence of contracts the
-/// compiler can't check (`unsafe fn` and `unsafe trait`), and to declare that a
-/// programmer has checked that these contracts have been upheld (`unsafe {}`
-/// and `unsafe impl`, but also `unsafe fn` -- see below). They are not mutually
-/// exclusive, as can be seen in `unsafe fn`.
+/// The `unsafe` keyword has two uses:
+/// - to declare the existence of contracts the compiler can't check (`unsafe fn` and `unsafe
+/// trait`),
+/// - and to declare that a programmer has checked that these contracts have been upheld (`unsafe
+/// {}` and `unsafe impl`, but also `unsafe fn` -- see below).
+///
+/// They are not mutually exclusive, as can be seen in `unsafe fn`: the body of an `unsafe fn` is,
+/// by default, treated like an unsafe block. The `unsafe_op_in_unsafe_fn` lint can be enabled to
+/// change that.
 ///
 /// # Unsafe abilities
 ///
@@ -1914,12 +1918,12 @@ mod type_keyword {}
 /// - `unsafe impl`: the contract necessary to implement the trait has been
 /// checked by the programmer and is guaranteed to be respected.
 ///
-/// `unsafe fn` also acts like an `unsafe {}` block
+/// By default, `unsafe fn` also acts like an `unsafe {}` block
 /// around the code inside the function. This means it is not just a signal to
 /// the caller, but also promises that the preconditions for the operations
-/// inside the function are upheld. Mixing these two meanings can be confusing
-/// and [proposal]s exist to use `unsafe {}` blocks inside such functions when
-/// making `unsafe` operations.
+/// inside the function are upheld. Mixing these two meanings can be confusing, so the
+/// `unsafe_op_in_unsafe_fn` lint can be enabled to warn against that and require explicit unsafe
+/// blocks even inside `unsafe fn`.
 ///
 /// See the [Rustnomicon] and the [Reference] for more information.
 ///
@@ -1987,13 +1991,16 @@ mod type_keyword {}
 ///
 /// ```rust
 /// # #![allow(dead_code)]
+/// #![deny(unsafe_op_in_unsafe_fn)]
+///
 /// /// Dereference the given pointer.
 /// ///
 /// /// # Safety
 /// ///
 /// /// `ptr` must be aligned and must not be dangling.
 /// unsafe fn deref_unchecked(ptr: *const i32) -> i32 {
-///     *ptr
+///     // SAFETY: the caller is required to ensure that `ptr` is aligned and dereferenceable.
+///     unsafe { *ptr }
 /// }
 ///
 /// let a = 3;
@@ -2003,35 +2010,118 @@ mod type_keyword {}
 /// unsafe { assert_eq!(*b, deref_unchecked(b)); };
 /// ```
 ///
-/// Traits marked as `unsafe` must be [`impl`]emented using `unsafe impl`. This
-/// makes a guarantee to other `unsafe` code that the implementation satisfies
-/// the trait's safety contract. The [Send] and [Sync] traits are examples of
-/// this behaviour in the standard library.
+/// ## `unsafe` and traits
+///
+/// The interactions of `unsafe` and traits can be surprising, so let us contrast the
+/// two combinations of safe `fn` in `unsafe trait` and `unsafe fn` in safe trait using two
+/// examples:
+///
+/// ```rust
+/// /// # Safety
+/// ///
+/// /// `make_even` must return an even number.
+/// unsafe trait MakeEven {
+///     fn make_even(&self) -> i32;
+/// }
+///
+/// // SAFETY: Our `make_even` always returns something even.
+/// unsafe impl MakeEven for i32 {
+///     fn make_even(&self) -> i32 {
+///         self << 1
+///     }
+/// }
+///
+/// fn use_make_even(x: impl MakeEven) {
+///     if x.make_even() % 2 == 1 {
+///         // SAFETY: this can never happen, because all `MakeEven` implementations
+///         // ensure that `make_even` returns something even.
+///         unsafe { std::hint::unreachable_unchecked() };
+///     }
+/// }
+/// ```
+///
+/// Note how the safety contract of the trait is upheld by the implementation, and is itself used to
+/// uphold the safety contract of the unsafe function `unreachable_unchecked` called by
+/// `use_make_even`. `make_even` itself is a safe function because its *callers* do not have to
+/// worry about any contract, only the *implementation* of `MakeEven` is required to uphold a
+/// certain contract. `use_make_even` is safe because it can use the promise made by `MakeEven`
+/// implementations to uphold the safety contract of the `unsafe fn unreachable_unchecked` it calls.
+///
+/// It is also possible to have `unsafe fn` in a regular safe `trait`:
 ///
 /// ```rust
-/// /// Implementors of this trait must guarantee an element is always
-/// /// accessible with index 3.
-/// unsafe trait ThreeIndexable<T> {
-///     /// Returns a reference to the element with index 3 in `&self`.
-///     fn three(&self) -> &T;
+/// # #![feature(never_type)]
+/// #![deny(unsafe_op_in_unsafe_fn)]
+///
+/// trait Indexable {
+///     const LEN: usize;
+///
+///     /// # Safety
+///     ///
+///     /// The caller must ensure that `idx < LEN`.
+///     unsafe fn idx_unchecked(&self, idx: usize) -> i32;
 /// }
 ///
-/// // The implementation of `ThreeIndexable` for `[T; 4]` is `unsafe`
-/// // because the implementor must abide by a contract the compiler cannot
-/// // check but as a programmer we know there will always be a valid element
-/// // at index 3 to access.
-/// unsafe impl<T> ThreeIndexable<T> for [T; 4] {
-///     fn three(&self) -> &T {
-///         // SAFETY: implementing the trait means there always is an element
-///         // with index 3 accessible.
-///         unsafe { self.get_unchecked(3) }
+/// // The implementation for `i32` doesn't need to do any contract reasoning.
+/// impl Indexable for i32 {
+///     const LEN: usize = 1;
+///
+///     unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
+///         debug_assert_eq!(idx, 0);
+///         *self
 ///     }
 /// }
 ///
-/// let a = [1, 2, 4, 8];
-/// assert_eq!(a.three(), &8);
+/// // The implementation for arrays exploits the function contract to
+/// // make use of `get_unchecked` on slices and avoid a run-time check.
+/// impl Indexable for [i32; 42] {
+///     const LEN: usize = 42;
+///
+///     unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
+///         // SAFETY: As per this trait's documentation, the caller ensures
+///         // that `idx < 42`.
+///         unsafe { *self.get_unchecked(idx) }
+///     }
+/// }
+///
+/// // The implementation for the never type declares a length of 0,
+/// // which means `idx_unchecked` can never be called.
+/// impl Indexable for ! {
+///     const LEN: usize = 0;
+///
+///     unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
+///         // SAFETY: As per this trait's documentation, the caller ensures
+///         // that `idx < 0`, which is impossible, so this is dead code.
+///         unsafe { std::hint::unreachable_unchecked() }
+///     }
+/// }
+///
+/// fn use_indexable<I: Indexable>(x: I, idx: usize) -> i32 {
+///     if idx < I::LEN {
+///         // SAFETY: We have checked that `idx < I::LEN`.
+///         unsafe { x.idx_unchecked(idx) }
+///     } else {
+///         panic!("index out-of-bounds")
+///     }
+/// }
 /// ```
 ///
+/// This time, `use_indexable` is safe because it uses a run-time check to discharge the safety
+/// contract of `idx_unchecked`. Implementing `Indexable` is safe because when writing
+/// `idx_unchecked`, we don't have to worry: our *callers* need to discharge a proof obligation
+/// (like `use_indexable` does), but the *implementation* of `get_unchecked` has no proof obligation
+/// to contend with. Of course, the implementation of `Indexable` may choose to call other unsafe
+/// operations, and then it needs an `unsafe` *block* to indicate it discharged the proof
+/// obligations of its callees. (We enabled `unsafe_op_in_unsafe_fn`, so the body of `idx_unchecked`
+/// is not implicitly an unsafe block.) For that purpose it can make use of the contract that all
+/// its callers must uphold -- the fact that `idx < LEN`.
+///
+/// Formally speaking, an `unsafe fn` in a trait is a function with *preconditions* that go beyond
+/// those encoded by the argument types (such as `idx < LEN`), whereas an `unsafe trait` can declare
+/// that some of its functions have *postconditions* that go beyond those encoded in the return type
+/// (such as returning an even integer). If a trait needs a function with both extra precondition
+/// and extra postcondition, then it needs an `unsafe fn` in an `unsafe trait`.
+///
 /// [`extern`]: keyword.extern.html
 /// [`trait`]: keyword.trait.html
 /// [`static`]: keyword.static.html
@@ -2043,7 +2133,6 @@ mod type_keyword {}
 /// [nomicon-soundness]: ../nomicon/safe-unsafe-meaning.html
 /// [soundness]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library
 /// [Reference]: ../reference/unsafety.html
-/// [proposal]: https://github.com/rust-lang/rfcs/pull/2585
 /// [discussion on Rust Internals]: https://internals.rust-lang.org/t/what-does-unsafe-mean/6696
 mod unsafe_keyword {}
 
diff --git a/src/ci/scripts/should-skip-this.sh b/src/ci/scripts/should-skip-this.sh
index 67ff00cc1df..60c2960b160 100755
--- a/src/ci/scripts/should-skip-this.sh
+++ b/src/ci/scripts/should-skip-this.sh
@@ -19,9 +19,12 @@ if [[ -n "${CI_ONLY_WHEN_SUBMODULES_CHANGED-}" ]]; then
         # 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); then
+             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" -- \
              src/test/rustdoc-gui \
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-102768.rs b/src/test/ui/const-generics/generic_const_exprs/issue-102768.rs
new file mode 100644
index 00000000000..7aea0d30d1a
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-102768.rs
@@ -0,0 +1,14 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait X {
+    type Y<'a>;
+}
+
+const _: () = {
+    fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
+    //~^ ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments
+    //~| ERROR this associated type takes 0 generic arguments but 1 generic argument
+};
+
+fn main() {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-102768.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-102768.stderr
new file mode 100644
index 00000000000..9deb9b26588
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-102768.stderr
@@ -0,0 +1,33 @@
+error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+  --> $DIR/issue-102768.rs:9:30
+   |
+LL |     fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
+   |                              ^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-102768.rs:5:10
+   |
+LL |     type Y<'a>;
+   |          ^ --
+help: add missing lifetime argument
+   |
+LL |     fn f2<'a>(arg: Box<dyn X<Y<'a, 1> = &'a ()>>) {}
+   |                                +++
+
+error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/issue-102768.rs:9:30
+   |
+LL |     fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
+   |                              ^--- help: remove these generics
+   |                              |
+   |                              expected 0 generic arguments
+   |
+note: associated type defined here, with 0 generic parameters
+  --> $DIR/issue-102768.rs:5:10
+   |
+LL |     type Y<'a>;
+   |          ^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/object-safety/issue-102762.rs b/src/test/ui/object-safety/issue-102762.rs
new file mode 100644
index 00000000000..4f4c3634528
--- /dev/null
+++ b/src/test/ui/object-safety/issue-102762.rs
@@ -0,0 +1,26 @@
+// compile-flags: --crate-type=lib
+// This test checks that the `where_clauses_object_safety` lint does not cause
+// other object safety *hard errors* to be suppressed, because we currently
+// only emit one object safety error per trait...
+
+use std::future::Future;
+use std::pin::Pin;
+
+pub trait Fetcher: Send + Sync {
+    fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
+    where
+        Self: Sync,
+    {
+        todo!()
+    }
+}
+
+fn fetcher() -> Box<dyn Fetcher> {
+    //~^ ERROR the trait `Fetcher` cannot be made into an object
+    todo!()
+}
+
+pub fn foo() {
+    let fetcher = fetcher();
+    let _ = fetcher.get();
+}
diff --git a/src/test/ui/object-safety/issue-102762.stderr b/src/test/ui/object-safety/issue-102762.stderr
new file mode 100644
index 00000000000..5041ebe7760
--- /dev/null
+++ b/src/test/ui/object-safety/issue-102762.stderr
@@ -0,0 +1,20 @@
+error[E0038]: the trait `Fetcher` cannot be made into an object
+  --> $DIR/issue-102762.rs:18:21
+   |
+LL |     fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
+   |                      ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self`
+...
+LL | fn fetcher() -> Box<dyn Fetcher> {
+   |                     ^^^^^^^^^^^ `Fetcher` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-102762.rs:10:22
+   |
+LL | pub trait Fetcher: Send + Sync {
+   |           ------- this trait cannot be made into an object...
+LL |     fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
+   |                      ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.