Auto merge of #97632 - JohnTitor:rollup-d2ucrjw, r=JohnTitor
Rollup of 6 pull requests Successful merges: - #95594 (Additional `*mut [T]` methods) - #97130 (rustdoc: avoid including impl blocks with filled-in generics) - #97166 (Move conditions out of recover/report functions.) - #97605 (Mention filename in suggestion when it differs from primary span) - #97613 (rustdoc: Improve calculation of "Impls on Foreign Types") - #97626 (rename PointerAddress → PointerExposeAddress) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
e838059d66
@ -2147,7 +2147,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
|
||||
}
|
||||
}
|
||||
|
||||
CastKind::PointerAddress => {
|
||||
CastKind::PointerExposeAddress => {
|
||||
let ty_from = op.ty(body, tcx);
|
||||
let cast_ty_from = CastTy::from_ty(ty_from);
|
||||
let cast_ty_to = CastTy::from_ty(*ty);
|
||||
|
@ -607,7 +607,11 @@ fn codegen_stmt<'tcx>(
|
||||
let operand = codegen_operand(fx, operand);
|
||||
lval.write_cvalue(fx, operand.cast_pointer_to(to_layout));
|
||||
}
|
||||
Rvalue::Cast(CastKind::Misc | CastKind::PointerAddress, ref operand, to_ty) => {
|
||||
Rvalue::Cast(
|
||||
CastKind::Misc | CastKind::PointerExposeAddress,
|
||||
ref operand,
|
||||
to_ty,
|
||||
) => {
|
||||
let operand = codegen_operand(fx, operand);
|
||||
let from_ty = operand.layout().ty;
|
||||
let to_ty = fx.monomorphize(to_ty);
|
||||
|
@ -181,7 +181,7 @@ pub fn codegen_rvalue_operand(
|
||||
let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty));
|
||||
|
||||
let val = match *kind {
|
||||
mir::CastKind::PointerAddress => {
|
||||
mir::CastKind::PointerExposeAddress => {
|
||||
assert!(bx.cx().is_backend_immediate(cast));
|
||||
let llptr = operand.immediate();
|
||||
let llcast_ty = bx.cx().immediate_backend_type(cast);
|
||||
|
@ -31,9 +31,9 @@ pub fn cast(
|
||||
self.unsize_into(src, cast_ty, dest)?;
|
||||
}
|
||||
|
||||
PointerAddress => {
|
||||
PointerExposeAddress => {
|
||||
let src = self.read_immediate(src)?;
|
||||
let res = self.pointer_address_cast(&src, cast_ty)?;
|
||||
let res = self.pointer_expose_address_cast(&src, cast_ty)?;
|
||||
self.write_immediate(res, dest)?;
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@ pub fn misc_cast(
|
||||
Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
|
||||
}
|
||||
|
||||
pub fn pointer_address_cast(
|
||||
pub fn pointer_expose_address_cast(
|
||||
&mut self,
|
||||
src: &ImmTy<'tcx, M::PointerTag>,
|
||||
cast_ty: Ty<'tcx>,
|
||||
|
@ -542,7 +542,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
// in the type of any local, which also excludes casts).
|
||||
}
|
||||
|
||||
Rvalue::Cast(CastKind::PointerAddress, _, _) => {
|
||||
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
|
||||
self.check_op(ops::RawPtrToIntCast);
|
||||
}
|
||||
|
||||
|
@ -502,7 +502,7 @@ fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable>
|
||||
Rvalue::ThreadLocalRef(_) => return Err(Unpromotable),
|
||||
|
||||
// ptr-to-int casts are not possible in consts and thus not promotable
|
||||
Rvalue::Cast(CastKind::PointerAddress, _, _) => return Err(Unpromotable),
|
||||
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => return Err(Unpromotable),
|
||||
|
||||
// int-to-ptr casts are fine, they just use the integer value at pointer type.
|
||||
Rvalue::Cast(_, operand, _) => {
|
||||
|
@ -1715,6 +1715,7 @@ fn emit_message_default(
|
||||
|
||||
fn emit_suggestion_default(
|
||||
&mut self,
|
||||
span: &MultiSpan,
|
||||
suggestion: &CodeSuggestion,
|
||||
args: &FluentArgs<'_>,
|
||||
level: &Level,
|
||||
@ -1766,6 +1767,30 @@ enum DisplaySuggestion {
|
||||
None,
|
||||
}
|
||||
|
||||
if let Some(span) = span.primary_span() {
|
||||
// Compare the primary span of the diagnostic with the span of the suggestion
|
||||
// being emitted. If they belong to the same file, we don't *need* to show the
|
||||
// file name, saving in verbosity, but if it *isn't* we do need it, otherwise we're
|
||||
// telling users to make a change but not clarifying *where*.
|
||||
let loc = sm.lookup_char_pos(parts[0].span.lo());
|
||||
if loc.file.name != sm.span_to_filename(span) && loc.file.name.is_real() {
|
||||
buffer.puts(row_num - 1, 0, "--> ", Style::LineNumber);
|
||||
buffer.append(
|
||||
row_num - 1,
|
||||
&format!(
|
||||
"{}:{}:{}",
|
||||
sm.filename_for_diagnostics(&loc.file.name),
|
||||
sm.doctest_offset_line(&loc.file.name, loc.line),
|
||||
loc.col.0 + 1,
|
||||
),
|
||||
Style::LineAndColumn,
|
||||
);
|
||||
for _ in 0..max_line_num_len {
|
||||
buffer.prepend(row_num - 1, " ", Style::NoStyle);
|
||||
}
|
||||
row_num += 1;
|
||||
}
|
||||
}
|
||||
let show_code_change = if has_deletion && !is_multiline {
|
||||
DisplaySuggestion::Diff
|
||||
} else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim())
|
||||
@ -1787,7 +1812,7 @@ enum DisplaySuggestion {
|
||||
assert!(!file_lines.lines.is_empty() || parts[0].span.is_dummy());
|
||||
|
||||
let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
|
||||
draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
|
||||
draw_col_separator_no_space(&mut buffer, row_num - 1, max_line_num_len + 1);
|
||||
let mut lines = complete.lines();
|
||||
if lines.clone().next().is_none() {
|
||||
// Account for a suggestion to completely remove a line(s) with whitespace (#94192).
|
||||
@ -2046,9 +2071,13 @@ fn emit_messages_default(
|
||||
) {
|
||||
panic!("failed to emit error: {}", e);
|
||||
}
|
||||
} else if let Err(e) =
|
||||
self.emit_suggestion_default(sugg, args, &Level::Help, max_line_num_len)
|
||||
{
|
||||
} else if let Err(e) = self.emit_suggestion_default(
|
||||
span,
|
||||
sugg,
|
||||
args,
|
||||
&Level::Help,
|
||||
max_line_num_len,
|
||||
) {
|
||||
panic!("failed to emit error: {}", e);
|
||||
};
|
||||
}
|
||||
|
@ -2607,16 +2607,17 @@ pub enum Rvalue<'tcx> {
|
||||
impl<'tcx> Rvalue<'tcx> {
|
||||
#[inline]
|
||||
pub fn is_pointer_int_cast(&self) -> bool {
|
||||
matches!(self, Rvalue::Cast(CastKind::PointerAddress, _, _))
|
||||
matches!(self, Rvalue::Cast(CastKind::PointerExposeAddress, _, _))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
pub enum CastKind {
|
||||
Misc,
|
||||
/// A pointer to address cast. A cast between a pointer and an integer type,
|
||||
/// or between a function pointer and an integer type.
|
||||
PointerAddress,
|
||||
/// An exposing pointer to address cast. A cast between a pointer and an integer type, or
|
||||
/// between a function pointer and an integer type.
|
||||
/// See the docs on `expose_addr` for more details.
|
||||
PointerExposeAddress,
|
||||
Pointer(PointerCast),
|
||||
}
|
||||
|
||||
|
@ -194,7 +194,7 @@ pub(crate) fn as_rvalue(
|
||||
let cast_ty = CastTy::from_ty(expr.ty);
|
||||
let cast_kind = match (from_ty, cast_ty) {
|
||||
(Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
|
||||
CastKind::PointerAddress
|
||||
CastKind::PointerExposeAddress
|
||||
}
|
||||
(_, _) => CastKind::Misc,
|
||||
};
|
||||
|
@ -1,8 +1,7 @@
|
||||
use super::pat::Expected;
|
||||
use super::ty::{AllowPlus, RecoverQuestionMark};
|
||||
use super::{
|
||||
BlockMode, CommaRecoveryMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions,
|
||||
SemiColonMode, SeqSep, TokenExpectType, TokenType,
|
||||
BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep,
|
||||
TokenExpectType, TokenType,
|
||||
};
|
||||
|
||||
use crate::lexer::UnmatchedBrace;
|
||||
@ -1233,26 +1232,14 @@ fn consume_fn_args(&mut self) -> Result<(), ()> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn maybe_report_ambiguous_plus(
|
||||
&mut self,
|
||||
allow_plus: AllowPlus,
|
||||
impl_dyn_multi: bool,
|
||||
ty: &Ty,
|
||||
) {
|
||||
if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi {
|
||||
pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) {
|
||||
if impl_dyn_multi {
|
||||
self.sess.emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(&ty), span: ty.span });
|
||||
}
|
||||
}
|
||||
|
||||
/// Swift lets users write `Ty?` to mean `Option<Ty>`. Parse the construct and recover from it.
|
||||
pub(super) fn maybe_recover_from_question_mark(
|
||||
&mut self,
|
||||
ty: P<Ty>,
|
||||
recover_question_mark: RecoverQuestionMark,
|
||||
) -> P<Ty> {
|
||||
if let RecoverQuestionMark::No = recover_question_mark {
|
||||
return ty;
|
||||
}
|
||||
pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P<Ty>) -> P<Ty> {
|
||||
if self.token == token::Question {
|
||||
self.bump();
|
||||
self.struct_span_err(self.prev_token.span, "invalid `?` in type")
|
||||
@ -1272,13 +1259,9 @@ pub(super) fn maybe_recover_from_question_mark(
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn maybe_recover_from_bad_type_plus(
|
||||
&mut self,
|
||||
allow_plus: AllowPlus,
|
||||
ty: &Ty,
|
||||
) -> PResult<'a, ()> {
|
||||
pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> {
|
||||
// Do not add `+` to expected tokens.
|
||||
if matches!(allow_plus, AllowPlus::No) || !self.token.is_like_plus() {
|
||||
if !self.token.is_like_plus() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -1444,10 +1427,9 @@ fn inc_dec_standalone_suggest(
|
||||
pub(super) fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
|
||||
&mut self,
|
||||
base: P<T>,
|
||||
allow_recovery: bool,
|
||||
) -> PResult<'a, P<T>> {
|
||||
// Do not add `::` to expected tokens.
|
||||
if allow_recovery && self.token == token::ModSep {
|
||||
if self.token == token::ModSep {
|
||||
if let Some(ty) = base.to_ty() {
|
||||
return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
|
||||
}
|
||||
@ -1593,7 +1575,7 @@ pub(super) fn recover_incorrect_await_syntax(
|
||||
_ => ExprKind::Await(expr),
|
||||
};
|
||||
let expr = self.mk_expr(lo.to(sp), kind, attrs);
|
||||
self.maybe_recover_from_bad_qpath(expr, true)
|
||||
self.maybe_recover_from_bad_qpath(expr)
|
||||
}
|
||||
|
||||
fn recover_await_macro(&mut self) -> PResult<'a, (Span, P<Expr>, bool)> {
|
||||
@ -2457,10 +2439,9 @@ pub(super) fn incorrect_move_async_order_found(
|
||||
pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
|
||||
&mut self,
|
||||
mut first_pat: P<Pat>,
|
||||
ra: RecoverColon,
|
||||
expected: Expected,
|
||||
) -> P<Pat> {
|
||||
if RecoverColon::Yes != ra || token::Colon != self.token.kind {
|
||||
if token::Colon != self.token.kind {
|
||||
return first_pat;
|
||||
}
|
||||
if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
|
||||
@ -2594,10 +2575,9 @@ pub(crate) fn maybe_recover_unexpected_block_label(&mut self) -> bool {
|
||||
pub(crate) fn maybe_recover_unexpected_comma(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
rc: RecoverComma,
|
||||
rt: CommaRecoveryMode,
|
||||
) -> PResult<'a, ()> {
|
||||
if rc == RecoverComma::No || self.token != token::Comma {
|
||||
if self.token != token::Comma {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -1417,7 +1417,7 @@ fn parse_lit_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
match self.parse_opt_lit() {
|
||||
Some(literal) => {
|
||||
let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal), attrs);
|
||||
self.maybe_recover_from_bad_qpath(expr, true)
|
||||
self.maybe_recover_from_bad_qpath(expr)
|
||||
}
|
||||
None => self.try_macro_suggestion(),
|
||||
}
|
||||
@ -1444,7 +1444,7 @@ fn parse_tuple_parens_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
ExprKind::Tup(es)
|
||||
};
|
||||
let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
|
||||
self.maybe_recover_from_bad_qpath(expr, true)
|
||||
self.maybe_recover_from_bad_qpath(expr)
|
||||
}
|
||||
|
||||
fn parse_array_or_repeat_expr(
|
||||
@ -1481,7 +1481,7 @@ fn parse_array_or_repeat_expr(
|
||||
}
|
||||
};
|
||||
let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
|
||||
self.maybe_recover_from_bad_qpath(expr, true)
|
||||
self.maybe_recover_from_bad_qpath(expr)
|
||||
}
|
||||
|
||||
fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
@ -1519,7 +1519,7 @@ fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
};
|
||||
|
||||
let expr = self.mk_expr(lo.to(hi), kind, attrs);
|
||||
self.maybe_recover_from_bad_qpath(expr, true)
|
||||
self.maybe_recover_from_bad_qpath(expr)
|
||||
}
|
||||
|
||||
/// Parse `'label: $expr`. The label is already parsed.
|
||||
@ -1604,7 +1604,7 @@ fn parse_return_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
let lo = self.prev_token.span;
|
||||
let kind = ExprKind::Ret(self.parse_expr_opt()?);
|
||||
let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
|
||||
self.maybe_recover_from_bad_qpath(expr, true)
|
||||
self.maybe_recover_from_bad_qpath(expr)
|
||||
}
|
||||
|
||||
/// Parse `"do" "yeet" expr?`.
|
||||
@ -1619,7 +1619,7 @@ fn parse_yeet_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
let span = lo.to(self.prev_token.span);
|
||||
self.sess.gated_spans.gate(sym::yeet_expr, span);
|
||||
let expr = self.mk_expr(span, kind, attrs);
|
||||
self.maybe_recover_from_bad_qpath(expr, true)
|
||||
self.maybe_recover_from_bad_qpath(expr)
|
||||
}
|
||||
|
||||
/// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
|
||||
@ -1679,7 +1679,7 @@ fn parse_break_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
None
|
||||
};
|
||||
let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind), attrs);
|
||||
self.maybe_recover_from_bad_qpath(expr, true)
|
||||
self.maybe_recover_from_bad_qpath(expr)
|
||||
}
|
||||
|
||||
/// Parse `"yield" expr?`.
|
||||
@ -1689,7 +1689,7 @@ fn parse_yield_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||
let span = lo.to(self.prev_token.span);
|
||||
self.sess.gated_spans.gate(sym::generators, span);
|
||||
let expr = self.mk_expr(span, kind, attrs);
|
||||
self.maybe_recover_from_bad_qpath(expr, true)
|
||||
self.maybe_recover_from_bad_qpath(expr)
|
||||
}
|
||||
|
||||
/// Returns a string literal if the next token is a string literal.
|
||||
|
@ -100,8 +100,10 @@ fn parse_pat_allow_top_alt_inner(
|
||||
};
|
||||
|
||||
// Parse the first pattern (`p_0`).
|
||||
let first_pat = self.parse_pat_no_top_alt(expected)?;
|
||||
self.maybe_recover_unexpected_comma(first_pat.span, rc, rt)?;
|
||||
let mut first_pat = self.parse_pat_no_top_alt(expected)?;
|
||||
if rc == RecoverComma::Yes {
|
||||
self.maybe_recover_unexpected_comma(first_pat.span, rt)?;
|
||||
}
|
||||
|
||||
// If the next token is not a `|`,
|
||||
// this is not an or-pattern and we should exit here.
|
||||
@ -111,7 +113,9 @@ fn parse_pat_allow_top_alt_inner(
|
||||
// This complicated procedure is done purely for diagnostics UX.
|
||||
|
||||
// Check if the user wrote `foo:bar` instead of `foo::bar`.
|
||||
let first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, ra, expected);
|
||||
if ra == RecoverColon::Yes {
|
||||
first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, expected);
|
||||
}
|
||||
|
||||
if let Some(leading_vert_span) = leading_vert_span {
|
||||
// If there was a leading vert, treat this as an or-pattern. This improves
|
||||
@ -139,7 +143,9 @@ fn parse_pat_allow_top_alt_inner(
|
||||
err.span_label(lo, WHILE_PARSING_OR_MSG);
|
||||
err
|
||||
})?;
|
||||
self.maybe_recover_unexpected_comma(pat.span, rc, rt)?;
|
||||
if rc == RecoverComma::Yes {
|
||||
self.maybe_recover_unexpected_comma(pat.span, rt)?;
|
||||
}
|
||||
pats.push(pat);
|
||||
}
|
||||
let or_pattern_span = lo.to(self.prev_token.span);
|
||||
@ -408,7 +414,7 @@ fn parse_pat_with_range_pat(
|
||||
};
|
||||
|
||||
let pat = self.mk_pat(lo.to(self.prev_token.span), pat);
|
||||
let pat = self.maybe_recover_from_bad_qpath(pat, true)?;
|
||||
let pat = self.maybe_recover_from_bad_qpath(pat)?;
|
||||
let pat = self.recover_intersection_pat(pat)?;
|
||||
|
||||
if !allow_range_pat {
|
||||
|
@ -180,7 +180,7 @@ fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResu
|
||||
} else {
|
||||
// Since none of the above applied, this is an expression statement macro.
|
||||
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new());
|
||||
let e = self.maybe_recover_from_bad_qpath(e, true)?;
|
||||
let e = self.maybe_recover_from_bad_qpath(e)?;
|
||||
let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
|
||||
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
|
||||
StmtKind::Expr(e)
|
||||
|
@ -312,13 +312,18 @@ fn parse_ty_common(
|
||||
};
|
||||
|
||||
let span = lo.to(self.prev_token.span);
|
||||
let ty = self.mk_ty(span, kind);
|
||||
let mut ty = self.mk_ty(span, kind);
|
||||
|
||||
// Try to recover from use of `+` with incorrect priority.
|
||||
self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty);
|
||||
self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
|
||||
let ty = self.maybe_recover_from_question_mark(ty, recover_question_mark);
|
||||
self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)
|
||||
if matches!(allow_plus, AllowPlus::Yes) {
|
||||
self.maybe_recover_from_bad_type_plus(&ty)?;
|
||||
} else {
|
||||
self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty);
|
||||
}
|
||||
if let RecoverQuestionMark::Yes = recover_question_mark {
|
||||
ty = self.maybe_recover_from_question_mark(ty);
|
||||
}
|
||||
if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
|
||||
}
|
||||
|
||||
/// Parses either:
|
||||
|
@ -1622,6 +1622,122 @@ pub const fn len(self) -> usize {
|
||||
metadata(self)
|
||||
}
|
||||
|
||||
/// Returns `true` if the raw slice has a length of 0.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_ptr_len)]
|
||||
///
|
||||
/// let mut a = [1, 2, 3];
|
||||
/// let ptr = &mut a as *mut [_];
|
||||
/// assert!(!ptr.is_empty());
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
#[unstable(feature = "slice_ptr_len", issue = "71146")]
|
||||
#[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
|
||||
pub const fn is_empty(self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Divides one mutable raw slice into two at an index.
|
||||
///
|
||||
/// The first will contain all indices from `[0, mid)` (excluding
|
||||
/// the index `mid` itself) and the second will contain all
|
||||
/// indices from `[mid, len)` (excluding the index `len` itself).
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `mid > len`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `mid` must be [in-bounds] of the underlying [allocated object].
|
||||
/// Which means `self` must be dereferenceable and span a single allocation
|
||||
/// that is at least `mid * size_of::<T>()` bytes long. Not upholding these
|
||||
/// requirements is *[undefined behavior]* even if the resulting pointers are not used.
|
||||
///
|
||||
/// Since `len` being in-bounds it is not a safety invariant of `*mut [T]` the
|
||||
/// safety requirements of this method are the same as for [`split_at_mut_unchecked`].
|
||||
/// The explicit bounds check is only as useful as `len` is correct.
|
||||
///
|
||||
/// [`split_at_mut_unchecked`]: #method.split_at_mut_unchecked
|
||||
/// [in-bounds]: #method.add
|
||||
/// [allocated object]: crate::ptr#allocated-object
|
||||
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(raw_slice_split)]
|
||||
/// #![feature(slice_ptr_get)]
|
||||
///
|
||||
/// let mut v = [1, 0, 3, 0, 5, 6];
|
||||
/// let ptr = &mut v as *mut [_];
|
||||
/// unsafe {
|
||||
/// let (left, right) = ptr.split_at_mut(2);
|
||||
/// assert_eq!(&*left, [1, 0]);
|
||||
/// assert_eq!(&*right, [3, 0, 5, 6]);
|
||||
/// }
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
#[track_caller]
|
||||
#[unstable(feature = "raw_slice_split", issue = "95595")]
|
||||
pub unsafe fn split_at_mut(self, mid: usize) -> (*mut [T], *mut [T]) {
|
||||
assert!(mid <= self.len());
|
||||
// SAFETY: The assert above is only a safety-net as long as `self.len()` is correct
|
||||
// The actual safety requirements of this function are the same as for `split_at_mut_unchecked`
|
||||
unsafe { self.split_at_mut_unchecked(mid) }
|
||||
}
|
||||
|
||||
/// Divides one mutable raw slice into two at an index, without doing bounds checking.
|
||||
///
|
||||
/// The first will contain all indices from `[0, mid)` (excluding
|
||||
/// the index `mid` itself) and the second will contain all
|
||||
/// indices from `[mid, len)` (excluding the index `len` itself).
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `mid` must be [in-bounds] of the underlying [allocated object].
|
||||
/// Which means `self` must be dereferenceable and span a single allocation
|
||||
/// that is at least `mid * size_of::<T>()` bytes long. Not upholding these
|
||||
/// requirements is *[undefined behavior]* even if the resulting pointers are not used.
|
||||
///
|
||||
/// [in-bounds]: #method.add
|
||||
/// [out-of-bounds index]: #method.add
|
||||
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(raw_slice_split)]
|
||||
///
|
||||
/// let mut v = [1, 0, 3, 0, 5, 6];
|
||||
/// // scoped to restrict the lifetime of the borrows
|
||||
/// unsafe {
|
||||
/// let ptr = &mut v as *mut [_];
|
||||
/// let (left, right) = ptr.split_at_mut_unchecked(2);
|
||||
/// assert_eq!(&*left, [1, 0]);
|
||||
/// assert_eq!(&*right, [3, 0, 5, 6]);
|
||||
/// (&mut *left)[1] = 2;
|
||||
/// (&mut *right)[1] = 4;
|
||||
/// }
|
||||
/// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
#[unstable(feature = "raw_slice_split", issue = "95595")]
|
||||
pub unsafe fn split_at_mut_unchecked(self, mid: usize) -> (*mut [T], *mut [T]) {
|
||||
let len = self.len();
|
||||
let ptr = self.as_mut_ptr();
|
||||
|
||||
// SAFETY: Caller must pass a valid pointer and an index that is in-bounds.
|
||||
let tail = unsafe { ptr.add(mid) };
|
||||
(
|
||||
crate::ptr::slice_from_raw_parts_mut(ptr, mid),
|
||||
crate::ptr::slice_from_raw_parts_mut(tail, len - mid),
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the slice's buffer.
|
||||
///
|
||||
/// This is equivalent to casting `self` to `*mut T`, but more type-safe.
|
||||
@ -1645,9 +1761,10 @@ pub const fn as_mut_ptr(self) -> *mut T {
|
||||
/// Returns a raw pointer to an element or subslice, without doing bounds
|
||||
/// checking.
|
||||
///
|
||||
/// Calling this method with an out-of-bounds index or when `self` is not dereferenceable
|
||||
/// Calling this method with an [out-of-bounds index] or when `self` is not dereferenceable
|
||||
/// is *[undefined behavior]* even if the resulting pointer is not used.
|
||||
///
|
||||
/// [out-of-bounds index]: #method.add
|
||||
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -7,6 +7,7 @@
|
||||
pub(crate) use renderer::{run_format, FormatRenderer};
|
||||
|
||||
use crate::clean::{self, ItemId};
|
||||
use cache::Cache;
|
||||
|
||||
/// Specifies whether rendering directly implemented trait items or ones from a certain Deref
|
||||
/// impl.
|
||||
@ -60,4 +61,28 @@ pub(crate) fn def_id(&self) -> DefId {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if this is an implementation on a "local" type, meaning:
|
||||
// the type is in the current crate, or the type and the trait are both
|
||||
// re-exported by the current crate.
|
||||
pub(crate) fn is_on_local_type(&self, cache: &Cache) -> bool {
|
||||
let for_type = &self.inner_impl().for_;
|
||||
if let Some(for_type_did) = for_type.def_id(cache) {
|
||||
// The "for" type is local if it's in the paths for the current crate.
|
||||
if cache.paths.contains_key(&for_type_did) {
|
||||
return true;
|
||||
}
|
||||
if let Some(trait_did) = self.trait_did() {
|
||||
// The "for" type and the trait are from the same crate. That could
|
||||
// be different from the current crate, for instance when both were
|
||||
// re-exported from some other crate. But they are local with respect to
|
||||
// each other.
|
||||
if for_type_did.krate == trait_did.krate {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -2285,9 +2285,7 @@ fn print_sidebar_section(
|
||||
if let Some(implementors) = cache.implementors.get(&it.item_id.expect_def_id()) {
|
||||
let mut res = implementors
|
||||
.iter()
|
||||
.filter(|i| {
|
||||
i.inner_impl().for_.def_id(cache).map_or(false, |d| !cache.paths.contains_key(&d))
|
||||
})
|
||||
.filter(|i| !i.is_on_local_type(cache))
|
||||
.filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
@ -822,9 +822,8 @@ fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::
|
||||
}
|
||||
}
|
||||
|
||||
let (local, foreign) = implementors.iter().partition::<Vec<_>, _>(|i| {
|
||||
i.inner_impl().for_.def_id(cache).map_or(true, |d| cache.paths.contains_key(&d))
|
||||
});
|
||||
let (local, foreign) =
|
||||
implementors.iter().partition::<Vec<_>, _>(|i| i.is_on_local_type(cache));
|
||||
|
||||
let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
|
||||
local.iter().partition(|i| i.inner_impl().kind.is_auto());
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::DefIdTree;
|
||||
use rustc_middle::ty::{self, DefIdTree};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
pub(crate) const COLLECT_TRAIT_IMPLS: Pass = Pass {
|
||||
@ -81,8 +81,35 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
|
||||
// Do not calculate blanket impl list for docs that are not going to be rendered.
|
||||
// While the `impl` blocks themselves are only in `libcore`, the module with `doc`
|
||||
// attached is directly included in `libstd` as well.
|
||||
let tcx = cx.tcx;
|
||||
if did.is_local() {
|
||||
for def_id in prim.impls(cx.tcx) {
|
||||
for def_id in prim.impls(tcx).filter(|def_id| {
|
||||
// Avoid including impl blocks with filled-in generics.
|
||||
// https://github.com/rust-lang/rust/issues/94937
|
||||
//
|
||||
// FIXME(notriddle): https://github.com/rust-lang/rust/issues/97129
|
||||
//
|
||||
// This tactic of using inherent impl blocks for getting
|
||||
// auto traits and blanket impls is a hack. What we really
|
||||
// want is to check if `[T]` impls `Send`, which has
|
||||
// nothing to do with the inherent impl.
|
||||
//
|
||||
// Rustdoc currently uses these `impl` block as a source of
|
||||
// the `Ty`, as well as the `ParamEnv`, `SubstsRef`, and
|
||||
// `Generics`. To avoid relying on the `impl` block, these
|
||||
// things would need to be created from wholecloth, in a
|
||||
// form that is valid for use in type inference.
|
||||
let ty = tcx.type_of(def_id);
|
||||
match ty.kind() {
|
||||
ty::Slice(ty)
|
||||
| ty::Ref(_, ty, _)
|
||||
| ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
|
||||
matches!(ty.kind(), ty::Param(..))
|
||||
}
|
||||
ty::Tuple(tys) => tys.iter().all(|ty| matches!(ty.kind(), ty::Param(..))),
|
||||
_ => true,
|
||||
}
|
||||
}) {
|
||||
let impls = get_auto_trait_and_blanket_impls(cx, def_id);
|
||||
new_items_external.extend(impls.filter(|i| cx.inlined.insert(i.item_id)));
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
// + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
|
||||
// + literal: Const { ty: &i32, val: Unevaluated(FOO, [], None) }
|
||||
_2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
|
||||
_1 = move _2 as usize (PointerAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
|
||||
_1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
|
||||
StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39
|
||||
StorageDead(_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:39: 7:40
|
||||
StorageLive(_4); // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:5: 8:12
|
||||
|
@ -17,7 +17,7 @@
|
||||
// mir::Constant
|
||||
// + span: $DIR/reify_fn_ptr.rs:4:13: 4:17
|
||||
// + literal: Const { ty: fn() {main}, val: Value(Scalar(<ZST>)) }
|
||||
_2 = move _3 as usize (PointerAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26
|
||||
_2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26
|
||||
StorageDead(_3); // scope 0 at $DIR/reify_fn_ptr.rs:4:25: 4:26
|
||||
_1 = move _2 as *const fn() (Misc); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41
|
||||
StorageDead(_2); // scope 0 at $DIR/reify_fn_ptr.rs:4:40: 4:41
|
||||
|
@ -19,12 +19,12 @@
|
||||
StorageLive(_2); // scope 0 at $DIR/provenance_soundness.rs:8:9: 8:11
|
||||
StorageLive(_3); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15
|
||||
_3 = _1; // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15
|
||||
_2 = move _3 as usize (PointerAddress); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:24
|
||||
_2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:24
|
||||
StorageDead(_3); // scope 0 at $DIR/provenance_soundness.rs:8:23: 8:24
|
||||
StorageLive(_4); // scope 1 at $DIR/provenance_soundness.rs:9:9: 9:11
|
||||
StorageLive(_5); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:15
|
||||
_5 = _1; // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:15
|
||||
_4 = move _5 as isize (PointerAddress); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:24
|
||||
_4 = move _5 as isize (PointerExposeAddress); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:24
|
||||
StorageDead(_5); // scope 1 at $DIR/provenance_soundness.rs:9:23: 9:24
|
||||
_0 = const (); // scope 0 at $DIR/provenance_soundness.rs:7:32: 10:2
|
||||
StorageDead(_4); // scope 1 at $DIR/provenance_soundness.rs:10:1: 10:2
|
||||
|
@ -13,5 +13,5 @@
|
||||
// @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//h3[@class="code-header in-band"]' 'impl Deref for EndianSlice'
|
||||
pub use realcore::Deref;
|
||||
|
||||
// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//h3[@class="code-header in-band"]' 'impl Join for Foo'
|
||||
// @has foo/trait.Join.html '//*[@id="impl-Join"]//h3[@class="code-header in-band"]' 'impl Join for Foo'
|
||||
pub use realcore::Join;
|
||||
|
14
src/test/rustdoc/primitive-slice-auto-trait.rs
Normal file
14
src/test/rustdoc/primitive-slice-auto-trait.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// compile-flags: --crate-type lib --edition 2018
|
||||
|
||||
#![crate_name = "foo"]
|
||||
#![feature(rustdoc_internals)]
|
||||
|
||||
// @has foo/primitive.slice.html '//a[@class="primitive"]' 'slice'
|
||||
// @has - '//span[@class="in-band"]' 'Primitive Type slice'
|
||||
// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
|
||||
// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
|
||||
// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T] where T: Send'
|
||||
// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T] where T: Sync'
|
||||
#[doc(primitive = "slice")]
|
||||
/// this is a test!
|
||||
mod slice_prim {}
|
@ -5,6 +5,7 @@ LL | impl Bar for Baz { }
|
||||
| ^^^ type aliases cannot be used as traits
|
||||
|
|
||||
help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias
|
||||
--> $DIR/two_files_data.rs:5:1
|
||||
|
|
||||
LL | trait Bar = dyn Foo;
|
||||
|
|
||||
|
@ -6,6 +6,7 @@ LL | If<{ FRAC <= 32 }>: True,
|
||||
|
|
||||
= note: the crate this constant originates from uses `#![feature(generic_const_exprs)]`
|
||||
help: consider enabling this feature
|
||||
--> $DIR/issue-94287.rs:1:1
|
||||
|
|
||||
LL | #![feature(generic_const_exprs)]
|
||||
|
|
||||
|
@ -6,6 +6,7 @@ LL | produces_async! {}
|
||||
|
|
||||
= note: this error originates in the macro `produces_async` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: escape `async` to use it as an identifier
|
||||
--> $DIR/auxiliary/edition-kw-macro-2018.rs:7:19
|
||||
|
|
||||
LL | () => (pub fn r#async() {})
|
||||
| ++
|
||||
|
@ -6,6 +6,7 @@ LL | produces_async! {}
|
||||
|
|
||||
= note: this error originates in the macro `produces_async` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: escape `async` to use it as an identifier
|
||||
--> $DIR/auxiliary/edition-kw-macro-2018.rs:7:19
|
||||
|
|
||||
LL | () => (pub fn r#async() {})
|
||||
| ++
|
||||
|
@ -9,6 +9,7 @@ LL | assert_eq!(a, 0);
|
||||
|
|
||||
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: you might have forgotten to call this function
|
||||
--> $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
|
|
||||
LL | if !(*left_val() == *right_val) {
|
||||
| ++
|
||||
|
@ -46,6 +46,7 @@ LL | bar.pow(2);
|
||||
| ^^^
|
||||
|
|
||||
help: you must specify a type for this binding, like `i32`
|
||||
--> $DIR/auxiliary/macro-in-other-crate.rs:3:29
|
||||
|
|
||||
LL | ($ident:ident) => { let $ident: i32 = 42; }
|
||||
| ~~~~~~~~~~~
|
||||
|
@ -125,7 +125,7 @@ fn check_rvalue<'tcx>(
|
||||
Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
|
||||
check_place(tcx, *place, span, body)
|
||||
},
|
||||
Rvalue::Cast(CastKind::PointerAddress, _, _) => {
|
||||
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
|
||||
Err((span, "casting pointers to ints is unstable in const fn".into()))
|
||||
},
|
||||
Rvalue::Cast(CastKind::Misc, operand, _) => {
|
||||
|
Loading…
Reference in New Issue
Block a user