mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-29 16:13:40 +00:00
Auto merge of #89608 - Manishearth:rollup-m7kd76f, r=Manishearth
Rollup of 12 pull requests Successful merges: - #87601 (Add functions to add unsigned and signed integers) - #88523 (Expand documentation for `FpCategory`.) - #89050 (refactor: VecDeques Drain fields to private) - #89245 (refactor: make VecDeque's IterMut fields module-private, not just crate-private) - #89324 (Rename `std:🧵:available_conccurrency` to `std:🧵:available_parallelism`) - #89329 (print-type-sizes: skip field printing for primitives) - #89501 (Note specific regions involved in 'borrowed data escapes' error) - #89506 (librustdoc: Use correct heading levels.) - #89528 (Fix suggestion to borrow when casting from pointer to reference) - #89531 (library std, libc dependency update) - #89588 (Add a test for generic_const_exprs) - #89591 (fix: alloc-optimisation is only for rust llvm) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
0eabf25b90
@ -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",
|
||||
]
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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!(
|
||||
|
@ -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<VecDeque<T, A>>,
|
||||
after_tail: usize,
|
||||
after_head: usize,
|
||||
iter: Iter<'a, T>,
|
||||
deque: NonNull<VecDeque<T, A>>,
|
||||
}
|
||||
|
||||
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<VecDeque<T, A>>,
|
||||
) -> Self {
|
||||
Drain { after_tail, after_head, iter, deque }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "collection_debug", since = "1.17.0")]
|
||||
|
@ -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,
|
||||
|
@ -1000,12 +1000,9 @@ impl<T, A: Allocator> VecDeque<T, A> {
|
||||
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<T, A: Allocator> VecDeque<T, A> {
|
||||
|
||||
// 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<T, A: Allocator> VecDeque<T, A> {
|
||||
// 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.
|
||||
|
@ -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)]
|
||||
|
@ -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<Self> {
|
||||
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<Self> {
|
||||
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
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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<Self> {
|
||||
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
|
||||
|
@ -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" }
|
||||
|
@ -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)
|
||||
|
@ -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)]
|
||||
|
@ -97,7 +97,7 @@ impl Thread {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn available_concurrency() -> io::Result<NonZeroUsize> {
|
||||
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,7 @@ impl Thread {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn available_concurrency() -> io::Result<NonZeroUsize> {
|
||||
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
|
@ -263,7 +263,7 @@ impl Drop for Thread {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn available_concurrency() -> io::Result<NonZeroUsize> {
|
||||
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(
|
||||
target_os = "android",
|
||||
|
@ -31,7 +31,7 @@ impl Thread {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn available_concurrency() -> io::Result<NonZeroUsize> {
|
||||
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ impl Thread {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn available_concurrency() -> io::Result<NonZeroUsize> {
|
||||
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ impl Thread {
|
||||
pub fn join(self) {}
|
||||
}
|
||||
|
||||
pub fn available_concurrency() -> io::Result<NonZeroUsize> {
|
||||
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ impl Thread {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn available_concurrency() -> io::Result<NonZeroUsize> {
|
||||
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
|
||||
let res = unsafe {
|
||||
let mut sysinfo: c::SYSTEM_INFO = crate::mem::zeroed();
|
||||
c::GetSystemInfo(&mut sysinfo);
|
||||
|
@ -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<NonZeroUsize> {
|
||||
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<NonZeroUsize> {
|
||||
imp::available_parallelism()
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
|
@ -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 })
|
||||
}
|
||||
|
@ -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<Playground>,
|
||||
);
|
||||
pub edition: Edition,
|
||||
pub playground: &'a Option<Playground>,
|
||||
/// Offset at which we render headings.
|
||||
/// E.g. if `heading_offset: HeadingOffset::H2`, then `# something` renders an `<h2>`.
|
||||
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<SpannedEvent<'a>>,
|
||||
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<Item = SpannedEvent<'a>>> 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!("</a></h{}>", 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<MarkdownLink> {
|
||||
// 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 {
|
||||
|
@ -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",
|
||||
"<h1 id=\"foo-bar\" class=\"section-header\"><a href=\"#foo-bar\">Foo bar</a></h1>",
|
||||
"<h2 id=\"foo-bar\" class=\"section-header\"><a href=\"#foo-bar\">Foo bar</a></h2>",
|
||||
);
|
||||
t(
|
||||
"## Foo-bar_baz qux",
|
||||
"<h2 id=\"foo-bar_baz-qux\" class=\"section-header\">\
|
||||
<a href=\"#foo-bar_baz-qux\">Foo-bar_baz qux</a></h2>",
|
||||
"<h3 id=\"foo-bar_baz-qux\" class=\"section-header\">\
|
||||
<a href=\"#foo-bar_baz-qux\">Foo-bar_baz qux</a></h3>",
|
||||
);
|
||||
t(
|
||||
"### **Foo** *bar* baz!?!& -_qux_-%",
|
||||
"<h3 id=\"foo-bar-baz--qux-\" class=\"section-header\">\
|
||||
"<h4 id=\"foo-bar-baz--qux-\" class=\"section-header\">\
|
||||
<a href=\"#foo-bar-baz--qux-\"><strong>Foo</strong> \
|
||||
<em>bar</em> baz!?!& -<em>qux</em>-%</a>\
|
||||
</h3>",
|
||||
</h4>",
|
||||
);
|
||||
t(
|
||||
"#### **Foo?** & \\*bar?!* _`baz`_ ❤ #qux",
|
||||
"<h4 id=\"foo--bar--baz--qux\" class=\"section-header\">\
|
||||
"<h5 id=\"foo--bar--baz--qux\" class=\"section-header\">\
|
||||
<a href=\"#foo--bar--baz--qux\"><strong>Foo?</strong> & *bar?!* \
|
||||
<em><code>baz</code></em> ❤ #qux</a>\
|
||||
</h4>",
|
||||
</h5>",
|
||||
);
|
||||
}
|
||||
|
||||
@ -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",
|
||||
"<h1 id=\"example\" class=\"section-header\"><a href=\"#example\">Example</a></h1>",
|
||||
"<h2 id=\"example\" class=\"section-header\"><a href=\"#example\">Example</a></h2>",
|
||||
);
|
||||
t(
|
||||
&mut map,
|
||||
"# Panics",
|
||||
"<h1 id=\"panics\" class=\"section-header\"><a href=\"#panics\">Panics</a></h1>",
|
||||
"<h2 id=\"panics\" class=\"section-header\"><a href=\"#panics\">Panics</a></h2>",
|
||||
);
|
||||
t(
|
||||
&mut map,
|
||||
"# Example",
|
||||
"<h1 id=\"example-1\" class=\"section-header\"><a href=\"#example-1\">Example</a></h1>",
|
||||
"<h2 id=\"example-1\" class=\"section-header\"><a href=\"#example-1\">Example</a></h2>",
|
||||
);
|
||||
t(
|
||||
&mut map,
|
||||
"# Main",
|
||||
"<h1 id=\"main-1\" class=\"section-header\"><a href=\"#main-1\">Main</a></h1>",
|
||||
"<h2 id=\"main-1\" class=\"section-header\"><a href=\"#main-1\">Main</a></h2>",
|
||||
);
|
||||
t(
|
||||
&mut map,
|
||||
"# Example",
|
||||
"<h1 id=\"example-2\" class=\"section-header\"><a href=\"#example-2\">Example</a></h1>",
|
||||
"<h2 id=\"example-2\" class=\"section-header\"><a href=\"#example-2\">Example</a></h2>",
|
||||
);
|
||||
t(
|
||||
&mut map,
|
||||
"# Panics",
|
||||
"<h1 id=\"panics-1\" class=\"section-header\"><a href=\"#panics-1\">Panics</a></h1>",
|
||||
"<h2 id=\"panics-1\" class=\"section-header\"><a href=\"#panics-1\">Panics</a></h2>",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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<String>);
|
||||
@ -470,32 +470,45 @@ fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<Strin
|
||||
))
|
||||
}
|
||||
|
||||
fn document(w: &mut Buffer, cx: &Context<'_>, 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<RenderedLink>) {
|
||||
fn render_markdown(
|
||||
w: &mut Buffer,
|
||||
cx: &Context<'_>,
|
||||
md_text: &str,
|
||||
links: Vec<RenderedLink>,
|
||||
heading_offset: HeadingOffset,
|
||||
) {
|
||||
let mut ids = cx.id_map.borrow_mut();
|
||||
write!(
|
||||
w,
|
||||
"<div class=\"docblock\">{}</div>",
|
||||
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_
|
||||
<span>Expand description</span>\
|
||||
</summary>",
|
||||
);
|
||||
render_markdown(w, cx, &s, item.links(cx));
|
||||
render_markdown(w, cx, &s, item.links(cx), heading_offset);
|
||||
w.write_str("</details>");
|
||||
} 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,
|
||||
"<div class=\"docblock\">{}</div>",
|
||||
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()
|
||||
);
|
||||
}
|
||||
|
@ -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 = "<div class=\"item-table\">";
|
||||
const ITEM_TABLE_CLOSE: &'static str = "</div>";
|
||||
@ -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::<Vec<usize>>();
|
||||
|
||||
@ -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, "<details class=\"rustdoc-toggle\" open><summary>");
|
||||
@ -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, "<span class=\"stab {stab}\"></span>", 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("</code>");
|
||||
render_stability_since(w, variant, it, cx.tcx());
|
||||
w.write_str("</div>");
|
||||
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).
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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<P: AsRef<Path>>(
|
||||
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!(
|
||||
|
@ -1,4 +1,5 @@
|
||||
//
|
||||
// no-system-llvm
|
||||
// min-llvm-version: 10.0.1
|
||||
// compile-flags: -O
|
||||
#![crate_type="lib"]
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// @has issue_42760/struct.NonGen.html
|
||||
// @has - '//h1' 'Example'
|
||||
// @has - '//h2' 'Example'
|
||||
|
||||
/// Item docs.
|
||||
///
|
||||
|
29
src/test/rustdoc/issue-89309-heading-levels.rs
Normal file
29
src/test/rustdoc/issue-89309-heading-levels.rs
Normal file
@ -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<usize, ()>;
|
||||
}
|
||||
|
||||
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<usize, ()> {
|
||||
Ok(1)
|
||||
}
|
||||
}
|
@ -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
|
||||
///
|
||||
|
@ -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!\";"
|
||||
|
@ -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
|
||||
|
||||
|
10
src/test/ui/cast/issue-89497.fixed
Normal file
10
src/test/ui/cast/issue-89497.fixed
Normal file
@ -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
|
||||
}
|
10
src/test/ui/cast/issue-89497.rs
Normal file
10
src/test/ui/cast/issue-89497.rs
Normal file
@ -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
|
||||
}
|
15
src/test/ui/cast/issue-89497.stderr
Normal file
15
src/test/ui/cast/issue-89497.stderr
Normal file
@ -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`.
|
@ -0,0 +1,29 @@
|
||||
// run-pass
|
||||
#![feature(generic_const_exprs)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Foo<const N: usize> {
|
||||
type Assoc: Default;
|
||||
}
|
||||
|
||||
impl Foo<0> for () {
|
||||
type Assoc = u32;
|
||||
}
|
||||
|
||||
impl Foo<3> for () {
|
||||
type Assoc = i64;
|
||||
}
|
||||
|
||||
fn foo<T, const N: usize>(_: 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);
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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<dyn Debug + '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 | 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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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<dyn Fn() + '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 | // 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<dyn Fn() + '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 | // 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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
26
src/test/ui/nll/issue-67007-escaping-data.rs
Normal file
26
src/test/ui/nll/issue-67007-escaping-data.rs
Normal file
@ -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() {}
|
21
src/test/ui/nll/issue-67007-escaping-data.stderr
Normal file
21
src/test/ui/nll/issue-67007-escaping-data.stderr
Normal file
@ -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`.
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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<dyn SomeTrait + 'a>) -> MyBox<dyn SomeTrait + 'a> {
|
||||
| -- `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
|
||||
|
||||
|
@ -11,5 +11,5 @@
|
||||
fn start(_: isize, _: *const *const u8) -> isize {
|
||||
let _x: Option<!> = None;
|
||||
let _y: Result<u32, !> = Ok(42);
|
||||
0
|
||||
let _z: Result<!, !> = loop {};
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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<Invariant<'a>>, 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
|
||||
|
||||
|
@ -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`
|
||||
|
||||
|
@ -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<T>) -> 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::<T>()
|
||||
| ^^^^^^^^^^^^^^^^^^^ `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
|
||||
|
||||
|
@ -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<String>,
|
||||
@ -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()
|
||||
)?
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user