mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 15:32:06 +00:00
Auto merge of #88596 - m-ou-se:rollup-cidzt4v, r=m-ou-se
Rollup of 12 pull requests Successful merges: - #88177 (Stabilize std::os::unix::fs::chroot) - #88505 (Use `unwrap_unchecked` where possible) - #88512 (Upgrade array_into_iter lint to include Deref-to-array types.) - #88532 (Remove single use variables) - #88543 (Improve closure dummy capture suggestion in macros.) - #88560 (`fmt::Formatter::pad`: don't call chars().count() more than one time) - #88565 (Add regression test for issue 83190) - #88567 (Remove redundant `Span` in `QueryJobInfo`) - #88573 (rustdoc: Don't panic on ambiguous inherent associated types) - #88582 (Implement #88581) - #88589 (Correct doc comments inside `use_expr_visitor.rs`) - #88592 (Fix ICE in const check) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
b834c4c1ba
@ -74,39 +74,45 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// As this is a method call expression, we have at least one
|
||||
// argument.
|
||||
// As this is a method call expression, we have at least one argument.
|
||||
let receiver_arg = &args[0];
|
||||
let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
|
||||
let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
|
||||
|
||||
// Peel all `Box<_>` layers. We have to special case `Box` here as
|
||||
// `Box` is the only thing that values can be moved out of via
|
||||
// method call. `Box::new([1]).into_iter()` should trigger this
|
||||
// lint.
|
||||
let mut recv_ty = cx.typeck_results().expr_ty(receiver_arg);
|
||||
let mut num_box_derefs = 0;
|
||||
while recv_ty.is_box() {
|
||||
num_box_derefs += 1;
|
||||
recv_ty = recv_ty.boxed_ty();
|
||||
let target = match adjustments.last() {
|
||||
Some(Adjustment { kind: Adjust::Borrow(_), target }) => target,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let types =
|
||||
std::iter::once(receiver_ty).chain(adjustments.iter().map(|adj| adj.target));
|
||||
|
||||
let mut found_array = false;
|
||||
|
||||
for ty in types {
|
||||
match ty.kind() {
|
||||
// If we run into a &[T; N] or &[T] first, there's nothing to warn about.
|
||||
// It'll resolve to the reference version.
|
||||
ty::Ref(_, inner_ty, _) if inner_ty.is_array() => return,
|
||||
ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => return,
|
||||
// Found an actual array type without matching a &[T; N] first.
|
||||
// This is the problematic case.
|
||||
ty::Array(..) => {
|
||||
found_array = true;
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we found an array after peeling the boxes.
|
||||
if !matches!(recv_ty.kind(), ty::Array(..)) {
|
||||
if !found_array {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure that there is an autoref coercion at the expected
|
||||
// position. The first `num_box_derefs` adjustments are the derefs
|
||||
// of the box.
|
||||
match cx.typeck_results().expr_adjustments(receiver_arg).get(num_box_derefs) {
|
||||
Some(Adjustment { kind: Adjust::Borrow(_), .. }) => {}
|
||||
_ => return,
|
||||
}
|
||||
|
||||
// Emit lint diagnostic.
|
||||
let target = match *cx.typeck_results().expr_ty_adjusted(receiver_arg).kind() {
|
||||
let target = match *target.kind() {
|
||||
ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]",
|
||||
ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]",
|
||||
|
||||
// We know the original first argument type is an array type,
|
||||
// we know that the first adjustment was an autoref coercion
|
||||
// and we know that `IntoIterator` is the trait involved. The
|
||||
@ -135,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
} else if receiver_ty.is_array() {
|
||||
diag.multipart_suggestion(
|
||||
"or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
|
||||
vec![
|
||||
|
@ -411,8 +411,7 @@ impl<'tcx> Body<'tcx> {
|
||||
/// Returns an iterator over all function arguments.
|
||||
#[inline]
|
||||
pub fn args_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator {
|
||||
let arg_count = self.arg_count;
|
||||
(1..arg_count + 1).map(Local::new)
|
||||
(1..self.arg_count + 1).map(Local::new)
|
||||
}
|
||||
|
||||
/// Returns an iterator over all user-defined variables and compiler-generated temporaries (all
|
||||
@ -421,9 +420,7 @@ impl<'tcx> Body<'tcx> {
|
||||
pub fn vars_and_temps_iter(
|
||||
&self,
|
||||
) -> impl DoubleEndedIterator<Item = Local> + ExactSizeIterator {
|
||||
let arg_count = self.arg_count;
|
||||
let local_count = self.local_decls.len();
|
||||
(arg_count + 1..local_count).map(Local::new)
|
||||
(self.arg_count + 1..self.local_decls.len()).map(Local::new)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -9,7 +9,7 @@ use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
|
||||
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::cast::CastTy;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
|
||||
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
|
||||
use rustc_span::{sym, Span, Symbol};
|
||||
@ -793,7 +793,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
|
||||
|
||||
let fn_ty = func.ty(body, tcx);
|
||||
|
||||
let (mut callee, substs) = match *fn_ty.kind() {
|
||||
let (mut callee, mut substs) = match *fn_ty.kind() {
|
||||
ty::FnDef(def_id, substs) => (def_id, substs),
|
||||
|
||||
ty::FnPtr(_) => {
|
||||
@ -846,29 +846,31 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
|
||||
.iter()
|
||||
.find(|did| tcx.item_name(**did) == callee_name)
|
||||
{
|
||||
// using internal substs is ok here, since this is only
|
||||
// used for the `resolve` call below
|
||||
substs = InternalSubsts::identity_for_item(tcx, did);
|
||||
callee = did;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if !tcx.is_const_fn_raw(callee) {
|
||||
// At this point, it is only legal when the caller is marked with
|
||||
// #[default_method_body_is_const], and the callee is in the same
|
||||
// trait.
|
||||
let callee_trait = tcx.trait_of_item(callee);
|
||||
if callee_trait.is_some() {
|
||||
if tcx.has_attr(caller, sym::default_method_body_is_const) {
|
||||
if tcx.trait_of_item(caller) == callee_trait {
|
||||
nonconst_call_permission = true;
|
||||
}
|
||||
_ if !tcx.is_const_fn_raw(callee) => {
|
||||
// At this point, it is only legal when the caller is marked with
|
||||
// #[default_method_body_is_const], and the callee is in the same
|
||||
// trait.
|
||||
let callee_trait = tcx.trait_of_item(callee);
|
||||
if callee_trait.is_some() {
|
||||
if tcx.has_attr(caller, sym::default_method_body_is_const) {
|
||||
if tcx.trait_of_item(caller) == callee_trait {
|
||||
nonconst_call_permission = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !nonconst_call_permission {
|
||||
self.check_op(ops::FnCallNonConst);
|
||||
return;
|
||||
}
|
||||
if !nonconst_call_permission {
|
||||
self.check_op(ops::FnCallNonConst);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Resolve a trait method call to its concrete implementation, which may be in a
|
||||
|
@ -61,7 +61,7 @@ where
|
||||
}
|
||||
|
||||
fn query(self, map: &QueryMap<D>) -> QueryStackFrame {
|
||||
map.get(&self).unwrap().info.query.clone()
|
||||
map.get(&self).unwrap().query.clone()
|
||||
}
|
||||
|
||||
#[cfg(parallel_compiler)]
|
||||
@ -81,7 +81,7 @@ where
|
||||
}
|
||||
|
||||
pub struct QueryJobInfo<D> {
|
||||
pub info: QueryInfo,
|
||||
pub query: QueryStackFrame,
|
||||
pub job: QueryJob<D>,
|
||||
}
|
||||
|
||||
@ -155,7 +155,7 @@ where
|
||||
|
||||
while let Some(job) = current_job {
|
||||
let info = query_map.get(&job).unwrap();
|
||||
cycle.push(info.info.clone());
|
||||
cycle.push(QueryInfo { span: info.job.span, query: info.query.clone() });
|
||||
|
||||
if job == *self {
|
||||
cycle.reverse();
|
||||
@ -170,7 +170,7 @@ where
|
||||
.job
|
||||
.parent
|
||||
.as_ref()
|
||||
.map(|parent| (info.info.span, parent.query(&query_map)));
|
||||
.map(|parent| (info.job.span, parent.query(&query_map)));
|
||||
return CycleError { usage, cycle };
|
||||
}
|
||||
|
||||
@ -649,13 +649,10 @@ pub fn print_query_stack<CTX: QueryContext>(
|
||||
};
|
||||
let mut diag = Diagnostic::new(
|
||||
Level::FailureNote,
|
||||
&format!(
|
||||
"#{} [{}] {}",
|
||||
i, query_info.info.query.name, query_info.info.query.description
|
||||
),
|
||||
&format!("#{} [{}] {}", i, query_info.query.name, query_info.query.description),
|
||||
);
|
||||
diag.span =
|
||||
tcx.dep_context().sess().source_map().guess_head_span(query_info.info.span).into();
|
||||
tcx.dep_context().sess().source_map().guess_head_span(query_info.job.span).into();
|
||||
handler.force_print_diagnostic(diag);
|
||||
|
||||
current_query = query_info.job.parent;
|
||||
|
@ -130,8 +130,8 @@ where
|
||||
for (k, v) in shard.active.iter() {
|
||||
if let QueryResult::Started(ref job) = *v {
|
||||
let id = QueryJobId::new(job.id, shard_id, kind);
|
||||
let info = QueryInfo { span: job.span, query: make_query(tcx, k.clone()) };
|
||||
jobs.insert(id, QueryJobInfo { info, job: job.clone() });
|
||||
let query = make_query(tcx, k.clone());
|
||||
jobs.insert(id, QueryJobInfo { query, job: job.clone() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ use rustc_middle::ty::{
|
||||
};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::sym;
|
||||
use rustc_span::{BytePos, MultiSpan, Pos, Span, Symbol, DUMMY_SP};
|
||||
use rustc_span::{BytePos, MultiSpan, Pos, Span, Symbol};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
|
||||
use rustc_data_structures::stable_map::FxHashMap;
|
||||
@ -680,15 +680,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
migrated_variables_concat
|
||||
);
|
||||
|
||||
// If the body was entirely expanded from a macro
|
||||
// invocation, i.e. the body is not contained inside the
|
||||
// closure span, then we walk up the expansion until we
|
||||
// find the span before the expansion.
|
||||
let closure_body_span = self.tcx.hir().span(body_id.hir_id)
|
||||
.find_ancestor_inside(closure_span)
|
||||
.unwrap_or(DUMMY_SP);
|
||||
let mut closure_body_span = {
|
||||
// If the body was entirely expanded from a macro
|
||||
// invocation, i.e. the body is not contained inside the
|
||||
// closure span, then we walk up the expansion until we
|
||||
// find the span before the expansion.
|
||||
let s = self.tcx.hir().span(body_id.hir_id);
|
||||
s.find_ancestor_inside(closure_span).unwrap_or(s)
|
||||
};
|
||||
|
||||
if let Ok(mut s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) {
|
||||
if s.starts_with('$') {
|
||||
// Looks like a macro fragment. Try to find the real block.
|
||||
if let Some(hir::Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Block(block, ..), ..
|
||||
})) = self.tcx.hir().find(body_id.hir_id) {
|
||||
// If the body is a block (with `{..}`), we use the span of that block.
|
||||
// E.g. with a `|| $body` expanded from a `m!({ .. })`, we use `{ .. }`, and not `$body`.
|
||||
// Since we know it's a block, we know we can insert the `let _ = ..` without
|
||||
// breaking the macro syntax.
|
||||
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(block.span) {
|
||||
closure_body_span = block.span;
|
||||
s = snippet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) {
|
||||
let mut lines = s.lines();
|
||||
let line1 = lines.next().unwrap_or_default();
|
||||
|
||||
|
@ -21,29 +21,26 @@ use std::iter;
|
||||
|
||||
use crate::mem_categorization as mc;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// The Delegate trait
|
||||
|
||||
/// This trait defines the callbacks you can expect to receive when
|
||||
/// employing the ExprUseVisitor.
|
||||
pub trait Delegate<'tcx> {
|
||||
// The value found at `place` is moved, depending
|
||||
// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
|
||||
//
|
||||
// Use of a `Copy` type in a ByValue context is considered a use
|
||||
// by `ImmBorrow` and `borrow` is called instead. This is because
|
||||
// a shared borrow is the "minimum access" that would be needed
|
||||
// to perform a copy.
|
||||
//
|
||||
//
|
||||
// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
|
||||
// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
|
||||
// id will be the id of the expression `expr` but the place itself will have
|
||||
// the id of the binding in the pattern `pat`.
|
||||
/// The value found at `place` is moved, depending
|
||||
/// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
|
||||
///
|
||||
/// Use of a `Copy` type in a ByValue context is considered a use
|
||||
/// by `ImmBorrow` and `borrow` is called instead. This is because
|
||||
/// a shared borrow is the "minimum access" that would be needed
|
||||
/// to perform a copy.
|
||||
///
|
||||
///
|
||||
/// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
|
||||
/// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
|
||||
/// id will be the id of the expression `expr` but the place itself will have
|
||||
/// the id of the binding in the pattern `pat`.
|
||||
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
|
||||
|
||||
// The value found at `place` is being borrowed with kind `bk`.
|
||||
// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
|
||||
/// The value found at `place` is being borrowed with kind `bk`.
|
||||
/// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
|
||||
fn borrow(
|
||||
&mut self,
|
||||
place_with_id: &PlaceWithHirId<'tcx>,
|
||||
@ -51,44 +48,47 @@ pub trait Delegate<'tcx> {
|
||||
bk: ty::BorrowKind,
|
||||
);
|
||||
|
||||
// The path at `assignee_place` is being assigned to.
|
||||
// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
|
||||
/// The path at `assignee_place` is being assigned to.
|
||||
/// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
|
||||
fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
|
||||
|
||||
// The `place` should be a fake read because of specified `cause`.
|
||||
/// The `place` should be a fake read because of specified `cause`.
|
||||
fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
enum ConsumeMode {
|
||||
Copy, // reference to x where x has a type that copies
|
||||
Move, // reference to x where x has a type that moves
|
||||
/// reference to x where x has a type that copies
|
||||
Copy,
|
||||
/// reference to x where x has a type that moves
|
||||
Move,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum MutateMode {
|
||||
Init,
|
||||
JustWrite, // x = y
|
||||
WriteAndRead, // x += y
|
||||
/// Example: `x = y`
|
||||
JustWrite,
|
||||
/// Example: `x += y`
|
||||
WriteAndRead,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// The ExprUseVisitor type
|
||||
//
|
||||
// This is the code that actually walks the tree.
|
||||
/// The ExprUseVisitor type
|
||||
///
|
||||
/// This is the code that actually walks the tree.
|
||||
pub struct ExprUseVisitor<'a, 'tcx> {
|
||||
mc: mc::MemCategorizationContext<'a, 'tcx>,
|
||||
body_owner: LocalDefId,
|
||||
delegate: &'a mut dyn Delegate<'tcx>,
|
||||
}
|
||||
|
||||
// If the MC results in an error, it's because the type check
|
||||
// failed (or will fail, when the error is uncovered and reported
|
||||
// during writeback). In this case, we just ignore this part of the
|
||||
// code.
|
||||
//
|
||||
// Note that this macro appears similar to try!(), but, unlike try!(),
|
||||
// it does not propagate the error.
|
||||
/// If the MC results in an error, it's because the type check
|
||||
/// failed (or will fail, when the error is uncovered and reported
|
||||
/// during writeback). In this case, we just ignore this part of the
|
||||
/// code.
|
||||
///
|
||||
/// Note that this macro appears similar to try!(), but, unlike try!(),
|
||||
/// it does not propagate the error.
|
||||
macro_rules! return_if_err {
|
||||
($inp: expr) => {
|
||||
match $inp {
|
||||
@ -537,9 +537,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
self.walk_expr(with_expr);
|
||||
}
|
||||
|
||||
// Invoke the appropriate delegate calls for anything that gets
|
||||
// consumed or borrowed as part of the automatic adjustment
|
||||
// process.
|
||||
/// Invoke the appropriate delegate calls for anything that gets
|
||||
/// consumed or borrowed as part of the automatic adjustment
|
||||
/// process.
|
||||
fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) {
|
||||
let adjustments = self.mc.typeck_results.expr_adjustments(expr);
|
||||
let mut place_with_id = return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
||||
|
@ -300,7 +300,10 @@ impl<T> LinkedList<T> {
|
||||
let tail = self.tail.take();
|
||||
let len = mem::replace(&mut self.len, 0);
|
||||
if let Some(head) = head {
|
||||
let tail = tail.unwrap_or_else(|| unsafe { core::hint::unreachable_unchecked() });
|
||||
// SAFETY: In a LinkedList, either both the head and tail are None because
|
||||
// the list is empty, or both head and tail are Some because the list is populated.
|
||||
// Since we have verified the head is Some, we are sure the tail is Some too.
|
||||
let tail = unsafe { tail.unwrap_unchecked() };
|
||||
Some((head, tail, len))
|
||||
} else {
|
||||
None
|
||||
|
@ -459,11 +459,8 @@ where
|
||||
debug_assert!(N <= iter.size_hint().1.unwrap_or(usize::MAX));
|
||||
debug_assert!(N <= iter.size_hint().0);
|
||||
|
||||
match collect_into_array(iter) {
|
||||
Some(array) => array,
|
||||
// SAFETY: covered by the function contract.
|
||||
None => unsafe { crate::hint::unreachable_unchecked() },
|
||||
}
|
||||
// SAFETY: covered by the function contract.
|
||||
unsafe { collect_into_array(iter).unwrap_unchecked() }
|
||||
}
|
||||
|
||||
/// Pulls `N` items from `iter` and returns them as an array. If the iterator
|
||||
|
@ -402,7 +402,7 @@ impl<'a> Arguments<'a> {
|
||||
|
||||
if self.args.is_empty() {
|
||||
pieces_length
|
||||
} else if self.pieces[0] == "" && pieces_length < 16 {
|
||||
} else if !self.pieces.is_empty() && self.pieces[0].is_empty() && pieces_length < 16 {
|
||||
// If the format string starts with an argument,
|
||||
// don't preallocate anything, unless length
|
||||
// of pieces is significant.
|
||||
@ -1163,7 +1163,7 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
|
||||
}
|
||||
// SAFETY: arg and args.args come from the same Arguments,
|
||||
// which guarantees the indexes are always within bounds.
|
||||
unsafe { run(&mut formatter, arg, &args.args) }?;
|
||||
unsafe { run(&mut formatter, arg, args.args) }?;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
@ -1409,7 +1409,7 @@ impl<'a> Formatter<'a> {
|
||||
// we know that it can't panic. Use `get` + `unwrap_or` to avoid
|
||||
// `unsafe` and otherwise don't emit any panic-related code
|
||||
// here.
|
||||
s.get(..i).unwrap_or(&s)
|
||||
s.get(..i).unwrap_or(s)
|
||||
} else {
|
||||
&s
|
||||
}
|
||||
@ -1421,16 +1421,21 @@ impl<'a> Formatter<'a> {
|
||||
// If we're under the maximum length, and there's no minimum length
|
||||
// requirements, then we can just emit the string
|
||||
None => self.buf.write_str(s),
|
||||
// If we're under the maximum width, check if we're over the minimum
|
||||
// width, if so it's as easy as just emitting the string.
|
||||
Some(width) if s.chars().count() >= width => self.buf.write_str(s),
|
||||
// If we're under both the maximum and the minimum width, then fill
|
||||
// up the minimum width with the specified string + some alignment.
|
||||
Some(width) => {
|
||||
let align = rt::v1::Alignment::Left;
|
||||
let post_padding = self.padding(width - s.chars().count(), align)?;
|
||||
self.buf.write_str(s)?;
|
||||
post_padding.write(self.buf)
|
||||
let chars_count = s.chars().count();
|
||||
// If we're under the maximum width, check if we're over the minimum
|
||||
// width, if so it's as easy as just emitting the string.
|
||||
if chars_count >= width {
|
||||
self.buf.write_str(s)
|
||||
}
|
||||
// If we're under both the maximum and the minimum width, then fill
|
||||
// up the minimum width with the specified string + some alignment.
|
||||
else {
|
||||
let align = rt::v1::Alignment::Left;
|
||||
let post_padding = self.padding(width - chars_count, align)?;
|
||||
self.buf.write_str(s)?;
|
||||
post_padding.write(self.buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1834,6 +1834,173 @@ macro_rules! int_impl {
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the quotient of `self` and `rhs`, rounding the result towards negative infinity.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if `rhs` is 0 or the division results in overflow.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(int_roundings)]
|
||||
#[doc = concat!("let a: ", stringify!($SelfT)," = 8;")]
|
||||
/// let b = 3;
|
||||
///
|
||||
/// assert_eq!(a.div_floor(b), 2);
|
||||
/// assert_eq!(a.div_floor(-b), -3);
|
||||
/// assert_eq!((-a).div_floor(b), -3);
|
||||
/// assert_eq!((-a).div_floor(-b), 2);
|
||||
/// ```
|
||||
#[unstable(feature = "int_roundings", issue = "88581")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
pub const fn div_floor(self, rhs: Self) -> Self {
|
||||
let d = self / rhs;
|
||||
let r = self % rhs;
|
||||
if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
|
||||
d - 1
|
||||
} else {
|
||||
d
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the quotient of `self` and `rhs`, rounding the result towards positive infinity.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if `rhs` is 0 or the division results in overflow.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(int_roundings)]
|
||||
#[doc = concat!("let a: ", stringify!($SelfT)," = 8;")]
|
||||
/// let b = 3;
|
||||
///
|
||||
/// assert_eq!(a.div_ceil(b), 3);
|
||||
/// assert_eq!(a.div_ceil(-b), -2);
|
||||
/// assert_eq!((-a).div_ceil(b), -2);
|
||||
/// assert_eq!((-a).div_ceil(-b), 3);
|
||||
/// ```
|
||||
#[unstable(feature = "int_roundings", issue = "88581")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
pub const fn div_ceil(self, rhs: Self) -> Self {
|
||||
let d = self / rhs;
|
||||
let r = self % rhs;
|
||||
if (r > 0 && rhs > 0) || (r < 0 && rhs < 0) {
|
||||
d + 1
|
||||
} else {
|
||||
d
|
||||
}
|
||||
}
|
||||
|
||||
/// If `rhs` is positive, calculates the smallest value greater than or
|
||||
/// equal to `self` that is a multiple of `rhs`. If `rhs` is negative,
|
||||
/// calculates the largest value less than or equal to `self` that is a
|
||||
/// multiple of `rhs`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if `rhs` is 0 or the operation results in overflow.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(int_roundings)]
|
||||
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")]
|
||||
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")]
|
||||
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(-8), 16);")]
|
||||
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(-8), 16);")]
|
||||
#[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(8), -16);")]
|
||||
#[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(8), -16);")]
|
||||
#[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(-8), -16);")]
|
||||
#[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(-8), -24);")]
|
||||
/// ```
|
||||
#[unstable(feature = "int_roundings", issue = "88581")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
pub const fn next_multiple_of(self, rhs: Self) -> Self {
|
||||
// This would otherwise fail when calculating `r` when self == T::MIN.
|
||||
if rhs == -1 {
|
||||
return self;
|
||||
}
|
||||
|
||||
let r = self % rhs;
|
||||
let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
|
||||
r + rhs
|
||||
} else {
|
||||
r
|
||||
};
|
||||
|
||||
if m == 0 {
|
||||
self
|
||||
} else {
|
||||
self + (rhs - m)
|
||||
}
|
||||
}
|
||||
|
||||
/// If `rhs` is positive, calculates the smallest value greater than or
|
||||
/// equal to `self` that is a multiple of `rhs`. If `rhs` is negative,
|
||||
/// calculates the largest value less than or equal to `self` that is a
|
||||
/// multiple of `rhs`. Returns `None` if `rhs` is zero or the operation
|
||||
/// would result in overflow.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(int_roundings)]
|
||||
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(16));")]
|
||||
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(24));")]
|
||||
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(-8), Some(16));")]
|
||||
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".checked_next_multiple_of(-8), Some(16));")]
|
||||
#[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").checked_next_multiple_of(8), Some(-16));")]
|
||||
#[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").checked_next_multiple_of(8), Some(-16));")]
|
||||
#[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").checked_next_multiple_of(-8), Some(-16));")]
|
||||
#[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").checked_next_multiple_of(-8), Some(-24));")]
|
||||
#[doc = concat!("assert_eq!(1_", stringify!($SelfT), ".checked_next_multiple_of(0), None);")]
|
||||
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_next_multiple_of(2), None);")]
|
||||
/// ```
|
||||
#[unstable(feature = "int_roundings", issue = "88581")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
|
||||
// This would otherwise fail when calculating `r` when self == T::MIN.
|
||||
if rhs == -1 {
|
||||
return Some(self);
|
||||
}
|
||||
|
||||
let r = try_opt!(self.checked_rem(rhs));
|
||||
let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) {
|
||||
try_opt!(r.checked_add(rhs))
|
||||
} else {
|
||||
r
|
||||
};
|
||||
|
||||
if m == 0 {
|
||||
Some(self)
|
||||
} else {
|
||||
self.checked_add(try_opt!(rhs.checked_sub(m)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the logarithm of the number with respect to an arbitrary base.
|
||||
///
|
||||
/// This method might not be optimized owing to implementation details;
|
||||
|
@ -1848,6 +1848,110 @@ macro_rules! uint_impl {
|
||||
self % rhs
|
||||
}
|
||||
|
||||
/// Calculates the quotient of `self` and `rhs`, rounding the result towards negative infinity.
|
||||
///
|
||||
/// This is the same as performing `self / rhs` for all unsigned integers.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if `rhs` is 0.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(int_roundings)]
|
||||
#[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_floor(4), 1);")]
|
||||
/// ```
|
||||
#[unstable(feature = "int_roundings", issue = "88581")]
|
||||
#[inline(always)]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
pub const fn div_floor(self, rhs: Self) -> Self {
|
||||
self / rhs
|
||||
}
|
||||
|
||||
/// Calculates the quotient of `self` and `rhs`, rounding the result towards positive infinity.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if `rhs` is 0.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(int_roundings)]
|
||||
#[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_ceil(4), 2);")]
|
||||
/// ```
|
||||
#[unstable(feature = "int_roundings", issue = "88581")]
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
pub const fn div_ceil(self, rhs: Self) -> Self {
|
||||
let d = self / rhs;
|
||||
let r = self % rhs;
|
||||
if r > 0 && rhs > 0 {
|
||||
d + 1
|
||||
} else {
|
||||
d
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the smallest value greater than or equal to `self` that
|
||||
/// is a multiple of `rhs`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if `rhs` is 0 or the operation results in overflow.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(int_roundings)]
|
||||
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")]
|
||||
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")]
|
||||
/// ```
|
||||
#[unstable(feature = "int_roundings", issue = "88581")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
pub const fn next_multiple_of(self, rhs: Self) -> Self {
|
||||
match self % rhs {
|
||||
0 => self,
|
||||
r => self + (rhs - r)
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the smallest value greater than or equal to `self` that
|
||||
/// is a multiple of `rhs`. If `rhs` is negative,
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(int_roundings)]
|
||||
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(16));")]
|
||||
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(24));")]
|
||||
#[doc = concat!("assert_eq!(1_", stringify!($SelfT), ".checked_next_multiple_of(0), None);")]
|
||||
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_next_multiple_of(2), None);")]
|
||||
/// ```
|
||||
#[unstable(feature = "int_roundings", issue = "88581")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
|
||||
match try_opt!(self.checked_rem(rhs)) {
|
||||
0 => Some(self),
|
||||
r => self.checked_add(try_opt!(rhs.checked_sub(r)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if and only if `self == 2^k` for some `k`.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -1198,11 +1198,8 @@ impl<T> Option<T> {
|
||||
pub fn insert(&mut self, value: T) -> &mut T {
|
||||
*self = Some(value);
|
||||
|
||||
match self {
|
||||
Some(v) => v,
|
||||
// SAFETY: the code above just filled the option
|
||||
None => unsafe { hint::unreachable_unchecked() },
|
||||
}
|
||||
// SAFETY: the code above just filled the option
|
||||
unsafe { self.as_mut().unwrap_unchecked() }
|
||||
}
|
||||
|
||||
/// Inserts `value` into the option if it is [`None`], then
|
||||
|
@ -64,6 +64,7 @@
|
||||
#![feature(unsized_tuple_coercion)]
|
||||
#![feature(const_option)]
|
||||
#![feature(integer_atomics)]
|
||||
#![feature(int_roundings)]
|
||||
#![feature(slice_group_by)]
|
||||
#![feature(trusted_random_access)]
|
||||
#![feature(unsize)]
|
||||
|
@ -289,6 +289,55 @@ macro_rules! int_module {
|
||||
assert_eq!(r.saturating_pow(3), -8 as $T);
|
||||
assert_eq!(r.saturating_pow(0), 1 as $T);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_div_floor() {
|
||||
let a: $T = 8;
|
||||
let b = 3;
|
||||
assert_eq!(a.div_floor(b), 2);
|
||||
assert_eq!(a.div_floor(-b), -3);
|
||||
assert_eq!((-a).div_floor(b), -3);
|
||||
assert_eq!((-a).div_floor(-b), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_div_ceil() {
|
||||
let a: $T = 8;
|
||||
let b = 3;
|
||||
assert_eq!(a.div_ceil(b), 3);
|
||||
assert_eq!(a.div_ceil(-b), -2);
|
||||
assert_eq!((-a).div_ceil(b), -2);
|
||||
assert_eq!((-a).div_ceil(-b), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_next_multiple_of() {
|
||||
assert_eq!((16 as $T).next_multiple_of(8), 16);
|
||||
assert_eq!((23 as $T).next_multiple_of(8), 24);
|
||||
assert_eq!((16 as $T).next_multiple_of(-8), 16);
|
||||
assert_eq!((23 as $T).next_multiple_of(-8), 16);
|
||||
assert_eq!((-16 as $T).next_multiple_of(8), -16);
|
||||
assert_eq!((-23 as $T).next_multiple_of(8), -16);
|
||||
assert_eq!((-16 as $T).next_multiple_of(-8), -16);
|
||||
assert_eq!((-23 as $T).next_multiple_of(-8), -24);
|
||||
assert_eq!(MIN.next_multiple_of(-1), MIN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_checked_next_multiple_of() {
|
||||
assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16));
|
||||
assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24));
|
||||
assert_eq!((16 as $T).checked_next_multiple_of(-8), Some(16));
|
||||
assert_eq!((23 as $T).checked_next_multiple_of(-8), Some(16));
|
||||
assert_eq!((-16 as $T).checked_next_multiple_of(8), Some(-16));
|
||||
assert_eq!((-23 as $T).checked_next_multiple_of(8), Some(-16));
|
||||
assert_eq!((-16 as $T).checked_next_multiple_of(-8), Some(-16));
|
||||
assert_eq!((-23 as $T).checked_next_multiple_of(-8), Some(-24));
|
||||
assert_eq!((1 as $T).checked_next_multiple_of(0), None);
|
||||
assert_eq!(MAX.checked_next_multiple_of(2), None);
|
||||
assert_eq!(MIN.checked_next_multiple_of(-3), None);
|
||||
assert_eq!(MIN.checked_next_multiple_of(-1), Some(MIN));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -205,6 +205,31 @@ macro_rules! uint_module {
|
||||
assert_eq!(r.overflowing_pow(2), (1 as $T, true));
|
||||
assert_eq!(r.saturating_pow(2), MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_div_floor() {
|
||||
assert_eq!((8 as $T).div_floor(3), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_div_ceil() {
|
||||
assert_eq!((8 as $T).div_ceil(3), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_next_multiple_of() {
|
||||
assert_eq!((16 as $T).next_multiple_of(8), 16);
|
||||
assert_eq!((23 as $T).next_multiple_of(8), 24);
|
||||
assert_eq!(MAX.next_multiple_of(1), MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_checked_next_multiple_of() {
|
||||
assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16));
|
||||
assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24));
|
||||
assert_eq!((1 as $T).checked_next_multiple_of(0), None);
|
||||
assert_eq!(MAX.checked_next_multiple_of(2), None);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -934,7 +934,6 @@ impl DirBuilderExt for fs::DirBuilder {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(unix_chroot)]
|
||||
/// use std::os::unix::fs;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
@ -944,7 +943,7 @@ impl DirBuilderExt for fs::DirBuilder {
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "unix_chroot", issue = "84715")]
|
||||
#[stable(feature = "unix_chroot", since = "1.56.0")]
|
||||
#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
|
||||
pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
|
||||
sys::fs::chroot(dir.as_ref())
|
||||
|
@ -1311,10 +1311,11 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
|
||||
}
|
||||
hir::QPath::TypeRelative(ref qself, ref segment) => {
|
||||
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
|
||||
let res = if let ty::Projection(proj) = ty.kind() {
|
||||
Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id)
|
||||
} else {
|
||||
Res::Err
|
||||
let res = match ty.kind() {
|
||||
ty::Projection(proj) => Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id),
|
||||
// Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s.
|
||||
ty::Error(_) => return Type::Infer,
|
||||
_ => bug!("clean: expected associated type, found `{:?}`", ty),
|
||||
};
|
||||
let trait_path = hir::Path { span, res, segments: &[] }.clean(cx);
|
||||
Type::QPath {
|
||||
@ -1379,6 +1380,7 @@ impl Clean<Type> for hir::Ty<'_> {
|
||||
DynTrait(bounds, lifetime)
|
||||
}
|
||||
TyKind::BareFn(ref barefn) => BareFunction(Box::new(barefn.clean(cx))),
|
||||
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
|
||||
TyKind::Infer | TyKind::Err => Infer,
|
||||
TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind),
|
||||
}
|
||||
|
17
src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs
Normal file
17
src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// This test ensures that rustdoc does not panic on inherented associated types
|
||||
// that are referred to without fully-qualified syntax.
|
||||
|
||||
#![feature(inherent_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
pub struct Struct;
|
||||
|
||||
impl Struct {
|
||||
pub type AssocTy = usize;
|
||||
pub const AssocConst: Self::AssocTy = 42;
|
||||
//~^ ERROR ambiguous associated type
|
||||
//~| HELP use fully-qualified syntax
|
||||
// FIXME: for some reason, the error is shown twice with rustdoc but only once with rustc
|
||||
//~| ERROR ambiguous associated type
|
||||
//~| HELP use fully-qualified syntax
|
||||
}
|
15
src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr
Normal file
15
src/test/rustdoc-ui/ambiguous-inherent-assoc-ty.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error[E0223]: ambiguous associated type
|
||||
--> $DIR/ambiguous-inherent-assoc-ty.rs:11:27
|
||||
|
|
||||
LL | pub const AssocConst: Self::AssocTy = 42;
|
||||
| ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Struct as Trait>::AssocTy`
|
||||
|
||||
error[E0223]: ambiguous associated type
|
||||
--> $DIR/ambiguous-inherent-assoc-ty.rs:11:27
|
||||
|
|
||||
LL | pub const AssocConst: Self::AssocTy = 42;
|
||||
| ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Struct as Trait>::AssocTy`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0223`.
|
@ -0,0 +1,25 @@
|
||||
// run-rustfix
|
||||
// edition:2018
|
||||
// check-pass
|
||||
#![warn(rust_2021_compatibility)]
|
||||
|
||||
macro_rules! m {
|
||||
(@ $body:expr) => {{
|
||||
let f = || $body;
|
||||
//~^ WARNING: drop order
|
||||
f();
|
||||
}};
|
||||
($body:block) => {{
|
||||
m!(@ $body);
|
||||
}};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = (1.to_string(), 2.to_string());
|
||||
m!({
|
||||
let _ = &a;
|
||||
//~^ HELP: add a dummy
|
||||
let x = a.0;
|
||||
println!("{}", x);
|
||||
});
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// run-rustfix
|
||||
// edition:2018
|
||||
// check-pass
|
||||
#![warn(rust_2021_compatibility)]
|
||||
|
||||
macro_rules! m {
|
||||
(@ $body:expr) => {{
|
||||
let f = || $body;
|
||||
//~^ WARNING: drop order
|
||||
f();
|
||||
}};
|
||||
($body:block) => {{
|
||||
m!(@ $body);
|
||||
}};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = (1.to_string(), 2.to_string());
|
||||
m!({
|
||||
//~^ HELP: add a dummy
|
||||
let x = a.0;
|
||||
println!("{}", x);
|
||||
});
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
warning: changes to closure capture in Rust 2021 will affect drop order
|
||||
--> $DIR/closure-body-macro-fragment.rs:8:17
|
||||
|
|
||||
LL | let f = || $body;
|
||||
| _________________^
|
||||
LL | |
|
||||
LL | | f();
|
||||
LL | | }};
|
||||
| | - in Rust 2018, `a` is dropped here, but in Rust 2021, only `a.0` will be dropped here as part of the closure
|
||||
LL | | ($body:block) => {{
|
||||
LL | | m!(@ $body);
|
||||
| |__________________^
|
||||
...
|
||||
LL | / m!({
|
||||
LL | |
|
||||
LL | | let x = a.0;
|
||||
| | --- in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0`
|
||||
LL | | println!("{}", x);
|
||||
LL | | });
|
||||
| |_______- in this macro invocation
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/closure-body-macro-fragment.rs:4:9
|
||||
|
|
||||
LL | #![warn(rust_2021_compatibility)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: `#[warn(rust_2021_incompatible_closure_captures)]` implied by `#[warn(rust_2021_compatibility)]`
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
|
||||
= note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: add a dummy let to cause `a` to be fully captured
|
||||
|
|
||||
LL ~ m!({
|
||||
LL + let _ = &a;
|
||||
|
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
26
src/test/ui/const-generics/const_trait_fn-issue-88433.rs
Normal file
26
src/test/ui/const-generics/const_trait_fn-issue-88433.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// build-pass
|
||||
|
||||
#![feature(const_trait_impl)]
|
||||
|
||||
trait Func<T> {
|
||||
type Output;
|
||||
|
||||
fn call_once(self, arg: T) -> Self::Output;
|
||||
}
|
||||
|
||||
|
||||
struct Closure;
|
||||
|
||||
impl const Func<&usize> for Closure {
|
||||
type Output = usize;
|
||||
|
||||
fn call_once(self, arg: &usize) -> Self::Output {
|
||||
*arg
|
||||
}
|
||||
}
|
||||
|
||||
enum Bug<T = [(); Closure.call_once(&0) ]> {
|
||||
V(T),
|
||||
}
|
||||
|
||||
fn main() {}
|
49
src/test/ui/issues/issue-83190.rs
Normal file
49
src/test/ui/issues/issue-83190.rs
Normal file
@ -0,0 +1,49 @@
|
||||
// check-pass
|
||||
|
||||
// Regression test for issue #83190, triggering an ICE in borrowck.
|
||||
|
||||
pub trait Any {}
|
||||
impl<T> Any for T {}
|
||||
|
||||
pub trait StreamOnce {
|
||||
type Range;
|
||||
}
|
||||
|
||||
pub trait Parser<Input>: Sized {
|
||||
type Output;
|
||||
type PartialState;
|
||||
fn map(self) -> Map<Self> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Map<P>(P);
|
||||
impl<I, P: Parser<I, Output = ()>> Parser<I> for Map<P> {
|
||||
type Output = ();
|
||||
type PartialState = P::PartialState;
|
||||
}
|
||||
|
||||
struct TakeWhile1<Input>(Input);
|
||||
impl<I: StreamOnce> Parser<I> for TakeWhile1<I> {
|
||||
type Output = I::Range;
|
||||
type PartialState = ();
|
||||
}
|
||||
impl<I> TakeWhile1<I> {
|
||||
fn new() -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, A: Parser<I>> Parser<I> for (A,) {
|
||||
type Output = ();
|
||||
type PartialState = Map<A::Output>;
|
||||
}
|
||||
|
||||
pub fn metric_stream_parser<'a, I>() -> impl Parser<I, Output = (), PartialState = impl Any + 'a>
|
||||
where
|
||||
I: StreamOnce<Range = &'a [()]>,
|
||||
{
|
||||
(TakeWhile1::new(),).map()
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -19,9 +19,12 @@ fn main() {
|
||||
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
|
||||
//~| WARNING this changes meaning
|
||||
|
||||
// The `array_into_iter` lint doesn't cover other wrappers that deref to an array.
|
||||
let _: Iter<'_, i32> = Rc::new(array).into_iter();
|
||||
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
|
||||
//~| WARNING this changes meaning
|
||||
let _: Iter<'_, i32> = Array(array).into_iter();
|
||||
//~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
|
||||
//~| WARNING this changes meaning
|
||||
|
||||
// But you can always use the trait method explicitly as an array.
|
||||
let _: IntoIter<i32, 10> = IntoIterator::into_iter(array);
|
||||
|
@ -20,21 +20,31 @@ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (du
|
||||
--> $DIR/into-iter-on-arrays-2018.rs:18:44
|
||||
|
|
||||
LL | let _: Iter<'_, i32> = Box::new(array).into_iter();
|
||||
| ^^^^^^^^^
|
||||
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||
|
|
||||
= warning: this changes meaning in Rust 2021
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
|
||||
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
||||
|
|
||||
LL | let _: Iter<'_, i32> = Box::new(array).iter();
|
||||
| ~~~~
|
||||
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
||||
|
|
||||
LL | let _: Iter<'_, i32> = IntoIterator::into_iter(Box::new(array));
|
||||
| ++++++++++++++++++++++++ ~
|
||||
|
||||
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
|
||||
--> $DIR/into-iter-on-arrays-2018.rs:29:24
|
||||
--> $DIR/into-iter-on-arrays-2018.rs:22:43
|
||||
|
|
||||
LL | let _: Iter<'_, i32> = Rc::new(array).into_iter();
|
||||
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||
|
|
||||
= warning: this changes meaning in Rust 2021
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
|
||||
|
||||
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
|
||||
--> $DIR/into-iter-on-arrays-2018.rs:25:41
|
||||
|
|
||||
LL | let _: Iter<'_, i32> = Array(array).into_iter();
|
||||
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||
|
|
||||
= warning: this changes meaning in Rust 2021
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
|
||||
|
||||
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
|
||||
--> $DIR/into-iter-on-arrays-2018.rs:32:24
|
||||
|
|
||||
LL | for _ in [1, 2, 3].into_iter() {}
|
||||
| ^^^^^^^^^
|
||||
@ -51,5 +61,5 @@ LL - for _ in [1, 2, 3].into_iter() {}
|
||||
LL + for _ in [1, 2, 3] {}
|
||||
|
|
||||
|
||||
warning: 3 warnings emitted
|
||||
warning: 5 warnings emitted
|
||||
|
||||
|
@ -71,137 +71,73 @@ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (du
|
||||
--> $DIR/into-iter-on-arrays-lint.rs:23:21
|
||||
|
|
||||
LL | Box::new(small).into_iter();
|
||||
| ^^^^^^^^^
|
||||
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||
|
|
||||
= warning: this changes meaning in Rust 2021
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
|
||||
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
||||
|
|
||||
LL | Box::new(small).iter();
|
||||
| ~~~~
|
||||
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
||||
|
|
||||
LL | IntoIterator::into_iter(Box::new(small));
|
||||
| ++++++++++++++++++++++++ ~
|
||||
|
||||
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
|
||||
--> $DIR/into-iter-on-arrays-lint.rs:26:22
|
||||
|
|
||||
LL | Box::new([1, 2]).into_iter();
|
||||
| ^^^^^^^^^
|
||||
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||
|
|
||||
= warning: this changes meaning in Rust 2021
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
|
||||
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
||||
|
|
||||
LL | Box::new([1, 2]).iter();
|
||||
| ~~~~
|
||||
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
||||
|
|
||||
LL | IntoIterator::into_iter(Box::new([1, 2]));
|
||||
| ++++++++++++++++++++++++ ~
|
||||
|
||||
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
|
||||
--> $DIR/into-iter-on-arrays-lint.rs:29:19
|
||||
|
|
||||
LL | Box::new(big).into_iter();
|
||||
| ^^^^^^^^^
|
||||
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||
|
|
||||
= warning: this changes meaning in Rust 2021
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
|
||||
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
||||
|
|
||||
LL | Box::new(big).iter();
|
||||
| ~~~~
|
||||
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
||||
|
|
||||
LL | IntoIterator::into_iter(Box::new(big));
|
||||
| ++++++++++++++++++++++++ ~
|
||||
|
||||
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
|
||||
--> $DIR/into-iter-on-arrays-lint.rs:32:25
|
||||
|
|
||||
LL | Box::new([0u8; 33]).into_iter();
|
||||
| ^^^^^^^^^
|
||||
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||
|
|
||||
= warning: this changes meaning in Rust 2021
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
|
||||
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
||||
|
|
||||
LL | Box::new([0u8; 33]).iter();
|
||||
| ~~~~
|
||||
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
||||
|
|
||||
LL | IntoIterator::into_iter(Box::new([0u8; 33]));
|
||||
| ++++++++++++++++++++++++ ~
|
||||
|
||||
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
|
||||
--> $DIR/into-iter-on-arrays-lint.rs:36:31
|
||||
|
|
||||
LL | Box::new(Box::new(small)).into_iter();
|
||||
| ^^^^^^^^^
|
||||
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||
|
|
||||
= warning: this changes meaning in Rust 2021
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
|
||||
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
||||
|
|
||||
LL | Box::new(Box::new(small)).iter();
|
||||
| ~~~~
|
||||
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
||||
|
|
||||
LL | IntoIterator::into_iter(Box::new(Box::new(small)));
|
||||
| ++++++++++++++++++++++++ ~
|
||||
|
||||
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
|
||||
--> $DIR/into-iter-on-arrays-lint.rs:39:32
|
||||
|
|
||||
LL | Box::new(Box::new([1, 2])).into_iter();
|
||||
| ^^^^^^^^^
|
||||
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||
|
|
||||
= warning: this changes meaning in Rust 2021
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
|
||||
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
||||
|
|
||||
LL | Box::new(Box::new([1, 2])).iter();
|
||||
| ~~~~
|
||||
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
||||
|
|
||||
LL | IntoIterator::into_iter(Box::new(Box::new([1, 2])));
|
||||
| ++++++++++++++++++++++++ ~
|
||||
|
||||
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
|
||||
--> $DIR/into-iter-on-arrays-lint.rs:42:29
|
||||
|
|
||||
LL | Box::new(Box::new(big)).into_iter();
|
||||
| ^^^^^^^^^
|
||||
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||
|
|
||||
= warning: this changes meaning in Rust 2021
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
|
||||
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
||||
|
|
||||
LL | Box::new(Box::new(big)).iter();
|
||||
| ~~~~
|
||||
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
||||
|
|
||||
LL | IntoIterator::into_iter(Box::new(Box::new(big)));
|
||||
| ++++++++++++++++++++++++ ~
|
||||
|
||||
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021.
|
||||
--> $DIR/into-iter-on-arrays-lint.rs:45:35
|
||||
|
|
||||
LL | Box::new(Box::new([0u8; 33])).into_iter();
|
||||
| ^^^^^^^^^
|
||||
| ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
|
||||
|
|
||||
= warning: this changes meaning in Rust 2021
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
|
||||
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
||||
|
|
||||
LL | Box::new(Box::new([0u8; 33])).iter();
|
||||
| ~~~~
|
||||
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
||||
|
|
||||
LL | IntoIterator::into_iter(Box::new(Box::new([0u8; 33])));
|
||||
| ++++++++++++++++++++++++ ~
|
||||
|
||||
warning: 12 warnings emitted
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user