diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index b69d7a000ee9a..d37aadeb523a1 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 b831423994f24..d92d9d96fe2ce 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 4849a07e3b4f4..f8b390aaf50e1 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 1fda60c021eed..c1d42c9ae7cc3 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 6b05a49575fd9..e7a08e052758c 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> 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 3dbcba72baf3b..337fcd28c663d 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> 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 679d30227f136..2b77ed8989345 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 78b0892b3bc17..9c42f6f26fc9e 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 a52d534024206..8c5b4e2dc96f9 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(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(C)->getAggregateElement(Idx)); +} +#endif diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 2b4e64bddc24b..03cb1cfcfc9ef 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 0000000000000..a7519ab5ab633 --- /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: T) {} +/// struct State { +/// 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: T) {} +/// struct State { +/// future: Exclusive +/// } +/// +/// 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 { + inner: T, +} + +// See `Exclusive`'s docs for justification. +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +unsafe impl Sync for Exclusive {} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl fmt::Debug for Exclusive { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.debug_struct("Exclusive").finish_non_exhaustive() + } +} + +impl Exclusive { + /// 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 Exclusive { + /// 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` 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 { + // 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) } + } + + /// Build a _pinned mutable_ references to an `Exclusive` 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> { + // 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 From for Exclusive { + fn from(t: T) -> Self { + Self::new(t) + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl Future for Exclusive { + type Output = T::Output; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.get_pin_mut().poll(cx) + } +} diff --git a/library/core/src/sync/mod.rs b/library/core/src/sync/mod.rs index b635bae0a47b4..4365e4cb250ca 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 65b8df4299663..ba76ee31b42dd 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 5fc18fda6a83b..7b507a169b395 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 0a6a7cfe976cc..c70ac8c9806d6 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>, ) -> io::Result> where F: FnOnce() -> T, @@ -479,8 +480,11 @@ impl Builder { })); let their_thread = my_thread.clone(); - let my_packet: Arc> = - Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None) }); + let my_packet: Arc> = 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 = crate::result::Result>; // 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>, result: UnsafeCell>>, + _marker: PhantomData>, } // 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 a387a09dc8b15..e6dbf35bd0286 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, /// 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 9cf038687f117..bae256fd5b38a 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 5d0756d30fb53..532b98d9bb9f6 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 c33e272774438..6658f07ce0103 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 290c29d3141a2..acb1d8d7b5c8d 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 8f53e8627ee1c..c441f84a82135 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 724520bc399d0..86df478fa1dd2 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 f60d3d10dce47..453cbf28569e9 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 0ebcfb40dc3b8..424ecadd4b8cc 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, | ^^^ not found in this scope @@ -59,7 +83,7 @@ LL | struct Data { | +++++ 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 0000000000000..828c871143ad5 --- /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; + +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 5a061009b6b95..3cf44a2d7d1ef 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; }) }