about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-07-01 11:09:35 +0000
committerbors <bors@rust-lang.org>2022-07-01 11:09:35 +0000
commitca1e68b3229e710c3948a361ee770d846a88e6da (patch)
treecbd0e8977b42bd32f8ab140f36f825a9d8d74ed6
parent7e2733bb1dd9afe5fd20370ca4d539d42ac50419 (diff)
parent6e918b4a97c8a2cb0923a639d76f840ac63b76c7 (diff)
downloadrust-ca1e68b3229e710c3948a361ee770d846a88e6da.tar.gz
rust-ca1e68b3229e710c3948a361ee770d846a88e6da.zip
Auto merge of #98730 - matthiaskrgr:rollup-2c4d4x5, r=matthiaskrgr
Rollup of 10 pull requests

Successful merges:

 - #97629 ([core] add `Exclusive` to sync)
 - #98503 (fix data race in thread::scope)
 - #98670 (llvm-wrapper: adapt for LLVMConstExtractValue removal)
 - #98671 (Fix source sidebar bugs)
 - #98677 (For diagnostic information of Boolean, remind it as use the type: 'bool')
 - #98684 (add test for 72793)
 - #98688 (interpret: add From<&MplaceTy> for PlaceTy)
 - #98695 (use "or pattern")
 - #98709 (Remove unneeded methods declaration for old web browsers)
 - #98717 (get rid of tidy 'unnecessarily ignored' warnings)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs6
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs7
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs16
-rw-r--r--compiler/rustc_const_eval/src/interpret/visitor.rs2
-rw-r--r--compiler/rustc_errors/src/lib.rs2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp8
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs2
-rw-r--r--library/core/src/sync/exclusive.rs173
-rw-r--r--library/core/src/sync/mod.rs3
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/sync/mod.rs2
-rw-r--r--library/std/src/thread/mod.rs17
-rw-r--r--library/std/src/thread/scoped.rs10
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css7
-rw-r--r--src/librustdoc/html/static/js/main.js34
-rw-r--r--src/librustdoc/html/static/js/source-script.js15
-rw-r--r--src/test/rustdoc-gui/sidebar-source-code-display.goml36
-rw-r--r--src/test/rustdoc-gui/sidebar-source-code.goml4
-rw-r--r--src/test/ui/lint/recommend-literal.rs7
-rw-r--r--src/test/ui/lint/recommend-literal.stderr36
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-72793.rs25
-rw-r--r--src/tools/tidy/src/style.rs13
26 files changed, 364 insertions, 79 deletions
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index b69d7a000ee..d37aadeb523 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -109,8 +109,7 @@ impl<'ll> CodegenCx<'ll, '_> {
     pub fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
         unsafe {
             assert_eq!(idx as c_uint as u64, idx);
-            let us = &[idx as c_uint];
-            let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint);
+            let r = llvm::LLVMGetAggregateElement(v, idx as c_uint).unwrap();
 
             debug!("const_get_elt(v={:?}, idx={}, r={:?})", v, idx, r);
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index b831423994f..d92d9d96fe2 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1134,11 +1134,7 @@ extern "C" {
     pub fn LLVMConstIntToPtr<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
     pub fn LLVMConstBitCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
     pub fn LLVMConstPointerCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
-    pub fn LLVMConstExtractValue(
-        AggConstant: &Value,
-        IdxList: *const c_uint,
-        NumIdx: c_uint,
-    ) -> &Value;
+    pub fn LLVMGetAggregateElement(ConstantVal: &Value, Idx: c_uint) -> Option<&Value>;
 
     // Operations on global variables, functions, and aliases (globals)
     pub fn LLVMIsDeclaration(Global: &Value) -> Bool;
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 4849a07e3b4..f8b390aaf50 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -346,7 +346,7 @@ fn valtree_into_mplace<'tcx>(
         ty::FnDef(_, _) => {
             ecx.write_immediate(
                 Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::ZST)),
-                &(*place).into(),
+                &place.into(),
             )
             .unwrap();
         }
@@ -355,7 +355,7 @@ fn valtree_into_mplace<'tcx>(
             debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place);
             ecx.write_immediate(
                 Immediate::Scalar(ScalarMaybeUninit::Scalar(scalar_int.into())),
-                &(*place).into(),
+                &place.into(),
             )
             .unwrap();
         }
@@ -382,7 +382,7 @@ fn valtree_into_mplace<'tcx>(
             };
             debug!(?imm);
 
-            ecx.write_immediate(imm, &(*place).into()).unwrap();
+            ecx.write_immediate(imm, &place.into()).unwrap();
         }
         ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => {
             let branches = valtree.unwrap_branch();
@@ -464,11 +464,11 @@ fn valtree_into_mplace<'tcx>(
 
             if let Some(variant_idx) = variant_idx {
                 // don't forget filling the place with the discriminant of the enum
-                ecx.write_discriminant(variant_idx, &(*place).into()).unwrap();
+                ecx.write_discriminant(variant_idx, &place.into()).unwrap();
             }
 
             debug!("dump of place after writing discriminant:");
-            dump_place(ecx, (*place).into());
+            dump_place(ecx, place.into());
         }
         _ => bug!("shouldn't have created a ValTree for {:?}", ty),
     }
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 1fda60c021e..c1d42c9ae7c 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -195,7 +195,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
         let tcx = self.ecx.tcx;
         let ty = mplace.layout.ty;
         if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() {
-            let value = self.ecx.read_immediate(&(*mplace).into())?;
+            let value = self.ecx.read_immediate(&mplace.into())?;
             let mplace = self.ecx.ref_to_mplace(&value)?;
             assert_eq!(mplace.layout.ty, referenced_ty);
             // Handle trait object vtables.
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 6b05a49575f..e7a08e05275 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -204,6 +204,13 @@ impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
     }
 }
 
+impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
+    #[inline(always)]
+    fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self {
+        OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout }
+    }
+}
+
 impl<'tcx, Tag: Provenance> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
     #[inline(always)]
     fn from(val: ImmTy<'tcx, Tag>) -> Self {
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 3dbcba72baf..337fcd28c66 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -118,7 +118,21 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for MPlaceTy<'tcx, Tag> {
 impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
     #[inline(always)]
     fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
-        PlaceTy { place: Place::Ptr(mplace.mplace), layout: mplace.layout }
+        PlaceTy { place: Place::Ptr(*mplace), layout: mplace.layout }
+    }
+}
+
+impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
+    #[inline(always)]
+    fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self {
+        PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout }
+    }
+}
+
+impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
+    #[inline(always)]
+    fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self {
+        PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout }
     }
 }
 
diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index 679d30227f1..2b77ed89893 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -92,7 +92,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M>
         &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        Ok((*self).into())
+        Ok(self.into())
     }
 
     #[inline(always)]
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 78b0892b3bc..9c42f6f26fc 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -1447,7 +1447,7 @@ impl HandlerInner {
                 self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0),
             ) {
                 (1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
-                (0, _) | (1, _) => {}
+                (0 | 1, _) => {}
                 (count, as_bug) => panic!(
                     "aborting after {} errors due to `-Z treat-err-as-bug={}`",
                     count, as_bug,
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index a52d5340242..8c5b4e2dc96 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1865,3 +1865,11 @@ extern "C" void LLVMRustGetMangledName(LLVMValueRef V, RustStringRef Str) {
   GlobalValue *GV = unwrap<GlobalValue>(V);
   Mangler().getNameWithPrefix(OS, GV, true);
 }
+
+// LLVMGetAggregateElement was added in LLVM 15. For earlier LLVM versions just
+// use its implementation.
+#if LLVM_VERSION_LT(15, 0)
+extern "C" LLVMValueRef LLVMGetAggregateElement(LLVMValueRef C, unsigned Idx) {
+    return wrap(unwrap<Constant>(C)->getAggregateElement(Idx));
+}
+#endif
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 2b4e64bddc2..03cb1cfcfc9 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1503,6 +1503,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         Some(match name {
             "byte" => sym::u8, // In Java, bytes are signed, but in practice one almost always wants unsigned bytes.
             "short" => sym::i16,
+            "Bool" => sym::bool,
+            "Boolean" => sym::bool,
             "boolean" => sym::bool,
             "int" => sym::i32,
             "long" => sym::i64,
diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs
new file mode 100644
index 00000000000..a7519ab5ab6
--- /dev/null
+++ b/library/core/src/sync/exclusive.rs
@@ -0,0 +1,173 @@
+//! Defines [`Exclusive`].
+
+use core::fmt;
+use core::future::Future;
+use core::pin::Pin;
+use core::task::{Context, Poll};
+
+/// `Exclusive` provides only _mutable_ access, also referred to as _exclusive_
+/// access to the underlying value. It provides no _immutable_, or _shared_
+/// access to the underlying value.
+///
+/// While this may seem not very useful, it allows `Exclusive` to _unconditionally_
+/// implement [`Sync`]. Indeed, the safety requirements of `Sync` state that for `Exclusive`
+/// to be `Sync`, it must be sound to _share_ across threads, that is, it must be sound
+/// for `&Exclusive` to cross thread boundaries. By design, a `&Exclusive` has no API
+/// whatsoever, making it useless, thus harmless, thus memory safe.
+///
+/// Certain constructs like [`Future`]s can only be used with _exclusive_ access,
+/// and are often `Send` but not `Sync`, so `Exclusive` can be used as hint to the
+/// rust compiler that something is `Sync` in practice.
+///
+/// ## Examples
+/// Using a non-`Sync` future prevents the wrapping struct from being `Sync`
+/// ```compile_fail
+/// use core::cell::Cell;
+///
+/// async fn other() {}
+/// fn assert_sync<T: Sync>(t: T) {}
+/// struct State<F> {
+///     future: F
+/// }
+///
+/// assert_sync(State {
+///     future: async {
+///         let cell = Cell::new(1);
+///         let cell_ref = &cell;
+///         other().await;
+///         let value = cell_ref.get();
+///     }
+/// });
+/// ```
+///
+/// `Exclusive` ensures the struct is `Sync` without stripping the future of its
+/// functionality.
+/// ```
+/// #![feature(exclusive_wrapper)]
+/// use core::cell::Cell;
+/// use core::sync::Exclusive;
+///
+/// async fn other() {}
+/// fn assert_sync<T: Sync>(t: T) {}
+/// struct State<F> {
+///     future: Exclusive<F>
+/// }
+///
+/// assert_sync(State {
+///     future: Exclusive::new(async {
+///         let cell = Cell::new(1);
+///         let cell_ref = &cell;
+///         other().await;
+///         let value = cell_ref.get();
+///     })
+/// });
+/// ```
+///
+/// ## Parallels with a mutex
+/// In some sense, `Exclusive` can be thought of as a _compile-time_ version of
+/// a mutex, as the borrow-checker guarantees that only one `&mut` can exist
+/// for any value. This is a parallel with the fact that
+/// `&` and `&mut` references together can be thought of as a _compile-time_
+/// version of a read-write lock.
+///
+///
+/// [`Sync`]: core::marker::Sync
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+#[doc(alias = "SyncWrapper")]
+#[doc(alias = "SyncCell")]
+#[doc(alias = "Unique")]
+// `Exclusive` can't have `PartialOrd`, `Clone`, etc. impls as they would
+// use `&` access to the inner value, violating the `Sync` impl's safety
+// requirements.
+#[derive(Default)]
+#[repr(transparent)]
+pub struct Exclusive<T: ?Sized> {
+    inner: T,
+}
+
+// See `Exclusive`'s docs for justification.
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+unsafe impl<T: ?Sized> Sync for Exclusive<T> {}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+impl<T: ?Sized> fmt::Debug for Exclusive<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+        f.debug_struct("Exclusive").finish_non_exhaustive()
+    }
+}
+
+impl<T: Sized> Exclusive<T> {
+    /// Wrap a value in an `Exclusive`
+    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[must_use]
+    pub const fn new(t: T) -> Self {
+        Self { inner: t }
+    }
+
+    /// Unwrap the value contained in the `Exclusive`
+    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[must_use]
+    pub const fn into_inner(self) -> T {
+        self.inner
+    }
+}
+
+impl<T: ?Sized> Exclusive<T> {
+    /// Get exclusive access to the underlying value.
+    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[must_use]
+    pub const fn get_mut(&mut self) -> &mut T {
+        &mut self.inner
+    }
+
+    /// Get pinned exclusive access to the underlying value.
+    ///
+    /// `Exclusive` is considered to _structurally pin_ the underlying
+    /// value, which means _unpinned_ `Exclusive`s can produce _unpinned_
+    /// access to the underlying value, but _pinned_ `Exclusive`s only
+    /// produce _pinned_ access to the underlying value.
+    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[must_use]
+    pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
+        // SAFETY: `Exclusive` can only produce `&mut T` if itself is unpinned
+        // `Pin::map_unchecked_mut` is not const, so we do this conversion manually
+        unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) }
+    }
+
+    /// Build a _mutable_ references to an `Exclusive<T>` from
+    /// a _mutable_ reference to a `T`. This allows you to skip
+    /// building an `Exclusive` with [`Exclusive::new`].
+    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[must_use]
+    pub const fn from_mut(r: &'_ mut T) -> &'_ mut Exclusive<T> {
+        // SAFETY: repr is ≥ C, so refs have the same layout; and `Exclusive` properties are `&mut`-agnostic
+        unsafe { &mut *(r as *mut T as *mut Exclusive<T>) }
+    }
+
+    /// Build a _pinned mutable_ references to an `Exclusive<T>` from
+    /// a _pinned mutable_ reference to a `T`. This allows you to skip
+    /// building an `Exclusive` with [`Exclusive::new`].
+    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
+    #[must_use]
+    pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut Exclusive<T>> {
+        // SAFETY: `Exclusive` can only produce `&mut T` if itself is unpinned
+        // `Pin::map_unchecked_mut` is not const, so we do this conversion manually
+        unsafe { Pin::new_unchecked(Self::from_mut(r.get_unchecked_mut())) }
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+impl<T> From<T> for Exclusive<T> {
+    fn from(t: T) -> Self {
+        Self::new(t)
+    }
+}
+
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+impl<T: Future + ?Sized> Future for Exclusive<T> {
+    type Output = T::Output;
+
+    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        self.get_pin_mut().poll(cx)
+    }
+}
diff --git a/library/core/src/sync/mod.rs b/library/core/src/sync/mod.rs
index b635bae0a47..4365e4cb250 100644
--- a/library/core/src/sync/mod.rs
+++ b/library/core/src/sync/mod.rs
@@ -3,3 +3,6 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 pub mod atomic;
+mod exclusive;
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+pub use exclusive::Exclusive;
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 65b8df42996..ba76ee31b42 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -270,6 +270,7 @@
 #![feature(duration_checked_float)]
 #![feature(duration_constants)]
 #![feature(exact_size_is_empty)]
+#![feature(exclusive_wrapper)]
 #![feature(extend_one)]
 #![feature(float_minimum_maximum)]
 #![feature(hasher_prefixfree_extras)]
diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs
index 5fc18fda6a8..7b507a169b3 100644
--- a/library/std/src/sync/mod.rs
+++ b/library/std/src/sync/mod.rs
@@ -155,6 +155,8 @@
 pub use alloc_crate::sync::{Arc, Weak};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::sync::atomic;
+#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+pub use core::sync::Exclusive;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::barrier::{Barrier, BarrierWaitResult};
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 0a6a7cfe976..c70ac8c9806 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -159,6 +159,7 @@ use crate::cell::UnsafeCell;
 use crate::ffi::{CStr, CString};
 use crate::fmt;
 use crate::io;
+use crate::marker::PhantomData;
 use crate::mem;
 use crate::num::NonZeroU64;
 use crate::num::NonZeroUsize;
@@ -462,7 +463,7 @@ impl Builder {
     unsafe fn spawn_unchecked_<'a, 'scope, F, T>(
         self,
         f: F,
-        scope_data: Option<&'scope scoped::ScopeData>,
+        scope_data: Option<Arc<scoped::ScopeData>>,
     ) -> io::Result<JoinInner<'scope, T>>
     where
         F: FnOnce() -> T,
@@ -479,8 +480,11 @@ impl Builder {
         }));
         let their_thread = my_thread.clone();
 
-        let my_packet: Arc<Packet<'scope, T>> =
-            Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None) });
+        let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet {
+            scope: scope_data,
+            result: UnsafeCell::new(None),
+            _marker: PhantomData,
+        });
         let their_packet = my_packet.clone();
 
         let output_capture = crate::io::set_output_capture(None);
@@ -507,7 +511,7 @@ impl Builder {
             unsafe { *their_packet.result.get() = Some(try_result) };
         };
 
-        if let Some(scope_data) = scope_data {
+        if let Some(scope_data) = &my_packet.scope {
             scope_data.increment_num_running_threads();
         }
 
@@ -1298,8 +1302,9 @@ pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;
 // An Arc to the packet is stored into a `JoinInner` which in turns is placed
 // in `JoinHandle`.
 struct Packet<'scope, T> {
-    scope: Option<&'scope scoped::ScopeData>,
+    scope: Option<Arc<scoped::ScopeData>>,
     result: UnsafeCell<Option<Result<T>>>,
+    _marker: PhantomData<Option<&'scope scoped::ScopeData>>,
 }
 
 // Due to the usage of `UnsafeCell` we need to manually implement Sync.
@@ -1330,7 +1335,7 @@ impl<'scope, T> Drop for Packet<'scope, T> {
             rtabort!("thread result panicked on drop");
         }
         // Book-keeping so the scope knows when it's done.
-        if let Some(scope) = self.scope {
+        if let Some(scope) = &self.scope {
             // Now that there will be no more user code running on this thread
             // that can use 'scope, mark the thread as 'finished'.
             // It's important we only do this after the `result` has been dropped,
diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs
index a387a09dc8b..e6dbf35bd02 100644
--- a/library/std/src/thread/scoped.rs
+++ b/library/std/src/thread/scoped.rs
@@ -11,7 +11,7 @@ use crate::sync::Arc;
 /// See [`scope`] for details.
 #[stable(feature = "scoped_threads", since = "1.63.0")]
 pub struct Scope<'scope, 'env: 'scope> {
-    data: ScopeData,
+    data: Arc<ScopeData>,
     /// Invariance over 'scope, to make sure 'scope cannot shrink,
     /// which is necessary for soundness.
     ///
@@ -130,12 +130,14 @@ pub fn scope<'env, F, T>(f: F) -> T
 where
     F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T,
 {
+    // We put the `ScopeData` into an `Arc` so that other threads can finish their
+    // `decrement_num_running_threads` even after this function returns.
     let scope = Scope {
-        data: ScopeData {
+        data: Arc::new(ScopeData {
             num_running_threads: AtomicUsize::new(0),
             main_thread: current(),
             a_thread_panicked: AtomicBool::new(false),
-        },
+        }),
         env: PhantomData,
         scope: PhantomData,
     };
@@ -250,7 +252,7 @@ impl Builder {
         F: FnOnce() -> T + Send + 'scope,
         T: Send + 'scope,
     {
-        Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(&scope.data)) }?))
+        Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(scope.data.clone())) }?))
     }
 }
 
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
index 9cf038687f1..bae256fd5b3 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
@@ -1 +1 @@
-0.9.6
\ No newline at end of file
+0.9.7
\ No newline at end of file
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 5d0756d30fb..532b98d9bb9 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -1772,9 +1772,11 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 	/* The source view uses a different design for the sidebar toggle, and doesn't have a topbar,
 	   so don't bump down the main content or the sidebar. */
 	.source main,
-	.source .sidebar {
+	.rustdoc.source .sidebar {
 		top: 0;
 		padding: 0;
+		height: 100vh;
+		border: 0;
 	}
 
 	.sidebar.shown,
@@ -1924,6 +1926,9 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 		width: unset;
 		border-top-right-radius: unset;
 		border-bottom-right-radius: unset;
+		position: sticky;
+		border: 0;
+		border-bottom: 1px solid;
 	}
 
 	#source-sidebar {
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index c33e2727744..6658f07ce01 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -4,40 +4,6 @@
 
 "use strict";
 
-if (!String.prototype.startsWith) {
-    String.prototype.startsWith = function(searchString, position) {
-        position = position || 0;
-        return this.indexOf(searchString, position) === position;
-    };
-}
-if (!String.prototype.endsWith) {
-    String.prototype.endsWith = function(suffix, length) {
-        const l = length || this.length;
-        return this.indexOf(suffix, l - suffix.length) !== -1;
-    };
-}
-
-if (!DOMTokenList.prototype.add) {
-    DOMTokenList.prototype.add = function(className) {
-        if (className && !hasClass(this, className)) {
-            if (this.className && this.className.length > 0) {
-                this.className += " " + className;
-            } else {
-                this.className = className;
-            }
-        }
-    };
-}
-
-if (!DOMTokenList.prototype.remove) {
-    DOMTokenList.prototype.remove = function(className) {
-        if (className && this.className) {
-            this.className = (" " + this.className + " ").replace(" " + className + " ", " ")
-                                                         .trim();
-        }
-    };
-}
-
 // Get a value from the rustdoc-vars div, which is used to convey data from
 // Rust to the JS. If there is no such element, return null.
 function getVar(name) {
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js
index 290c29d3141..acb1d8d7b5c 100644
--- a/src/librustdoc/html/static/js/source-script.js
+++ b/src/librustdoc/html/static/js/source-script.js
@@ -10,6 +10,7 @@
 (function() {
 
 const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value;
+let oldScrollPosition = 0;
 
 function createDirEntry(elem, parent, fullPath, hasFoundFile) {
     const name = document.createElement("div");
@@ -65,10 +66,24 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
 function toggleSidebar() {
     const child = this.children[0];
     if (child.innerText === ">") {
+        if (window.innerWidth < 701) {
+            // This is to keep the scroll position on mobile.
+            oldScrollPosition = window.scrollY;
+            document.body.style.position = "fixed";
+            document.body.style.top = `-${oldScrollPosition}px`;
+        }
         addClass(document.documentElement, "source-sidebar-expanded");
         child.innerText = "<";
         updateLocalStorage("source-sidebar-show", "true");
     } else {
+        if (window.innerWidth < 701) {
+            // This is to keep the scroll position on mobile.
+            document.body.style.position = "";
+            document.body.style.top = "";
+            // The scroll position is lost when resetting the style, hence why we store it in
+            // `oldScroll`.
+            window.scrollTo(0, oldScrollPosition);
+        }
         removeClass(document.documentElement, "source-sidebar-expanded");
         child.innerText = ">";
         updateLocalStorage("source-sidebar-show", "false");
diff --git a/src/test/rustdoc-gui/sidebar-source-code-display.goml b/src/test/rustdoc-gui/sidebar-source-code-display.goml
index 8f53e8627ee..c441f84a821 100644
--- a/src/test/rustdoc-gui/sidebar-source-code-display.goml
+++ b/src/test/rustdoc-gui/sidebar-source-code-display.goml
@@ -116,3 +116,39 @@ assert-css: (
     "#source-sidebar .expand + .children .folders .name",
     {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
 )
+
+// Now checking on mobile devices.
+size: (500, 700)
+reload:
+// Waiting for the sidebar to be displayed...
+wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
+
+// We now check it takes the full size of the display.
+assert-property: ("body", {"clientWidth": "500", "clientHeight": "700"})
+assert-property: (".sidebar", {"clientWidth": "500", "clientHeight": "700"})
+
+// We now check the display of the toggle once the sidebar is expanded.
+assert-property: ("#sidebar-toggle", {"clientWidth": "500", "clientHeight": "39"})
+assert-css: (
+    "#sidebar-toggle",
+    {
+        "border-top-width": "0px",
+        "border-right-width": "0px",
+        "border-left-width": "0px",
+        "border-bottom-width": "1px",
+    },
+)
+
+// We now check that the scroll position is kept when opening the sidebar.
+click: "#sidebar-toggle"
+wait-for-css: (".sidebar", {"width": "0px"})
+// We scroll to line 117 to change the scroll position.
+scroll-to: '//*[@id="117"]'
+assert-window-property: {"pageYOffset": "2519"}
+// Expanding the sidebar...
+click: "#sidebar-toggle"
+wait-for-css: (".sidebar", {"width": "500px"})
+click: "#sidebar-toggle"
+wait-for-css: (".sidebar", {"width": "0px"})
+// The "scrollTop" property should be the same.
+assert-window-property: {"pageYOffset": "2519"}
diff --git a/src/test/rustdoc-gui/sidebar-source-code.goml b/src/test/rustdoc-gui/sidebar-source-code.goml
index 724520bc399..86df478fa1d 100644
--- a/src/test/rustdoc-gui/sidebar-source-code.goml
+++ b/src/test/rustdoc-gui/sidebar-source-code.goml
@@ -18,8 +18,8 @@ assert: "nav.sidebar"
 
 // We now switch to mobile mode.
 size: (600, 600)
-// We check that the sidebar has the expected width (0 and 1px for the border).
-assert-css: ("nav.sidebar", {"width": "1px"})
+// We check that the sidebar has the expected width (0).
+assert-css: ("nav.sidebar", {"width": "0px"})
 // We expand the sidebar.
 click: "#sidebar-toggle"
 assert-css: (".source-sidebar-expanded nav.sidebar", {"width": "600px"})
diff --git a/src/test/ui/lint/recommend-literal.rs b/src/test/ui/lint/recommend-literal.rs
index f60d3d10dce..453cbf28569 100644
--- a/src/test/ui/lint/recommend-literal.rs
+++ b/src/test/ui/lint/recommend-literal.rs
@@ -7,6 +7,13 @@ fn main() {
     let y: long = 74802374902374923;
     //~^ ERROR cannot find type `long` in this scope
     //~| HELP perhaps you intended to use this type
+    let v1: Boolean = true;
+    //~^ ERROR: cannot find type `Boolean` in this scope [E0412]
+    //~| HELP perhaps you intended to use this type
+    let v2: Bool = true;
+    //~^ ERROR: cannot find type `Bool` in this scope [E0412]
+    //~| HELP a builtin type with a similar name exists
+    //~| HELP perhaps you intended to use this type
 }
 
 fn z(a: boolean) {
diff --git a/src/test/ui/lint/recommend-literal.stderr b/src/test/ui/lint/recommend-literal.stderr
index 0ebcfb40dc3..424ecadd4b8 100644
--- a/src/test/ui/lint/recommend-literal.stderr
+++ b/src/test/ui/lint/recommend-literal.stderr
@@ -16,8 +16,32 @@ LL |     let y: long = 74802374902374923;
    |            not found in this scope
    |            help: perhaps you intended to use this type: `i64`
 
+error[E0412]: cannot find type `Boolean` in this scope
+  --> $DIR/recommend-literal.rs:10:13
+   |
+LL |     let v1: Boolean = true;
+   |             ^^^^^^^
+   |             |
+   |             not found in this scope
+   |             help: perhaps you intended to use this type: `bool`
+
+error[E0412]: cannot find type `Bool` in this scope
+  --> $DIR/recommend-literal.rs:13:13
+   |
+LL |     let v2: Bool = true;
+   |             ^^^^
+   |
+help: a builtin type with a similar name exists
+   |
+LL |     let v2: bool = true;
+   |             ~~~~
+help: perhaps you intended to use this type
+   |
+LL |     let v2: bool = true;
+   |             ~~~~
+
 error[E0412]: cannot find type `boolean` in this scope
-  --> $DIR/recommend-literal.rs:12:9
+  --> $DIR/recommend-literal.rs:19:9
    |
 LL | fn z(a: boolean) {
    |         ^^^^^^^
@@ -26,7 +50,7 @@ LL | fn z(a: boolean) {
    |         help: perhaps you intended to use this type: `bool`
 
 error[E0412]: cannot find type `byte` in this scope
-  --> $DIR/recommend-literal.rs:17:11
+  --> $DIR/recommend-literal.rs:24:11
    |
 LL | fn a() -> byte {
    |           ^^^^
@@ -35,7 +59,7 @@ LL | fn a() -> byte {
    |           help: perhaps you intended to use this type: `u8`
 
 error[E0412]: cannot find type `float` in this scope
-  --> $DIR/recommend-literal.rs:24:12
+  --> $DIR/recommend-literal.rs:31:12
    |
 LL |     width: float,
    |            ^^^^^
@@ -44,7 +68,7 @@ LL |     width: float,
    |            help: perhaps you intended to use this type: `f32`
 
 error[E0412]: cannot find type `int` in this scope
-  --> $DIR/recommend-literal.rs:27:19
+  --> $DIR/recommend-literal.rs:34:19
    |
 LL |     depth: Option<int>,
    |                   ^^^ not found in this scope
@@ -59,7 +83,7 @@ LL | struct Data<int> {
    |            +++++
 
 error[E0412]: cannot find type `short` in this scope
-  --> $DIR/recommend-literal.rs:33:16
+  --> $DIR/recommend-literal.rs:40:16
    |
 LL | impl Stuff for short {}
    |                ^^^^^
@@ -67,6 +91,6 @@ LL | impl Stuff for short {}
    |                not found in this scope
    |                help: perhaps you intended to use this type: `i16`
 
-error: aborting due to 7 previous errors
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-72793.rs b/src/test/ui/type-alias-impl-trait/issue-72793.rs
new file mode 100644
index 00000000000..828c871143a
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-72793.rs
@@ -0,0 +1,25 @@
+// check-pass
+// compile-flags: -Zmir-opt-level=3
+
+#![feature(type_alias_impl_trait)]
+
+trait T { type Item; }
+
+type Alias<'a> = impl T<Item = &'a ()>;
+
+struct S;
+impl<'a> T for &'a S {
+    type Item = &'a ();
+}
+
+fn filter_positive<'a>() -> Alias<'a> {
+    &S
+}
+
+fn with_positive(fun: impl Fn(Alias<'_>)) {
+    fun(filter_positive());
+}
+
+fn main() {
+    with_positive(|_| ());
+}
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 5a061009b6b..3cf44a2d7d1 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -395,9 +395,6 @@ pub fn check(path: &Path, bad: &mut bool) {
                 );
             };
             suppressible_tidy_err!(err, skip_file_length, "");
-        } else if lines > (LINES * 7) / 10 {
-            // Just set it to something that doesn't trigger the "unnecessarily ignored" warning.
-            skip_file_length = Directive::Ignore(true);
         }
 
         if let Directive::Ignore(false) = skip_cr {
@@ -406,12 +403,6 @@ pub fn check(path: &Path, bad: &mut bool) {
         if let Directive::Ignore(false) = skip_tab {
             tidy_error!(bad, "{}: ignoring tab characters unnecessarily", file.display());
         }
-        if let Directive::Ignore(false) = skip_line_length {
-            tidy_error!(bad, "{}: ignoring line length unnecessarily", file.display());
-        }
-        if let Directive::Ignore(false) = skip_file_length {
-            tidy_error!(bad, "{}: ignoring file length unnecessarily", file.display());
-        }
         if let Directive::Ignore(false) = skip_end_whitespace {
             tidy_error!(bad, "{}: ignoring trailing whitespace unnecessarily", file.display());
         }
@@ -424,5 +415,9 @@ pub fn check(path: &Path, bad: &mut bool) {
         if let Directive::Ignore(false) = skip_copyright {
             tidy_error!(bad, "{}: ignoring copyright unnecessarily", file.display());
         }
+        // We deliberately do not warn about these being unnecessary,
+        // that would just lead to annoying churn.
+        let _unused = skip_line_length;
+        let _unused = skip_file_length;
     })
 }