diff --git a/Cargo.lock b/Cargo.lock index 890c5ce3ac4..197b2c8f3f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1879,9 +1879,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.99" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" +checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" dependencies = [ "rustc-std-workspace-core", ] diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index d05cfebc5f0..11cdbe84acc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -498,6 +498,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { diag.span_label(*span, format!("`{}` escapes the {} body here", fr_name, escapes_from)); } + // Only show an extra note if we can find an 'error region' for both of the region + // variables. This avoids showing a noisy note that just mentions 'synthetic' regions + // that don't help the user understand the error. + if self.to_error_region(errci.fr).is_some() + && self.to_error_region(errci.outlived_fr).is_some() + { + let fr_region_name = self.give_region_a_name(errci.fr).unwrap(); + fr_region_name.highlight_region_name(&mut diag); + let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap(); + outlived_fr_region_name.highlight_region_name(&mut diag); + + diag.span_label( + *span, + format!( + "{}requires that `{}` must outlive `{}`", + category.description(), + fr_region_name, + outlived_fr_region_name, + ), + ); + } diag } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index f13531814d6..fee13fd2e2e 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1826,8 +1826,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { match layout.variants { Variants::Single { index } => { - debug!("print-type-size `{:#?}` variant {}", layout, adt_def.variants[index].ident); - if !adt_def.variants.is_empty() { + if !adt_def.variants.is_empty() && layout.fields != FieldsShape::Primitive { + debug!( + "print-type-size `{:#?}` variant {}", + layout, adt_def.variants[index].ident + ); let variant_def = &adt_def.variants[index]; let fields: Vec<_> = variant_def.fields.iter().map(|f| f.ident.name).collect(); record( diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 9736a7b2e28..51c766fe57c 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -351,7 +351,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ); let mut sugg = None; let mut sugg_mutref = false; - if let ty::Ref(reg, _, mutbl) = *self.cast_ty.kind() { + if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() { if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() { if fcx .try_coerce( @@ -366,7 +366,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ) .is_ok() { - sugg = Some(format!("&{}*", mutbl.prefix_str())); + sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty)); } } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() { if expr_mutbl == Mutability::Not @@ -400,7 +400,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ) .is_ok() { - sugg = Some(format!("&{}", mutbl.prefix_str())); + sugg = Some((format!("&{}", mutbl.prefix_str()), false)); } } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind() { if fcx @@ -416,19 +416,47 @@ impl<'a, 'tcx> CastCheck<'tcx> { ) .is_ok() { - sugg = Some(format!("&{}", mutbl.prefix_str())); + sugg = Some((format!("&{}", mutbl.prefix_str()), false)); } } if sugg_mutref { err.span_label(self.span, "invalid cast"); err.span_note(self.expr.span, "this reference is immutable"); err.span_note(self.cast_span, "trying to cast to a mutable reference type"); - } else if let Some(sugg) = sugg { + } else if let Some((sugg, remove_cast)) = sugg { err.span_label(self.span, "invalid cast"); - err.span_suggestion_verbose( - self.expr.span.shrink_to_lo(), + + let has_parens = fcx + .tcx + .sess + .source_map() + .span_to_snippet(self.expr.span) + .map_or(false, |snip| snip.starts_with("(")); + + // Very crude check to see whether the expression must be wrapped + // in parentheses for the suggestion to work (issue #89497). + // Can/should be extended in the future. + let needs_parens = !has_parens + && match self.expr.kind { + hir::ExprKind::Cast(..) => true, + _ => false, + }; + + let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)]; + if needs_parens { + suggestion[0].1 += "("; + suggestion.push((self.expr.span.shrink_to_hi(), ")".to_string())); + } + if remove_cast { + suggestion.push(( + self.expr.span.shrink_to_hi().to(self.cast_span), + String::new(), + )); + } + + err.multipart_suggestion_verbose( "consider borrowing the value", - sugg, + suggestion, Applicability::MachineApplicable, ); } else if !matches!( diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs index dfa0227dea3..05f94da6de7 100644 --- a/library/alloc/src/collections/vec_deque/drain.rs +++ b/library/alloc/src/collections/vec_deque/drain.rs @@ -18,10 +18,21 @@ pub struct Drain< T: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { - pub(crate) after_tail: usize, - pub(crate) after_head: usize, - pub(crate) iter: Iter<'a, T>, - pub(crate) deque: NonNull>, + after_tail: usize, + after_head: usize, + iter: Iter<'a, T>, + deque: NonNull>, +} + +impl<'a, T, A: Allocator> Drain<'a, T, A> { + pub(super) unsafe fn new( + after_tail: usize, + after_head: usize, + iter: Iter<'a, T>, + deque: NonNull>, + ) -> Self { + Drain { after_tail, after_head, iter, deque } + } } #[stable(feature = "collection_debug", since = "1.17.0")] diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index 7700b31cf5b..31e6e3b06af 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -13,10 +13,21 @@ use super::{count, wrap_index, RingSlices}; #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { // Internal safety invariant: the entire slice is dereferencable. - pub(crate) ring: *mut [T], - pub(crate) tail: usize, - pub(crate) head: usize, - pub(crate) phantom: PhantomData<&'a mut [T]>, + ring: *mut [T], + tail: usize, + head: usize, + phantom: PhantomData<&'a mut [T]>, +} + +impl<'a, T> IterMut<'a, T> { + pub(super) unsafe fn new( + ring: *mut [T], + tail: usize, + head: usize, + phantom: PhantomData<&'a mut [T]>, + ) -> Self { + IterMut { ring, tail, head, phantom } + } } // SAFETY: we do nothing thread-local and there is no interior mutability, diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index f4de2b2ebe5..e996784bbad 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1000,12 +1000,9 @@ impl VecDeque { pub fn iter_mut(&mut self) -> IterMut<'_, T> { // SAFETY: The internal `IterMut` safety invariant is established because the // `ring` we create is a dereferencable slice for lifetime '_. - IterMut { - tail: self.tail, - head: self.head, - ring: ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()), - phantom: PhantomData, - } + let ring = ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()); + + unsafe { IterMut::new(ring, self.tail, self.head, PhantomData) } } /// Returns a pair of slices which contain, in order, the contents of the @@ -1192,12 +1189,9 @@ impl VecDeque { // SAFETY: The internal `IterMut` safety invariant is established because the // `ring` we create is a dereferencable slice for lifetime '_. - IterMut { - tail, - head, - ring: ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()), - phantom: PhantomData, - } + let ring = ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()); + + unsafe { IterMut::new(ring, tail, head, PhantomData) } } /// Creates a draining iterator that removes the specified range in the @@ -1269,19 +1263,17 @@ impl VecDeque { // the drain is complete and the Drain destructor is run. self.head = drain_tail; - Drain { - deque: NonNull::from(&mut *self), - after_tail: drain_head, - after_head: head, - iter: Iter { - tail: drain_tail, - head: drain_head, - // Crucially, we only create shared references from `self` here and read from - // it. We do not write to `self` nor reborrow to a mutable reference. - // Hence the raw pointer we created above, for `deque`, remains valid. - ring: unsafe { self.buffer_as_slice() }, - }, - } + let deque = NonNull::from(&mut *self); + let iter = Iter { + tail: drain_tail, + head: drain_head, + // Crucially, we only create shared references from `self` here and read from + // it. We do not write to `self` nor reborrow to a mutable reference. + // Hence the raw pointer we created above, for `deque`, remains valid. + ring: unsafe { self.buffer_as_slice() }, + }; + + unsafe { Drain::new(drain_head, head, iter, deque) } } /// Clears the `VecDeque`, removing all values. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 4742970f954..f9d517ce8c0 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -142,6 +142,7 @@ #![feature(link_llvm_intrinsics)] #![feature(llvm_asm)] #![feature(min_specialization)] +#![feature(mixed_integer_ops)] #![cfg_attr(not(bootstrap), feature(must_not_suspend))] #![feature(negative_impls)] #![feature(never_type)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 9d46948ce02..12dda61400f 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -433,6 +433,28 @@ macro_rules! int_impl { unsafe { intrinsics::unchecked_add(self, rhs) } } + /// Checked addition with an unsigned integer. Computes `self + rhs`, + /// returning `None` if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_unsigned(2), Some(3));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_unsigned(3), None);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option { + let (a, b) = self.overflowing_add_unsigned(rhs); + if unlikely!(b) {None} else {Some(a)} + } + /// Checked integer subtraction. Computes `self - rhs`, returning `None` if /// overflow occurred. /// @@ -479,6 +501,28 @@ macro_rules! int_impl { unsafe { intrinsics::unchecked_sub(self, rhs) } } + /// Checked subtraction with an unsigned integer. Computes `self - rhs`, + /// returning `None` if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_unsigned(2), Some(-1));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub_unsigned(3), None);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option { + let (a, b) = self.overflowing_sub_unsigned(rhs); + if unlikely!(b) {None} else {Some(a)} + } + /// Checked integer multiplication. Computes `self * rhs`, returning `None` if /// overflow occurred. /// @@ -826,6 +870,32 @@ macro_rules! int_impl { intrinsics::saturating_add(self, rhs) } + /// Saturating addition with an unsigned integer. Computes `self + rhs`, + /// saturating at the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_unsigned(2), 3);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add_unsigned(100), ", stringify!($SelfT), "::MAX);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_add_unsigned(self, rhs: $UnsignedT) -> Self { + // Overflow can only happen at the upper bound + // We cannot use `unwrap_or` here because it is not `const` + match self.checked_add_unsigned(rhs) { + Some(x) => x, + None => Self::MAX, + } + } + /// Saturating integer subtraction. Computes `self - rhs`, saturating at the /// numeric bounds instead of overflowing. /// @@ -847,6 +917,32 @@ macro_rules! int_impl { intrinsics::saturating_sub(self, rhs) } + /// Saturating subtraction with an unsigned integer. Computes `self - rhs`, + /// saturating at the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub_unsigned(127), -27);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub_unsigned(100), ", stringify!($SelfT), "::MIN);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_sub_unsigned(self, rhs: $UnsignedT) -> Self { + // Overflow can only happen at the lower bound + // We cannot use `unwrap_or` here because it is not `const` + match self.checked_sub_unsigned(rhs) { + Some(x) => x, + None => Self::MIN, + } + } + /// Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` /// instead of overflowing. /// @@ -1002,6 +1098,27 @@ macro_rules! int_impl { intrinsics::wrapping_add(self, rhs) } + /// Wrapping (modular) addition with an unsigned integer. Computes + /// `self + rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_add_unsigned(27), 127);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add_unsigned(2), ", stringify!($SelfT), "::MIN + 1);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn wrapping_add_unsigned(self, rhs: $UnsignedT) -> Self { + self.wrapping_add(rhs as Self) + } + /// Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the /// boundary of the type. /// @@ -1022,6 +1139,27 @@ macro_rules! int_impl { intrinsics::wrapping_sub(self, rhs) } + /// Wrapping (modular) subtraction with an unsigned integer. Computes + /// `self - rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".wrapping_sub_unsigned(127), -127);")] + #[doc = concat!("assert_eq!((-2", stringify!($SelfT), ").wrapping_sub_unsigned(", stringify!($UnsignedT), "::MAX), -1);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn wrapping_sub_unsigned(self, rhs: $UnsignedT) -> Self { + self.wrapping_sub(rhs as Self) + } + /// Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at /// the boundary of the type. /// @@ -1372,6 +1510,33 @@ macro_rules! int_impl { (sum as $SelfT, carry) } + /// Calculates `self` + `rhs` with an unsigned `rhs` + /// + /// Returns a tuple of the addition along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would + /// have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_unsigned(2), (3, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN).overflowing_add_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MAX, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_unsigned(3), (", stringify!($SelfT), "::MIN, true));")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_add_unsigned(self, rhs: $UnsignedT) -> (Self, bool) { + let rhs = rhs as Self; + let (res, overflowed) = self.overflowing_add(rhs); + (res, overflowed ^ (rhs < 0)) + } + /// Calculates `self` - `rhs` /// /// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow @@ -1423,6 +1588,33 @@ macro_rules! int_impl { (sum as $SelfT, borrow) } + /// Calculates `self` - `rhs` with an unsigned `rhs` + /// + /// Returns a tuple of the subtraction along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would + /// have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_unsigned(2), (-1, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX).overflowing_sub_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MIN, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).overflowing_sub_unsigned(3), (", stringify!($SelfT), "::MAX, true));")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_sub_unsigned(self, rhs: $UnsignedT) -> (Self, bool) { + let rhs = rhs as Self; + let (res, overflowed) = self.overflowing_sub(rhs); + (res, overflowed ^ (rhs < 0)) + } + /// Calculates the multiplication of `self` and `rhs`. /// /// Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 59b68cbe9c0..d5fb98eff57 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -245,7 +245,7 @@ const ASCII_CASE_MASK: u8 = 0b0010_0000; #[lang = "u8"] impl u8 { widening_impl! { u8, u16, 8 } - uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", + uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", "[0x12]", "", "" } /// Checks if the value is within the ASCII range. @@ -779,21 +779,21 @@ impl u8 { #[lang = "u16"] impl u16 { widening_impl! { u16, u32, 16 } - uint_impl! { u16, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", + uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } } #[lang = "u32"] impl u32 { widening_impl! { u32, u64, 32 } - uint_impl! { u32, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", + uint_impl! { u32, u32, i32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" } } #[lang = "u64"] impl u64 { widening_impl! { u64, u128, 64 } - uint_impl! { u64, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", + uint_impl! { u64, u64, i64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", @@ -802,7 +802,7 @@ impl u64 { #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, 16, + uint_impl! { u128, u128, i128, 128, 340282366920938463463374607431768211455, 16, "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012", "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48", "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \ @@ -816,7 +816,7 @@ impl u128 { #[lang = "usize"] impl usize { widening_impl! { usize, u32, 16 } - uint_impl! { usize, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", + uint_impl! { usize, u16, isize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } @@ -824,7 +824,7 @@ impl usize { #[lang = "usize"] impl usize { widening_impl! { usize, u64, 32 } - uint_impl! { usize, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", + uint_impl! { usize, u32, isize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } @@ -833,7 +833,7 @@ impl usize { #[lang = "usize"] impl usize { widening_impl! { usize, u128, 64 } - uint_impl! { usize, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", + uint_impl! { usize, u64, isize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", @@ -865,23 +865,41 @@ impl usize { #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum FpCategory { - /// "Not a Number", often obtained by dividing by zero. + /// NaN (not a number): this value results from calculations like `(-1.0).sqrt()`. + /// + /// See [the documentation for `f32`](f32) for more information on the unusual properties + /// of NaN. #[stable(feature = "rust1", since = "1.0.0")] Nan, - /// Positive or negative infinity. + /// Positive or negative infinity, which often results from dividing a nonzero number + /// by zero. #[stable(feature = "rust1", since = "1.0.0")] Infinite, /// Positive or negative zero. + /// + /// See [the documentation for `f32`](f32) for more information on the signedness of zeroes. #[stable(feature = "rust1", since = "1.0.0")] Zero, - /// De-normalized floating point representation (less precise than `Normal`). + /// “Subnormal” or “denormal” floating point representation (less precise, relative to + /// their magnitude, than [`Normal`]). + /// + /// Subnormal numbers are larger in magnitude than [`Zero`] but smaller in magnitude than all + /// [`Normal`] numbers. + /// + /// [`Normal`]: Self::Normal + /// [`Zero`]: Self::Zero #[stable(feature = "rust1", since = "1.0.0")] Subnormal, - /// A regular floating point number. + /// A regular floating point number, not any of the exceptional categories. + /// + /// The smallest positive normal numbers are [`f32::MIN_POSITIVE`] and [`f64::MIN_POSITIVE`], + /// and the largest positive normal numbers are [`f32::MAX`] and [`f64::MAX`]. (Unlike signed + /// integers, floating point numbers are symmetric in their range, so negating any of these + /// constants will produce their negative counterpart.) #[stable(feature = "rust1", since = "1.0.0")] Normal, } diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 7ef8ea23b50..25cd582bb67 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1,5 +1,5 @@ macro_rules! uint_impl { - ($SelfT:ty, $ActualT:ident, $BITS:expr, $MaxV:expr, + ($SelfT:ty, $ActualT:ident, $SignedT:ident, $BITS:expr, $MaxV:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, $reversed:expr, $le_bytes:expr, $be_bytes:expr, $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { @@ -442,6 +442,29 @@ macro_rules! uint_impl { unsafe { intrinsics::unchecked_add(self, rhs) } } + /// Checked addition with a signed integer. Computes `self + rhs`, + /// returning `None` if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(2), Some(3));")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(-2), None);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_signed(3), None);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_add_signed(self, rhs: $SignedT) -> Option { + let (a, b) = self.overflowing_add_signed(rhs); + if unlikely!(b) {None} else {Some(a)} + } + /// Checked integer subtraction. Computes `self - rhs`, returning /// `None` if overflow occurred. /// @@ -995,6 +1018,35 @@ macro_rules! uint_impl { intrinsics::saturating_add(self, rhs) } + /// Saturating addition with a signed integer. Computes `self + rhs`, + /// saturating at the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(2), 3);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(-2), 0);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).saturating_add_signed(4), ", stringify!($SelfT), "::MAX);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_add_signed(self, rhs: $SignedT) -> Self { + let (res, overflow) = self.overflowing_add(rhs as Self); + if overflow == (rhs < 0) { + res + } else if overflow { + Self::MAX + } else { + 0 + } + } + /// Saturating integer subtraction. Computes `self - rhs`, saturating /// at the numeric bounds instead of overflowing. /// @@ -1111,6 +1163,28 @@ macro_rules! uint_impl { intrinsics::wrapping_add(self, rhs) } + /// Wrapping (modular) addition with a signed integer. Computes + /// `self + rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(2), 3);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(-2), ", stringify!($SelfT), "::MAX);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).wrapping_add_signed(4), 1);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_add_signed(self, rhs: $SignedT) -> Self { + self.wrapping_add(rhs as Self) + } + /// Wrapping (modular) subtraction. Computes `self - rhs`, /// wrapping around at the boundary of the type. /// @@ -1435,6 +1509,32 @@ macro_rules! uint_impl { (c, b | d) } + /// Calculates `self` + `rhs` with a signed `rhs` + /// + /// Returns a tuple of the addition along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would + /// have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(2), (3, false));")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(-2), (", stringify!($SelfT), "::MAX, true));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_signed(4), (1, true));")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_add_signed(self, rhs: $SignedT) -> (Self, bool) { + let (res, overflowed) = self.overflowing_add(rhs as Self); + (res, overflowed ^ (rhs < 0)) + } + /// Calculates `self` - `rhs` /// /// Returns a tuple of the subtraction along with a boolean indicating diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 2b77dc54ab3..6bc445c6f2b 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -15,7 +15,7 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } -libc = { version = "0.2.99", default-features = false, features = ['rustc-dep-of-std'] } +libc = { version = "0.2.103", default-features = false, features = ['rustc-dep-of-std'] } compiler_builtins = { version = "0.1.44" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 25cc5e67ad1..980b2531192 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -292,12 +292,7 @@ where SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n), SeekFrom::Current(n) => (self.pos, n), }; - let new_pos = if offset >= 0 { - base_pos.checked_add(offset as u64) - } else { - base_pos.checked_sub((offset.wrapping_neg()) as u64) - }; - match new_pos { + match base_pos.checked_add_signed(offset) { Some(n) => { self.pos = n; Ok(self.pos) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0ba4e85886c..a7516bf4ffd 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -297,6 +297,7 @@ #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(min_specialization)] +#![feature(mixed_integer_ops)] #![cfg_attr(not(bootstrap), feature(must_not_suspend))] #![feature(needs_panic_runtime)] #![feature(negative_impls)] diff --git a/library/std/src/sys/hermit/thread.rs b/library/std/src/sys/hermit/thread.rs index 8be25f84999..81b21fbbb16 100644 --- a/library/std/src/sys/hermit/thread.rs +++ b/library/std/src/sys/hermit/thread.rs @@ -97,7 +97,7 @@ impl Thread { } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/sgx/thread.rs b/library/std/src/sys/sgx/thread.rs index cbb8ba96401..d745a619614 100644 --- a/library/std/src/sys/sgx/thread.rs +++ b/library/std/src/sys/sgx/thread.rs @@ -137,7 +137,7 @@ impl Thread { } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 5631834eca6..891f3413e91 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -263,7 +263,7 @@ impl Drop for Thread { } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { cfg_if::cfg_if! { if #[cfg(any( target_os = "android", diff --git a/library/std/src/sys/unsupported/thread.rs b/library/std/src/sys/unsupported/thread.rs index dc75d4ee672..a8db251de20 100644 --- a/library/std/src/sys/unsupported/thread.rs +++ b/library/std/src/sys/unsupported/thread.rs @@ -31,7 +31,7 @@ impl Thread { } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs index 9ec02bbec26..2e4e474c449 100644 --- a/library/std/src/sys/wasi/thread.rs +++ b/library/std/src/sys/wasi/thread.rs @@ -64,7 +64,7 @@ impl Thread { } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/wasm/atomics/thread.rs b/library/std/src/sys/wasm/atomics/thread.rs index a66ab083757..16418a06226 100644 --- a/library/std/src/sys/wasm/atomics/thread.rs +++ b/library/std/src/sys/wasm/atomics/thread.rs @@ -40,7 +40,7 @@ impl Thread { pub fn join(self) {} } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs index a5293133b3a..75f70c2076e 100644 --- a/library/std/src/sys/windows/thread.rs +++ b/library/std/src/sys/windows/thread.rs @@ -100,7 +100,7 @@ impl Thread { } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { let res = unsafe { let mut sysinfo: c::SYSTEM_INFO = crate::mem::zeroed(); c::GetSystemInfo(&mut sysinfo); diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 9d659102b03..707a55b6258 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1453,12 +1453,14 @@ fn _assert_sync_and_send() { /// /// ``` /// # #![allow(dead_code)] -/// #![feature(available_concurrency)] +/// #![feature(available_parallelism)] /// use std::thread; /// -/// let count = thread::available_concurrency().map(|n| n.get()).unwrap_or(1); +/// let count = thread::available_parallelism().map(|n| n.get()).unwrap_or(1); /// ``` -#[unstable(feature = "available_concurrency", issue = "74479")] -pub fn available_concurrency() -> io::Result { - imp::available_concurrency() +#[doc(alias = "hardware_concurrency")] // Alias for C++ `std::thread::hardware_concurrency`. +#[doc(alias = "available_concurrency")] // Alias for a name we gave this API on unstable. +#[unstable(feature = "available_parallelism", issue = "74479")] +pub fn available_parallelism() -> io::Result { + imp::available_parallelism() } diff --git a/library/test/src/helpers/concurrency.rs b/library/test/src/helpers/concurrency.rs index c39a9b0ec02..e25f524ec05 100644 --- a/library/test/src/helpers/concurrency.rs +++ b/library/test/src/helpers/concurrency.rs @@ -9,6 +9,6 @@ pub fn get_concurrency() -> usize { _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", value), } } else { - thread::available_concurrency().map(|n| n.get()).unwrap_or(1) + thread::available_parallelism().map(|n| n.get()).unwrap_or(1) } } diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 251f099f28a..6732c6c61c2 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -23,7 +23,7 @@ #![feature(libc)] #![feature(rustc_private)] #![feature(nll)] -#![feature(available_concurrency)] +#![feature(available_parallelism)] #![feature(bench_black_box)] #![feature(internal_output_capture)] #![feature(panic_unwind)] diff --git a/src/doc/rustc/src/tests/index.md b/src/doc/rustc/src/tests/index.md index ec23d4fe0db..04e20fdd41c 100644 --- a/src/doc/rustc/src/tests/index.md +++ b/src/doc/rustc/src/tests/index.md @@ -161,7 +161,7 @@ The following options affect how tests are executed. Sets the number of threads to use for running tests in parallel. By default, uses the amount of concurrency available on the hardware as indicated by -[`available_concurrency`]. +[`available_parallelism`]. This can also be specified with the `RUST_TEST_THREADS` environment variable. @@ -265,7 +265,7 @@ Experimental support for using custom test harnesses is available on the [`--test` option]: ../command-line-arguments.md#option-test [`-Z panic-abort-tests`]: https://github.com/rust-lang/rust/issues/67650 -[`available_concurrency`]: ../../std/thread/fn.available_concurrency.html +[`available_parallelism`]: ../../std/thread/fn.available_parallelism.html [`cargo test`]: ../../cargo/commands/cargo-test.html [`libtest`]: ../../test/index.html [`main` function]: ../../reference/crates-and-source-files.html#main-functions diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 56d2ca57218..302fc5a6777 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -1,4 +1,4 @@ -use crate::html::markdown::{ErrorCodes, IdMap, Markdown, Playground}; +use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground}; use crate::rustc_span::edition::Edition; use std::fs; use std::path::Path; @@ -39,14 +39,32 @@ impl ExternalHtml { let bc = format!( "{}{}", bc, - Markdown(&m_bc, &[], id_map, codes, edition, playground).into_string() + Markdown { + content: &m_bc, + links: &[], + ids: id_map, + error_codes: codes, + edition, + playground, + heading_offset: HeadingOffset::H2, + } + .into_string() ); let ac = load_external_files(after_content, diag)?; let m_ac = load_external_files(md_after_content, diag)?; let ac = format!( "{}{}", ac, - Markdown(&m_ac, &[], id_map, codes, edition, playground).into_string() + Markdown { + content: &m_ac, + links: &[], + ids: id_map, + error_codes: codes, + edition, + playground, + heading_offset: HeadingOffset::H2, + } + .into_string() ); Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac }) } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index fda2512a050..9f2e282fce1 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -8,11 +8,19 @@ //! extern crate rustc_span; //! //! use rustc_span::edition::Edition; -//! use rustdoc::html::markdown::{IdMap, Markdown, ErrorCodes}; +//! use rustdoc::html::markdown::{HeadingOffset, IdMap, Markdown, ErrorCodes}; //! //! let s = "My *markdown* _text_"; //! let mut id_map = IdMap::new(); -//! let md = Markdown(s, &[], &mut id_map, ErrorCodes::Yes, Edition::Edition2015, &None); +//! let md = Markdown { +//! content: s, +//! links: &[], +//! ids: &mut id_map, +//! error_codes: ErrorCodes::Yes, +//! edition: Edition::Edition2015, +//! playground: &None, +//! heading_offset: HeadingOffset::H2, +//! }; //! let html = md.into_string(); //! // ... something using html //! ``` @@ -47,6 +55,8 @@ use pulldown_cmark::{ #[cfg(test)] mod tests; +const MAX_HEADER_LEVEL: u32 = 6; + /// Options for rendering Markdown in the main body of documentation. pub(crate) fn main_body_opts() -> Options { Options::ENABLE_TABLES @@ -65,20 +75,33 @@ pub(crate) fn summary_opts() -> Options { | Options::ENABLE_SMART_PUNCTUATION } +#[derive(Debug, Clone, Copy)] +pub enum HeadingOffset { + H1 = 0, + H2, + H3, + H4, + H5, + H6, +} + /// When `to_string` is called, this struct will emit the HTML corresponding to /// the rendered version of the contained markdown string. -pub struct Markdown<'a>( - pub &'a str, +pub struct Markdown<'a> { + pub content: &'a str, /// A list of link replacements. - pub &'a [RenderedLink], + pub links: &'a [RenderedLink], /// The current list of used header IDs. - pub &'a mut IdMap, + pub ids: &'a mut IdMap, /// Whether to allow the use of explicit error codes in doctest lang strings. - pub ErrorCodes, + pub error_codes: ErrorCodes, /// Default edition to use when parsing doctests (to add a `fn main`). - pub Edition, - pub &'a Option, -); + pub edition: Edition, + pub playground: &'a Option, + /// Offset at which we render headings. + /// E.g. if `heading_offset: HeadingOffset::H2`, then `# something` renders an `

`. + pub heading_offset: HeadingOffset, +} /// A tuple struct like `Markdown` that renders the markdown with a table of contents. crate struct MarkdownWithToc<'a>( crate &'a str, @@ -489,11 +512,17 @@ struct HeadingLinks<'a, 'b, 'ids, I> { toc: Option<&'b mut TocBuilder>, buf: VecDeque>, id_map: &'ids mut IdMap, + heading_offset: HeadingOffset, } impl<'a, 'b, 'ids, I> HeadingLinks<'a, 'b, 'ids, I> { - fn new(iter: I, toc: Option<&'b mut TocBuilder>, ids: &'ids mut IdMap) -> Self { - HeadingLinks { inner: iter, toc, buf: VecDeque::new(), id_map: ids } + fn new( + iter: I, + toc: Option<&'b mut TocBuilder>, + ids: &'ids mut IdMap, + heading_offset: HeadingOffset, + ) -> Self { + HeadingLinks { inner: iter, toc, buf: VecDeque::new(), id_map: ids, heading_offset } } } @@ -530,6 +559,7 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator self.buf.push_front((Event::Html(format!("{} ", sec).into()), 0..0)); } + let level = std::cmp::min(level + (self.heading_offset as u32), MAX_HEADER_LEVEL); self.buf.push_back((Event::Html(format!("", level).into()), 0..0)); let start_tags = format!( @@ -1005,7 +1035,15 @@ impl LangString { impl Markdown<'_> { pub fn into_string(self) -> String { - let Markdown(md, links, mut ids, codes, edition, playground) = self; + let Markdown { + content: md, + links, + mut ids, + error_codes: codes, + edition, + playground, + heading_offset, + } = self; // This is actually common enough to special-case if md.is_empty() { @@ -1026,7 +1064,7 @@ impl Markdown<'_> { let mut s = String::with_capacity(md.len() * 3 / 2); - let p = HeadingLinks::new(p, None, &mut ids); + let p = HeadingLinks::new(p, None, &mut ids, heading_offset); let p = Footnotes::new(p); let p = LinkReplacer::new(p.map(|(ev, _)| ev), links); let p = TableWrapper::new(p); @@ -1048,7 +1086,7 @@ impl MarkdownWithToc<'_> { let mut toc = TocBuilder::new(); { - let p = HeadingLinks::new(p, Some(&mut toc), &mut ids); + let p = HeadingLinks::new(p, Some(&mut toc), &mut ids, HeadingOffset::H1); let p = Footnotes::new(p); let p = TableWrapper::new(p.map(|(ev, _)| ev)); let p = CodeBlocks::new(p, codes, edition, playground); @@ -1077,7 +1115,7 @@ impl MarkdownHtml<'_> { let mut s = String::with_capacity(md.len() * 3 / 2); - let p = HeadingLinks::new(p, None, &mut ids); + let p = HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1); let p = Footnotes::new(p); let p = TableWrapper::new(p.map(|(ev, _)| ev)); let p = CodeBlocks::new(p, codes, edition, playground); @@ -1295,7 +1333,7 @@ crate fn markdown_links(md: &str) -> Vec { // There's no need to thread an IdMap through to here because // the IDs generated aren't going to be emitted anywhere. let mut ids = IdMap::new(); - let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids)); + let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1)); for ev in iter { if let Event::Start(Tag::Link(kind, dest, _)) = ev.0 { diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 1e4cf3381f6..68ab002f138 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -1,5 +1,5 @@ use super::{find_testable_code, plain_text_summary, short_markdown_summary}; -use super::{ErrorCodes, IdMap, Ignore, LangString, Markdown, MarkdownHtml}; +use super::{ErrorCodes, HeadingOffset, IdMap, Ignore, LangString, Markdown, MarkdownHtml}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; #[test] @@ -147,33 +147,41 @@ fn test_lang_string_tokenizer() { fn test_header() { fn t(input: &str, expect: &str) { let mut map = IdMap::new(); - let output = - Markdown(input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string(); + let output = Markdown { + content: input, + links: &[], + ids: &mut map, + error_codes: ErrorCodes::Yes, + edition: DEFAULT_EDITION, + playground: &None, + heading_offset: HeadingOffset::H2, + } + .into_string(); assert_eq!(output, expect, "original: {}", input); } t( "# Foo bar", - "

Foo bar

", + "

Foo bar

", ); t( "## Foo-bar_baz qux", - "

\ - Foo-bar_baz qux

", + "

\ + Foo-bar_baz qux

", ); t( "### **Foo** *bar* baz!?!& -_qux_-%", - "

\ + "

\ Foo \ bar baz!?!& -qux-%\ -

", +

", ); t( "#### **Foo?** & \\*bar?!* _`baz`_ ❤ #qux", - "

\ + "

\ Foo? & *bar?!* \ baz ❤ #qux\ -
", + ", ); } @@ -181,40 +189,48 @@ fn test_header() { fn test_header_ids_multiple_blocks() { let mut map = IdMap::new(); fn t(map: &mut IdMap, input: &str, expect: &str) { - let output = - Markdown(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string(); + let output = Markdown { + content: input, + links: &[], + ids: map, + error_codes: ErrorCodes::Yes, + edition: DEFAULT_EDITION, + playground: &None, + heading_offset: HeadingOffset::H2, + } + .into_string(); assert_eq!(output, expect, "original: {}", input); } t( &mut map, "# Example", - "

Example

", + "

Example

", ); t( &mut map, "# Panics", - "

Panics

", + "

Panics

", ); t( &mut map, "# Example", - "

Example

", + "

Example

", ); t( &mut map, "# Main", - "

Main

", + "

Main

", ); t( &mut map, "# Example", - "

Example

", + "

Example

", ); t( &mut map, "# Panics", - "

Panics

", + "

Panics

", ); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 5045a99800a..11682afdf89 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -67,7 +67,7 @@ use crate::html::format::{ href, print_abi_with_space, print_constness_with_space, print_default_space, print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace, }; -use crate::html::markdown::{Markdown, MarkdownHtml, MarkdownSummaryLine}; +use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine}; /// A pair of name and its optional document. crate type NameDoc = (String, Option); @@ -470,32 +470,45 @@ fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result, item: &clean::Item, parent: Option<&clean::Item>) { +fn document( + w: &mut Buffer, + cx: &Context<'_>, + item: &clean::Item, + parent: Option<&clean::Item>, + heading_offset: HeadingOffset, +) { if let Some(ref name) = item.name { info!("Documenting {}", name); } document_item_info(w, cx, item, parent); if parent.is_none() { - document_full_collapsible(w, item, cx); + document_full_collapsible(w, item, cx, heading_offset); } else { - document_full(w, item, cx); + document_full(w, item, cx, heading_offset); } } /// Render md_text as markdown. -fn render_markdown(w: &mut Buffer, cx: &Context<'_>, md_text: &str, links: Vec) { +fn render_markdown( + w: &mut Buffer, + cx: &Context<'_>, + md_text: &str, + links: Vec, + heading_offset: HeadingOffset, +) { let mut ids = cx.id_map.borrow_mut(); write!( w, "
{}
", - Markdown( - md_text, - &links, - &mut ids, - cx.shared.codes, - cx.shared.edition(), - &cx.shared.playground - ) + Markdown { + content: md_text, + links: &links, + ids: &mut ids, + error_codes: cx.shared.codes, + edition: cx.shared.edition(), + playground: &cx.shared.playground, + heading_offset, + } .into_string() ) } @@ -531,15 +544,31 @@ fn document_short( } } -fn document_full_collapsible(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) { - document_full_inner(w, item, cx, true); +fn document_full_collapsible( + w: &mut Buffer, + item: &clean::Item, + cx: &Context<'_>, + heading_offset: HeadingOffset, +) { + document_full_inner(w, item, cx, true, heading_offset); } -fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) { - document_full_inner(w, item, cx, false); +fn document_full( + w: &mut Buffer, + item: &clean::Item, + cx: &Context<'_>, + heading_offset: HeadingOffset, +) { + document_full_inner(w, item, cx, false, heading_offset); } -fn document_full_inner(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>, is_collapsible: bool) { +fn document_full_inner( + w: &mut Buffer, + item: &clean::Item, + cx: &Context<'_>, + is_collapsible: bool, + heading_offset: HeadingOffset, +) { if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) { debug!("Doc block: =====\n{}\n=====", s); if is_collapsible { @@ -549,10 +578,10 @@ fn document_full_inner(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>, is_ Expand description\ ", ); - render_markdown(w, cx, &s, item.links(cx)); + render_markdown(w, cx, &s, item.links(cx), heading_offset); w.write_str(""); } else { - render_markdown(w, cx, &s, item.links(cx)); + render_markdown(w, cx, &s, item.links(cx), heading_offset); } } } @@ -1321,7 +1350,7 @@ fn render_impl( // because impls can't have a stability. if item.doc_value().is_some() { document_item_info(&mut info_buffer, cx, it, Some(parent)); - document_full(&mut doc_buffer, item, cx); + document_full(&mut doc_buffer, item, cx, HeadingOffset::H5); short_documented = false; } else { // In case the item isn't documented, @@ -1339,7 +1368,7 @@ fn render_impl( } else { document_item_info(&mut info_buffer, cx, item, Some(parent)); if rendering_params.show_def_docs { - document_full(&mut doc_buffer, item, cx); + document_full(&mut doc_buffer, item, cx, HeadingOffset::H5); short_documented = false; } } @@ -1573,14 +1602,15 @@ fn render_impl( write!( w, "
{}
", - Markdown( - &*dox, - &i.impl_item.links(cx), - &mut ids, - cx.shared.codes, - cx.shared.edition(), - &cx.shared.playground - ) + Markdown { + content: &*dox, + links: &i.impl_item.links(cx), + ids: &mut ids, + error_codes: cx.shared.codes, + edition: cx.shared.edition(), + playground: &cx.shared.playground, + heading_offset: HeadingOffset::H2 + } .into_string() ); } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 28b2eded7cc..1275fa4e156 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -30,7 +30,7 @@ use crate::html::format::{ }; use crate::html::highlight; use crate::html::layout::Page; -use crate::html::markdown::MarkdownSummaryLine; +use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine}; const ITEM_TABLE_OPEN: &'static str = "
"; const ITEM_TABLE_CLOSE: &'static str = "
"; @@ -175,7 +175,7 @@ fn toggle_close(w: &mut Buffer) { } fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) { - document(w, cx, item, None); + document(w, cx, item, None, HeadingOffset::H2); let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::>(); @@ -482,7 +482,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean:: notable_traits = notable_traits_decl(&f.decl, cx), ); }); - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) { @@ -605,7 +605,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra }); // Trait documentation - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) { write!( @@ -623,7 +623,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); let mut content = Buffer::empty_from(w); - document(&mut content, cx, m, Some(t)); + document(&mut content, cx, m, Some(t), HeadingOffset::H5); let toggled = !content.is_empty(); if toggled { write!(w, "
"); @@ -837,7 +837,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea ); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -859,7 +859,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean: ); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -890,7 +890,7 @@ fn item_typedef( ); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); let def_id = it.def_id.expect_def_id(); // Render any items associated directly to this alias, as otherwise they @@ -908,7 +908,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni }); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); let mut fields = s .fields @@ -941,7 +941,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni if let Some(stability_class) = field.stability_class(cx.tcx()) { write!(w, "", stab = stability_class); } - document(w, cx, field, Some(it)); + document(w, cx, field, Some(it), HeadingOffset::H2); } } let def_id = it.def_id.expect_def_id(); @@ -1023,7 +1023,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum }); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); if !e.variants.is_empty() { write!( @@ -1052,7 +1052,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum w.write_str(""); render_stability_since(w, variant, it, cx.tcx()); w.write_str(""); - document(w, cx, variant, Some(it)); + document(w, cx, variant, Some(it), HeadingOffset::H2); document_non_exhaustive(w, variant); use crate::clean::Variant; @@ -1092,7 +1092,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum f = field.name.as_ref().unwrap(), t = ty.print(cx) ); - document(w, cx, field, Some(variant)); + document(w, cx, field, Some(variant), HeadingOffset::H2); } _ => unreachable!(), } @@ -1119,7 +1119,7 @@ fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Mac None, ); }); - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) { @@ -1149,11 +1149,11 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean }); } } - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All) } @@ -1192,7 +1192,7 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean:: } }); - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) { @@ -1203,7 +1203,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St }); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); let mut fields = s .fields @@ -1239,7 +1239,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St name = field_name, ty = ty.print(cx) ); - document(w, cx, field, Some(it)); + document(w, cx, field, Some(it), HeadingOffset::H2); } } } @@ -1260,7 +1260,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St typ = s.type_.print(cx) ); }); - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { @@ -1275,13 +1275,13 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { ); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All) } fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } /// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order). diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 341d9b80fd8..5d33681847a 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -126,7 +126,7 @@ h2 { h3 { font-size: 1.3em; } -h1, h2, h3, h4 { +h1, h2, h3, h4, h5, h6 { font-weight: 500; margin: 20px 0 15px 0; padding-bottom: 6px; @@ -179,7 +179,7 @@ div.impl-items > div { padding-left: 0; } -h1, h2, h3, h4, +h1, h2, h3, h4, h5, h6, .sidebar, a.source, .search-input, .search-results .result-name, .content table td:first-child > a, .item-left > a, @@ -501,21 +501,20 @@ nav.sub { white-space: pre-wrap; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { border-bottom: 1px solid; } -.top-doc .docblock h1 { font-size: 1.3em; } -.top-doc .docblock h2 { font-size: 1.15em; } -.top-doc .docblock h3, +.top-doc .docblock h2 { font-size: 1.3em; } +.top-doc .docblock h3 { font-size: 1.15em; } .top-doc .docblock h4, -.top-doc .docblock h5 { +.top-doc .docblock h5, +.top-doc .docblock h6 { font-size: 1em; } -.docblock h1 { font-size: 1em; } -.docblock h2 { font-size: 0.95em; } -.docblock h3, .docblock h4, .docblock h5 { font-size: 0.9em; } +.docblock h5 { font-size: 1em; } +.docblock h6 { font-size: 0.95em; } .docblock { margin-left: 24px; diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index c79801e8308..0fd6462a8f5 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -136,7 +136,7 @@ pre, .rustdoc.source .example-wrap { border-right: 1px solid #ffb44c; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { border-bottom-color: #5c6773; } diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index d2e54070acd..d863701dd73 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -93,7 +93,7 @@ pre, .rustdoc.source .example-wrap { background-color: #0a042f !important; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { border-bottom-color: #DDD; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 25d810560c1..28d2e99a3d0 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -93,7 +93,7 @@ pre, .rustdoc.source .example-wrap { background-color: #f6fdb0 !important; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { border-bottom-color: #ddd; } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 2ae4897dc34..47b24d40edc 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -10,7 +10,9 @@ use crate::config::{Options, RenderOptions}; use crate::doctest::{Collector, TestOptions}; use crate::html::escape::Escape; use crate::html::markdown; -use crate::html::markdown::{find_testable_code, ErrorCodes, IdMap, Markdown, MarkdownWithToc}; +use crate::html::markdown::{ + find_testable_code, ErrorCodes, HeadingOffset, IdMap, Markdown, MarkdownWithToc, +}; /// Separate any lines at the start of the file that begin with `# ` or `%`. fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) { @@ -70,7 +72,16 @@ crate fn render>( let text = if !options.markdown_no_toc { MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).into_string() } else { - Markdown(text, &[], &mut ids, error_codes, edition, &playground).into_string() + Markdown { + content: text, + links: &[], + ids: &mut ids, + error_codes, + edition, + playground: &playground, + heading_offset: HeadingOffset::H1, + } + .into_string() }; let err = write!( diff --git a/src/test/codegen/alloc-optimisation.rs b/src/test/codegen/alloc-optimisation.rs index 5b27f3f4545..aee93b93e37 100644 --- a/src/test/codegen/alloc-optimisation.rs +++ b/src/test/codegen/alloc-optimisation.rs @@ -1,4 +1,5 @@ // +// no-system-llvm // min-llvm-version: 10.0.1 // compile-flags: -O #![crate_type="lib"] diff --git a/src/test/rustdoc/external-cross.rs b/src/test/rustdoc/external-cross.rs index 056ed353462..3f8e1688291 100644 --- a/src/test/rustdoc/external-cross.rs +++ b/src/test/rustdoc/external-cross.rs @@ -6,5 +6,5 @@ extern crate external_cross; // @has host/struct.NeedMoreDocs.html -// @has - '//h1' 'Cross-crate imported docs' +// @has - '//h2' 'Cross-crate imported docs' pub use external_cross::NeedMoreDocs; diff --git a/src/test/rustdoc/external-doc.rs b/src/test/rustdoc/external-doc.rs index fc29cb252e2..bd322d67a37 100644 --- a/src/test/rustdoc/external-doc.rs +++ b/src/test/rustdoc/external-doc.rs @@ -1,6 +1,6 @@ // @has external_doc/struct.IncludeStrDocs.html -// @has - '//h1' 'External Docs' -// @has - '//h2' 'Inline Docs' +// @has - '//h2' 'External Docs' +// @has - '//h3' 'Inline Docs' #[doc = include_str!("auxiliary/external-doc.md")] /// ## Inline Docs pub struct IncludeStrDocs; @@ -8,7 +8,7 @@ pub struct IncludeStrDocs; macro_rules! dir { () => { "auxiliary" } } // @has external_doc/struct.EagerExpansion.html -// @has - '//h1' 'External Docs' +// @has - '//h2' 'External Docs' #[doc = include_str!(concat!(dir!(), "/external-doc.md"))] /// ## Inline Docs pub struct EagerExpansion; diff --git a/src/test/rustdoc/issue-42760.rs b/src/test/rustdoc/issue-42760.rs index b07dc3f6e96..4944f815701 100644 --- a/src/test/rustdoc/issue-42760.rs +++ b/src/test/rustdoc/issue-42760.rs @@ -1,5 +1,5 @@ // @has issue_42760/struct.NonGen.html -// @has - '//h1' 'Example' +// @has - '//h2' 'Example' /// Item docs. /// diff --git a/src/test/rustdoc/issue-89309-heading-levels.rs b/src/test/rustdoc/issue-89309-heading-levels.rs new file mode 100644 index 00000000000..bb706c28ffa --- /dev/null +++ b/src/test/rustdoc/issue-89309-heading-levels.rs @@ -0,0 +1,29 @@ +#![crate_name = "foo"] + +// @has foo/trait.Read.html +// @has - '//h2' 'Trait examples' +/// # Trait examples +pub trait Read { + // @has - '//h5' 'Function examples' + /// # Function examples + fn read(&mut self, buf: &mut [u8]) -> Result; +} + +pub struct Foo; + +// @has foo/struct.Foo.html +impl Foo { + // @has - '//h5' 'Implementation header' + /// # Implementation header + pub fn bar(&self) -> usize { + 1 + } +} + +impl Read for Foo { + // @has - '//h5' 'Trait implementation header' + /// # Trait implementation header + fn read(&mut self, buf: &mut [u8]) -> Result { + Ok(1) + } +} diff --git a/src/test/rustdoc/short-docblock.rs b/src/test/rustdoc/short-docblock.rs index 74fa783174d..17c44eab091 100644 --- a/src/test/rustdoc/short-docblock.rs +++ b/src/test/rustdoc/short-docblock.rs @@ -2,7 +2,7 @@ // @has foo/index.html '//*[@class="item-right docblock-short"]/p' 'fooo' // @!has foo/index.html '//*[@class="item-right docblock-short"]/p/h1' 'fooo' -// @has foo/fn.foo.html '//h1[@id="fooo"]/a[@href="#fooo"]' 'fooo' +// @has foo/fn.foo.html '//h2[@id="fooo"]/a[@href="#fooo"]' 'fooo' /// # fooo /// @@ -11,7 +11,7 @@ pub fn foo() {} // @has foo/index.html '//*[@class="item-right docblock-short"]/p' 'mooood' // @!has foo/index.html '//*[@class="item-right docblock-short"]/p/h2' 'mooood' -// @has foo/foo/index.html '//h2[@id="mooood"]/a[@href="#mooood"]' 'mooood' +// @has foo/foo/index.html '//h3[@id="mooood"]/a[@href="#mooood"]' 'mooood' /// ## mooood /// diff --git a/src/test/rustdoc/smart-punct.rs b/src/test/rustdoc/smart-punct.rs index 5319892c99c..7ae5bd69945 100644 --- a/src/test/rustdoc/smart-punct.rs +++ b/src/test/rustdoc/smart-punct.rs @@ -21,7 +21,7 @@ //! ``` // @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?" -// @has "foo/index.html" "//h1" "Header with “smart punct’”" +// @has "foo/index.html" "//h2" "Header with “smart punct’”" // @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!" // @has "foo/index.html" '//code' "this inline code -- it shouldn't have \"smart punct\"" // @has "foo/index.html" '//pre' "let x = \"don't smart-punct me -- please!\";" diff --git a/src/test/ui/async-await/issues/issue-62097.nll.stderr b/src/test/ui/async-await/issues/issue-62097.nll.stderr index e71bcf58228..786f6213260 100644 --- a/src/test/ui/async-await/issues/issue-62097.nll.stderr +++ b/src/test/ui/async-await/issues/issue-62097.nll.stderr @@ -20,9 +20,15 @@ error[E0521]: borrowed data escapes outside of associated function --> $DIR/issue-62097.rs:13:9 | LL | pub async fn run_dummy_fn(&self) { - | ----- `self` is a reference that is only valid in the associated function body + | ----- + | | + | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` LL | foo(|| self.bar()).await; - | ^^^^^^^^^^^^^^^^^^ `self` escapes the associated function body here + | ^^^^^^^^^^^^^^^^^^ + | | + | `self` escapes the associated function body here + | argument requires that `'1` must outlive `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/cast/issue-89497.fixed b/src/test/ui/cast/issue-89497.fixed new file mode 100644 index 00000000000..04c10a5f79e --- /dev/null +++ b/src/test/ui/cast/issue-89497.fixed @@ -0,0 +1,10 @@ +// Regression test for issue #89497. + +// run-rustfix + +fn main() { + let pointer: usize = &1_i32 as *const i32 as usize; + let _reference: &'static i32 = unsafe { &*(pointer as *const i32) }; + //~^ ERROR: non-primitive cast + //~| HELP: consider borrowing the value +} diff --git a/src/test/ui/cast/issue-89497.rs b/src/test/ui/cast/issue-89497.rs new file mode 100644 index 00000000000..76301b704c8 --- /dev/null +++ b/src/test/ui/cast/issue-89497.rs @@ -0,0 +1,10 @@ +// Regression test for issue #89497. + +// run-rustfix + +fn main() { + let pointer: usize = &1_i32 as *const i32 as usize; + let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 }; + //~^ ERROR: non-primitive cast + //~| HELP: consider borrowing the value +} diff --git a/src/test/ui/cast/issue-89497.stderr b/src/test/ui/cast/issue-89497.stderr new file mode 100644 index 00000000000..3726f8a4101 --- /dev/null +++ b/src/test/ui/cast/issue-89497.stderr @@ -0,0 +1,15 @@ +error[E0605]: non-primitive cast: `*const i32` as `&'static i32` + --> $DIR/issue-89497.rs:7:45 + | +LL | let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast + | +help: consider borrowing the value + | +LL - let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 }; +LL + let _reference: &'static i32 = unsafe { &*(pointer as *const i32) }; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0605`. diff --git a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs new file mode 100644 index 00000000000..b79bc262d2b --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs @@ -0,0 +1,29 @@ +// run-pass +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +trait Foo { + type Assoc: Default; +} + +impl Foo<0> for () { + type Assoc = u32; +} + +impl Foo<3> for () { + type Assoc = i64; +} + +fn foo(_: T) -> <() as Foo<{ N + 1 }>>::Assoc +where + (): Foo<{ N + 1 }>, +{ + Default::default() +} + +fn main() { + // Test that we can correctly infer `T` which requires evaluating + // `{ N + 1 }` which has substs containing an inference var + let mut _q = Default::default(); + _q = foo::<_, 2>(_q); +} diff --git a/src/test/ui/error-codes/E0605.stderr b/src/test/ui/error-codes/E0605.stderr index e5647ee6d09..d082b6c10cc 100644 --- a/src/test/ui/error-codes/E0605.stderr +++ b/src/test/ui/error-codes/E0605.stderr @@ -12,8 +12,9 @@ LL | v as &u8; | help: consider borrowing the value | -LL | &*v as &u8; - | ++ +LL - v as &u8; +LL + &*v; + | error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr index e49bd9da754..88c260b18cb 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr @@ -2,9 +2,14 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/dyn-trait.rs:20:5 | LL | fn with_dyn_debug_static<'a>(x: Box) { - | - `x` is a reference that is only valid in the function body + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | static_val(x); - | ^^^^^^^^^^^^^ `x` escapes the function body here + | ^^^^^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16683.nll.stderr b/src/test/ui/issues/issue-16683.nll.stderr index 51d86eaf9e6..0e8f520353f 100644 --- a/src/test/ui/issues/issue-16683.nll.stderr +++ b/src/test/ui/issues/issue-16683.nll.stderr @@ -1,10 +1,19 @@ error[E0521]: borrowed data escapes outside of associated function --> $DIR/issue-16683.rs:4:9 | +LL | trait T<'a> { + | -- lifetime `'a` defined here +LL | fn a(&'a self) -> &'a bool; LL | fn b(&self) { - | ----- `self` is a reference that is only valid in the associated function body + | ----- + | | + | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` LL | self.a(); - | ^^^^^^^^ `self` escapes the associated function body here + | ^^^^^^^^ + | | + | `self` escapes the associated function body here + | argument requires that `'1` must outlive `'a` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17758.nll.stderr b/src/test/ui/issues/issue-17758.nll.stderr index 075c141ed7a..b929fdbf368 100644 --- a/src/test/ui/issues/issue-17758.nll.stderr +++ b/src/test/ui/issues/issue-17758.nll.stderr @@ -1,10 +1,19 @@ error[E0521]: borrowed data escapes outside of associated function --> $DIR/issue-17758.rs:7:9 | +LL | trait Foo<'a> { + | -- lifetime `'a` defined here +LL | fn foo(&'a self); LL | fn bar(&self) { - | ----- `self` is a reference that is only valid in the associated function body + | ----- + | | + | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` LL | self.foo(); - | ^^^^^^^^^^ `self` escapes the associated function body here + | ^^^^^^^^^^ + | | + | `self` escapes the associated function body here + | argument requires that `'1` must outlive `'a` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2995.stderr b/src/test/ui/issues/issue-2995.stderr index 455d32e233a..7616f987d73 100644 --- a/src/test/ui/issues/issue-2995.stderr +++ b/src/test/ui/issues/issue-2995.stderr @@ -6,8 +6,9 @@ LL | let _q: &isize = p as &isize; | help: consider borrowing the value | -LL | let _q: &isize = &*p as &isize; - | ++ +LL - let _q: &isize = p as &isize; +LL + let _q: &isize = &*p; + | error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr index 050d5fcf05e..6f3f84096e4 100644 --- a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr @@ -2,19 +2,29 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/lifetime-bound-will-change-warning.rs:34:5 | LL | fn test2<'a>(x: &'a Box) { - | - `x` is a reference that is only valid in the function body + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | // but ref_obj will not, so warn. LL | ref_obj(x) - | ^^^^^^^^^^ `x` escapes the function body here + | ^^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function --> $DIR/lifetime-bound-will-change-warning.rs:39:5 | LL | fn test2cc<'a>(x: &'a Box) { - | - `x` is a reference that is only valid in the function body + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | // same as test2, but cross crate LL | lib::ref_obj(x) - | ^^^^^^^^^^^^^^^ `x` escapes the function body here + | ^^^^^^^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index a47eb87cff0..7f91d5ed42c 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -28,8 +28,9 @@ LL | let _ = v as &u8; | help: consider borrowing the value | -LL | let _ = &*v as &u8; - | ++ +LL - let _ = v as &u8; +LL + let _ = &*v; + | error[E0605]: non-primitive cast: `*const u8` as `E` --> $DIR/cast-rfc0401.rs:30:13 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index d17a40a95c1..d77793291c5 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -38,14 +38,19 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:5 | LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { - | ------ `cell_a` is a reference that is only valid in the function body + | -- ------ `cell_a` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { LL | | LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | }); - | |______^ `cell_a` escapes the function body here + | | ^ + | | | + | |______`cell_a` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index 06c46ec8259..cc67270ad20 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -38,14 +38,19 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:5 | LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { - | ------ `cell_a` is a reference that is only valid in the function body + | -- ------ `cell_a` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { LL | | LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | }); - | |______^ `cell_a` escapes the function body here + | | ^ + | | | + | |______`cell_a` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/issue-67007-escaping-data.rs b/src/test/ui/nll/issue-67007-escaping-data.rs new file mode 100644 index 00000000000..8c21737e05f --- /dev/null +++ b/src/test/ui/nll/issue-67007-escaping-data.rs @@ -0,0 +1,26 @@ +// Regression test for issue #67007 +// Ensures that we show information about the specific regions involved + +#![feature(nll)] + +// Covariant over 'a, invariant over 'tcx +struct FnCtxt<'a, 'tcx: 'a>(&'a (), *mut &'tcx ()); + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + fn use_it(&self, _: &'tcx ()) {} +} + +struct Consumer<'tcx>(&'tcx ()); + +impl<'tcx> Consumer<'tcx> { + fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { + let other = self.use_fcx(fcx); //~ ERROR borrowed data + fcx.use_it(other); + } + + fn use_fcx<'a>(&self, _: &FnCtxt<'a, 'tcx>) -> &'a () { + &() + } +} + +fn main() {} diff --git a/src/test/ui/nll/issue-67007-escaping-data.stderr b/src/test/ui/nll/issue-67007-escaping-data.stderr new file mode 100644 index 00000000000..2834d6fb0d2 --- /dev/null +++ b/src/test/ui/nll/issue-67007-escaping-data.stderr @@ -0,0 +1,21 @@ +error[E0521]: borrowed data escapes outside of associated function + --> $DIR/issue-67007-escaping-data.rs:17:21 + | +LL | impl<'tcx> Consumer<'tcx> { + | ---- lifetime `'tcx` defined here +LL | fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { + | -- ----- --- `fcx` is a reference that is only valid in the associated function body + | | | + | | `self` declared here, outside of the associated function body + | lifetime `'a` defined here +LL | let other = self.use_fcx(fcx); + | ^^^^^^^^^^^^^^^^^ + | | + | `fcx` escapes the associated function body here + | argument requires that `'a` must outlive `'tcx` + | + = help: consider adding the following bound: `'a: 'tcx` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/nll/outlives-suggestion-simple.stderr b/src/test/ui/nll/outlives-suggestion-simple.stderr index fa85ce27990..3b2017d2d03 100644 --- a/src/test/ui/nll/outlives-suggestion-simple.stderr +++ b/src/test/ui/nll/outlives-suggestion-simple.stderr @@ -92,13 +92,20 @@ LL | self.x error[E0521]: borrowed data escapes outside of associated function --> $DIR/outlives-suggestion-simple.rs:73:9 | +LL | impl<'a> Foo2<'a> { + | -- lifetime `'a` defined here +LL | // should not produce outlives suggestions to name 'self LL | fn get_bar(&self) -> Bar2 { | ----- | | | `self` declared here, outside of the associated function body | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` LL | Bar2::new(&self) - | ^^^^^^^^^^^^^^^^ `self` escapes the associated function body here + | ^^^^^^^^^^^^^^^^ + | | + | `self` escapes the associated function body here + | argument requires that `'1` must outlive `'a` error: aborting due to 9 previous errors diff --git a/src/test/ui/nll/user-annotations/closure-substs.stderr b/src/test/ui/nll/user-annotations/closure-substs.stderr index 55bb3a6090c..20002e4591d 100644 --- a/src/test/ui/nll/user-annotations/closure-substs.stderr +++ b/src/test/ui/nll/user-annotations/closure-substs.stderr @@ -28,9 +28,14 @@ error[E0521]: borrowed data escapes outside of closure --> $DIR/closure-substs.rs:29:9 | LL | |x: &i32, b: fn(&'static i32)| { - | - `x` is a reference that is only valid in the closure body + | - - let's call the lifetime of this reference `'1` + | | + | `x` is a reference that is only valid in the closure body LL | b(x); - | ^^^^ `x` escapes the closure body here + | ^^^^ + | | + | `x` escapes the closure body here + | argument requires that `'1` must outlive `'static` error: aborting due to 4 previous errors diff --git a/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr index 6ce1b2eed85..af20c5e5fc0 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr @@ -15,9 +15,14 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/object-lifetime-default-mybox.rs:31:5 | LL | fn load2<'a>(ss: &MyBox) -> MyBox { - | -- `ss` is a reference that is only valid in the function body + | -- -- `ss` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | load0(ss) - | ^^^^^^^^^ `ss` escapes the function body here + | ^^^^^^^^^ + | | + | `ss` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs index c234547bd14..06a62db4ebb 100644 --- a/src/test/ui/print_type_sizes/uninhabited.rs +++ b/src/test/ui/print_type_sizes/uninhabited.rs @@ -11,5 +11,5 @@ fn start(_: isize, _: *const *const u8) -> isize { let _x: Option = None; let _y: Result = Ok(42); - 0 + let _z: Result = loop {}; } diff --git a/src/test/ui/print_type_sizes/uninhabited.stdout b/src/test/ui/print_type_sizes/uninhabited.stdout index 2a8706f7ac5..5eb5384bce3 100644 --- a/src/test/ui/print_type_sizes/uninhabited.stdout +++ b/src/test/ui/print_type_sizes/uninhabited.stdout @@ -3,3 +3,4 @@ print-type-size variant `Ok`: 4 bytes print-type-size field `.0`: 4 bytes print-type-size type: `std::option::Option`: 0 bytes, alignment: 1 bytes print-type-size variant `None`: 0 bytes +print-type-size type: `std::result::Result`: 0 bytes, alignment: 1 bytes diff --git a/src/test/ui/regions/issue-78262.nll.stderr b/src/test/ui/regions/issue-78262.nll.stderr index a35d6fd9bf8..721dafac0be 100644 --- a/src/test/ui/regions/issue-78262.nll.stderr +++ b/src/test/ui/regions/issue-78262.nll.stderr @@ -2,8 +2,11 @@ error[E0521]: borrowed data escapes outside of closure --> $DIR/issue-78262.rs:14:26 | LL | let f = |x: &dyn TT| x.func(); - | - ^^^^^^^^ `x` escapes the closure body here - | | + | - - ^^^^^^^^ + | | | | + | | | `x` escapes the closure body here + | | | argument requires that `'1` must outlive `'static` + | | let's call the lifetime of this reference `'1` | `x` is a reference that is only valid in the closure body error: aborting due to previous error diff --git a/src/test/ui/regions/issue-78262.polonius.stderr b/src/test/ui/regions/issue-78262.polonius.stderr index a35d6fd9bf8..721dafac0be 100644 --- a/src/test/ui/regions/issue-78262.polonius.stderr +++ b/src/test/ui/regions/issue-78262.polonius.stderr @@ -2,8 +2,11 @@ error[E0521]: borrowed data escapes outside of closure --> $DIR/issue-78262.rs:14:26 | LL | let f = |x: &dyn TT| x.func(); - | - ^^^^^^^^ `x` escapes the closure body here - | | + | - - ^^^^^^^^ + | | | | + | | | `x` escapes the closure body here + | | | argument requires that `'1` must outlive `'static` + | | let's call the lifetime of this reference `'1` | `x` is a reference that is only valid in the closure body error: aborting due to previous error diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr b/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr index 7221759dbd4..e220cbf5559 100644 --- a/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr +++ b/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr @@ -2,10 +2,15 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/region-invariant-static-error-reporting.rs:15:9 | LL | fn unify<'a>(x: Option>, f: fn(Invariant<'a>)) { - | - `x` is a reference that is only valid in the function body + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | let bad = if x.is_some() { LL | x.unwrap() - | ^^^^^^^^^^ `x` escapes the function body here + | ^^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr index ed7b17c207c..83d6e13dc0a 100644 --- a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr +++ b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr @@ -2,12 +2,17 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:20:5 | LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) { - | - - `b` is a reference that is only valid in the function body - | | - | `a` declared here, outside of the function body + | -- -- - - `b` is a reference that is only valid in the function body + | | | | + | | | `a` declared here, outside of the function body + | | lifetime `'b` defined here + | lifetime `'a` defined here LL | // Here the value provided for 'y is 'b, and hence 'b:'a does not hold. LL | f.method(b); - | ^^^^^^^^^^^ `b` escapes the function body here + | ^^^^^^^^^^^ + | | + | `b` escapes the function body here + | argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr index 32a2de1e84d..a1ef32c5445 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr @@ -2,33 +2,53 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:9 | LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - | --- `val` is a reference that is only valid in the function body + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | val.use_self::() - | ^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here + | ^^^^^^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:9 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - | --- `val` is a reference that is only valid in the function body + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | val.use_self() - | ^^^^^^^^^^^^^^ `val` escapes the function body here + | ^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:88:9 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { - | --- `val` is a reference that is only valid in the function body + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | val.use_self() - | ^^^^^^^^^^^^^^ `val` escapes the function body here + | ^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - | --- `val` is a reference that is only valid in the function body + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | MyTrait::use_self(val) - | ^^^^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here + | ^^^^^^^^^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to 4 previous errors diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 0386d8be167..39498c99e64 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -14,7 +14,7 @@ use std::path::PathBuf; use rustc_span::edition::DEFAULT_EDITION; -use rustdoc::html::markdown::{ErrorCodes, IdMap, Markdown, Playground}; +use rustdoc::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground}; pub struct ErrorMetadata { pub description: Option, @@ -119,14 +119,15 @@ impl Formatter for HTMLFormatter { write!( output, "{}", - Markdown( - desc, - &[], - &mut id_map, - ErrorCodes::Yes, - DEFAULT_EDITION, - &Some(playground) - ) + Markdown { + content: desc, + links: &[], + ids: &mut id_map, + error_codes: ErrorCodes::Yes, + edition: DEFAULT_EDITION, + playground: &Some(playground), + heading_offset: HeadingOffset::H1, + } .into_string() )? }