Auto merge of #155766 - jhpratt:rollup-EcXAaqS, r=jhpratt

Rollup of 7 pull requests

Successful merges:

 - rust-lang/rust#155643 (Improve suggestion for $-prefixed fragment specifiers)
 - rust-lang/rust#154197 (Avoid redundant clone suggestions in borrowck diagnostics)
 - rust-lang/rust#154372 (Exposing Float Masks)
 - rust-lang/rust#155680 (Handle index projections in call destinations in DSE)
 - rust-lang/rust#155732 (bootstrap: Don't clone submodules unconditionally in dry-run)
 - rust-lang/rust#155737 (Account for `GetSyntheticValue` failures)
 - rust-lang/rust#155738 (Pass fields to `is_tuple_fields` instead of `SBValue` object)
This commit is contained in:
bors
2026-04-25 06:41:56 +00:00
30 changed files with 690 additions and 188 deletions
+89 -42
View File
@@ -602,8 +602,14 @@ pub(super) fn borrowed_content_source(
BorrowedContentSource::DerefRawPointer
} else if base_ty.is_mutable_ptr() {
BorrowedContentSource::DerefMutableRef
} else {
} else if base_ty.is_ref() {
BorrowedContentSource::DerefSharedRef
} else {
// Custom type implementing `Deref` (e.g. `MyBox<T>`, `Rc<T>`, `Arc<T>`)
// that wasn't detected via the MIR init trace above. This can happen
// when the deref base is initialized by a regular statement rather than
// a `TerminatorKind::Call` with `CallSource::OverloadedOperator`.
BorrowedContentSource::OverloadedDeref(base_ty)
}
}
@@ -1002,6 +1008,14 @@ struct CapturedMessageOpt {
maybe_reinitialized_locations_is_empty: bool,
}
/// Tracks whether [`MirBorrowckCtxt::explain_captures`] emitted a clone
/// suggestion, so callers can avoid emitting redundant suggestions downstream.
#[derive(Copy, Clone, PartialEq, Eq)]
pub(super) enum CloneSuggestion {
Emitted,
NotEmitted,
}
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// Finds the spans associated to a move or copy of move_place at location.
pub(super) fn move_spans(
@@ -1226,7 +1240,7 @@ fn explain_captures(
move_spans: UseSpans<'tcx>,
moved_place: Place<'tcx>,
msg_opt: CapturedMessageOpt,
) {
) -> CloneSuggestion {
let CapturedMessageOpt {
is_partial_move: is_partial,
is_loop_message,
@@ -1235,6 +1249,7 @@ fn explain_captures(
has_suggest_reborrow,
maybe_reinitialized_locations_is_empty,
} = msg_opt;
let mut suggested_cloning = false;
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
let place_name = self
.describe_place(moved_place.as_ref())
@@ -1461,10 +1476,26 @@ fn explain_captures(
has_sugg = true;
}
if let Some(clone_trait) = tcx.lang_items().clone_trait() {
let sugg = if moved_place
// Check whether the deref is from a custom Deref impl
// (e.g. Rc, Box) or a built-in reference deref.
// For built-in derefs with Clone fully satisfied, we skip
// the UFCS suggestion here and let `suggest_cloning`
// downstream emit a simpler `.clone()` suggestion instead.
let has_overloaded_deref =
moved_place.iter_projections().any(|(place, elem)| {
matches!(elem, ProjectionElem::Deref)
&& matches!(
self.borrowed_content_source(place),
BorrowedContentSource::OverloadedDeref(_)
| BorrowedContentSource::OverloadedIndex(_)
)
});
let has_deref = moved_place
.iter_projections()
.any(|(_, elem)| matches!(elem, ProjectionElem::Deref))
{
.any(|(_, elem)| matches!(elem, ProjectionElem::Deref));
let sugg = if has_deref {
let (start, end) = if let Some(expr) = self.find_expr(move_span)
&& let Some(_) = self.clone_on_reference(expr)
&& let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind
@@ -1490,43 +1521,58 @@ fn explain_captures(
self.infcx.param_env,
) && !has_sugg
{
let msg = match &errors[..] {
[] => "you can `clone` the value and consume it, but this \
might not be your desired behavior"
.to_string(),
[error] => {
format!(
"you could `clone` the value and consume it, if the \
`{}` trait bound could be satisfied",
error.obligation.predicate,
)
}
_ => {
format!(
"you could `clone` the value and consume it, if the \
following trait bounds could be satisfied: {}",
listify(&errors, |e: &FulfillmentError<'tcx>| format!(
"`{}`",
e.obligation.predicate
))
.unwrap(),
)
}
};
err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
for error in errors {
if let FulfillmentErrorCode::Select(
SelectionError::Unimplemented,
) = error.code
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
pred,
)) = error.obligation.predicate.kind().skip_binder()
{
self.infcx.err_ctxt().suggest_derive(
&error.obligation,
err,
error.obligation.predicate.kind().rebind(pred),
);
let skip_for_simple_clone =
has_deref && !has_overloaded_deref && errors.is_empty();
if !skip_for_simple_clone {
let msg = match &errors[..] {
[] => "you can `clone` the value and consume it, but \
this might not be your desired behavior"
.to_string(),
[error] => {
format!(
"you could `clone` the value and consume it, if \
the `{}` trait bound could be satisfied",
error.obligation.predicate,
)
}
_ => {
format!(
"you could `clone` the value and consume it, if \
the following trait bounds could be satisfied: \
{}",
listify(
&errors,
|e: &FulfillmentError<'tcx>| format!(
"`{}`",
e.obligation.predicate
)
)
.unwrap(),
)
}
};
err.multipart_suggestion(
msg,
sugg,
Applicability::MaybeIncorrect,
);
suggested_cloning = errors.is_empty();
for error in errors {
if let FulfillmentErrorCode::Select(
SelectionError::Unimplemented,
) = error.code
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
pred,
)) = error.obligation.predicate.kind().skip_binder()
{
self.infcx.err_ctxt().suggest_derive(
&error.obligation,
err,
error.obligation.predicate.kind().rebind(pred),
);
}
}
}
}
@@ -1558,6 +1604,7 @@ fn explain_captures(
})
}
}
if suggested_cloning { CloneSuggestion::Emitted } else { CloneSuggestion::NotEmitted }
}
/// Skip over locals that begin with an underscore or have no name
@@ -14,7 +14,9 @@
use tracing::debug;
use crate::MirBorrowckCtxt;
use crate::diagnostics::{CapturedMessageOpt, DescribePlaceOpt, UseSpans};
use crate::diagnostics::{
BorrowedContentSource, CapturedMessageOpt, CloneSuggestion, DescribePlaceOpt, UseSpans,
};
use crate::prefixes::PrefixSet;
#[derive(Debug)]
@@ -269,14 +271,19 @@ fn report(&mut self, error: GroupedMoveError<'tcx>) {
.span_delayed_bug(span, "Type may implement copy, but there is no other error.");
return;
}
let mut has_clone_suggestion = CloneSuggestion::NotEmitted;
let mut err = match kind {
&IllegalMoveOriginKind::BorrowedContent { target_place } => self
.report_cannot_move_from_borrowed_content(
&IllegalMoveOriginKind::BorrowedContent { target_place } => {
let (diag, clone_sugg) = self.report_cannot_move_from_borrowed_content(
original_path,
target_place,
span,
use_spans,
),
);
has_clone_suggestion = clone_sugg;
diag
}
&IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
self.cannot_move_out_of_interior_of_drop(span, ty)
}
@@ -285,7 +292,7 @@ fn report(&mut self, error: GroupedMoveError<'tcx>) {
}
};
self.add_move_hints(error, &mut err, span);
self.add_move_hints(error, &mut err, span, has_clone_suggestion);
self.buffer_error(err);
}
@@ -426,7 +433,7 @@ fn report_cannot_move_from_borrowed_content(
deref_target_place: Place<'tcx>,
span: Span,
use_spans: Option<UseSpans<'tcx>>,
) -> Diag<'infcx> {
) -> (Diag<'infcx>, CloneSuggestion) {
let tcx = self.infcx.tcx;
// Inspect the type of the content behind the
// borrow to provide feedback about why this
@@ -447,8 +454,8 @@ fn report_cannot_move_from_borrowed_content(
let decl = &self.body.local_decls[local];
let local_name = self.local_name(local).map(|sym| format!("`{sym}`"));
if decl.is_ref_for_guard() {
return self
.cannot_move_out_of(
return (
self.cannot_move_out_of(
span,
&format!(
"{} in pattern guard",
@@ -458,9 +465,14 @@ fn report_cannot_move_from_borrowed_content(
.with_note(
"variables bound in patterns cannot be moved from \
until after the end of the pattern guard",
);
),
CloneSuggestion::NotEmitted,
);
} else if decl.is_ref_to_static() {
return self.report_cannot_move_from_static(move_place, span);
return (
self.report_cannot_move_from_static(move_place, span),
CloneSuggestion::NotEmitted,
);
}
}
@@ -539,10 +551,12 @@ fn report_cannot_move_from_borrowed_content(
has_suggest_reborrow: false,
maybe_reinitialized_locations_is_empty: true,
};
if let Some(use_spans) = use_spans {
self.explain_captures(&mut err, span, span, use_spans, move_place, msg_opt);
}
err
let suggested_cloning = if let Some(use_spans) = use_spans {
self.explain_captures(&mut err, span, span, use_spans, move_place, msg_opt)
} else {
CloneSuggestion::NotEmitted
};
(err, suggested_cloning)
}
fn report_closure_move_error(
@@ -676,7 +690,49 @@ fn closure_clause_kind(
}
}
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
/// Suggest cloning via UFCS when a move occurs through a custom `Deref` impl.
///
/// A simple `.clone()` on a type like `MyBox<Vec<i32>>` would clone the wrapper,
/// not the inner `Vec<i32>`. Instead, we suggest `<Vec<i32> as Clone>::clone(&val)`.
fn suggest_cloning_through_overloaded_deref(
&self,
err: &mut Diag<'_>,
ty: Ty<'tcx>,
span: Span,
) -> CloneSuggestion {
let tcx = self.infcx.tcx;
let Some(clone_trait) = tcx.lang_items().clone_trait() else {
return CloneSuggestion::NotEmitted;
};
let Some(errors) =
self.infcx.type_implements_trait_shallow(clone_trait, ty, self.infcx.param_env)
else {
return CloneSuggestion::NotEmitted;
};
if !errors.is_empty() {
return CloneSuggestion::NotEmitted;
}
let sugg = vec![
(span.shrink_to_lo(), format!("<{ty} as Clone>::clone(&")),
(span.shrink_to_hi(), ")".to_string()),
];
err.multipart_suggestion(
"you can `clone` the value and consume it, but this might not be \
your desired behavior",
sugg,
Applicability::MaybeIncorrect,
);
CloneSuggestion::Emitted
}
fn add_move_hints(
&self,
error: GroupedMoveError<'tcx>,
err: &mut Diag<'_>,
span: Span,
has_clone_suggestion: CloneSuggestion,
) {
match error {
GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
self.add_borrow_suggestions(err, span, !binds_to.is_empty());
@@ -719,14 +775,43 @@ fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span
None => "value".to_string(),
};
if let Some(expr) = self.find_expr(use_span) {
self.suggest_cloning(
err,
original_path.as_ref(),
place_ty,
expr,
Some(use_spans),
);
if has_clone_suggestion == CloneSuggestion::NotEmitted {
// Check if the move is directly through a custom Deref impl
// (e.g. `*my_box` where MyBox implements Deref).
// A simple `.clone()` would clone the wrapper type rather than
// the inner value, so we need a UFCS suggestion instead.
//
// However, if there are further projections after the deref
// (e.g. `(*rc).field`), the value accessed is already the inner
// type and a simple `.clone()` works correctly.
let needs_ufcs = original_path.projection.last()
== Some(&ProjectionElem::Deref)
&& original_path.iter_projections().any(|(place, elem)| {
matches!(elem, ProjectionElem::Deref)
&& matches!(
self.borrowed_content_source(place),
BorrowedContentSource::OverloadedDeref(_)
| BorrowedContentSource::OverloadedIndex(_)
)
});
let emitted_ufcs = if needs_ufcs {
self.suggest_cloning_through_overloaded_deref(err, place_ty, use_span)
} else {
CloneSuggestion::NotEmitted
};
if emitted_ufcs == CloneSuggestion::NotEmitted {
if let Some(expr) = self.find_expr(use_span) {
self.suggest_cloning(
err,
original_path.as_ref(),
place_ty,
expr,
Some(use_spans),
);
}
}
}
if let Some(upvar_field) = self
+37 -9
View File
@@ -2,6 +2,7 @@
use rustc_ast::tokenstream::TokenStreamIter;
use rustc_ast::{NodeId, tokenstream};
use rustc_ast_pretty::pprust;
use rustc_errors::Applicability;
use rustc_feature::Features;
use rustc_session::Session;
use rustc_session::parse::feature_err;
@@ -88,16 +89,17 @@ fn parse(
continue;
};
// Push a metavariable with no fragment specifier at the given span
let mut missing_fragment_specifier = |span| {
let fallback_metavar_decl =
|span| TokenTree::MetaVarDecl { span, name: ident, kind: NonterminalKind::TT };
// Emit a missing-fragment diagnostic and return a `TokenTree` fallback so parsing can
// continue.
let missing_fragment_specifier = |span, add_span| {
sess.dcx().emit_err(errors::MissingFragmentSpecifier {
span,
add_span: span.shrink_to_hi(),
add_span,
valid: VALID_FRAGMENT_NAMES_MSG,
});
// Fall back to a `TokenTree` since that will match anything if we continue expanding.
result.push(TokenTree::MetaVarDecl { span, name: ident, kind: NonterminalKind::TT });
fallback_metavar_decl(span)
};
// Not consuming the next token immediately, as it may not be a colon
@@ -112,13 +114,39 @@ fn parse(
// since if it's not a token then it will be an invalid declaration.
let Some(tokenstream::TokenTree::Token(token, _)) = iter.next() else {
// Invalid, return a nice source location as `var:`
missing_fragment_specifier(colon_span.with_lo(start_sp.lo()));
result.push(missing_fragment_specifier(
colon_span.with_lo(start_sp.lo()),
colon_span.shrink_to_hi(),
));
continue;
};
let Some((fragment, _)) = token.ident() else {
// No identifier for the fragment specifier;
missing_fragment_specifier(token.span);
if token.kind == token::Dollar
&& iter.peek().is_some_and(|next| {
matches!(
next,
tokenstream::TokenTree::Token(next_token, _)
if next_token.ident().is_some()
)
})
{
let mut err =
sess.dcx().struct_span_err(token.span, "missing fragment specifier");
err.note("fragment specifiers must be provided");
err.help(VALID_FRAGMENT_NAMES_MSG);
err.span_suggestion_verbose(
token.span,
"fragment specifiers should not be prefixed with `$`",
"",
Applicability::MaybeIncorrect,
);
err.emit();
result.push(fallback_metavar_decl(token.span));
} else {
result.push(missing_fragment_specifier(token.span, token.span.shrink_to_hi()));
}
continue;
};
@@ -146,7 +174,7 @@ fn parse(
} else {
// Whether it's none or some other tree, it doesn't belong to
// the current meta variable, returning the original span.
missing_fragment_specifier(start_sp);
result.push(missing_fragment_specifier(start_sp, start_sp.shrink_to_hi()));
}
}
result
@@ -47,13 +47,21 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
let mut patch = Vec::new();
for (bb, bb_data) in traversal::preorder(body) {
if let TerminatorKind::Call { ref args, .. } = bb_data.terminator().kind {
if let TerminatorKind::Call { ref args, ref destination, .. } = bb_data.terminator().kind {
let loc = Location { block: bb, statement_index: bb_data.statements.len() };
// Position ourselves between the evaluation of `args` and the write to `destination`.
live.seek_to_block_end(bb);
let mut state = live.get().clone();
// Don't turn into a move if the local is used as an index
// projection for the destination place.
LivenessTransferFunction(&mut state).visit_place(
destination,
visit::PlaceContext::MutatingUse(visit::MutatingUseContext::Call),
loc,
);
for (index, arg) in args.iter().map(|a| &a.node).enumerate().rev() {
if let Operand::Copy(place) = *arg
&& !place.is_indirect()
+73 -9
View File
@@ -339,14 +339,78 @@ impl f128 {
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
pub const MIN_EXACT_INTEGER: i128 = -Self::MAX_EXACT_INTEGER;
/// Sign bit
pub(crate) const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
/// The mask of the bit used to encode the sign of an [`f128`].
///
/// This bit is set when the sign is negative and unset when the sign is
/// positive.
/// If you only need to check whether a value is positive or negative,
/// [`is_sign_positive`] or [`is_sign_negative`] can be used.
///
/// [`is_sign_positive`]: f128::is_sign_positive
/// [`is_sign_negative`]: f128::is_sign_negative
/// ```rust
/// #![feature(float_masks)]
/// #![feature(f128)]
/// # #[cfg(target_has_reliable_f128)] {
/// let sign_mask = f128::SIGN_MASK;
/// let a = 1.6552f128;
/// let a_bits = a.to_bits();
///
/// assert_eq!(a_bits & sign_mask, 0x0);
/// assert_eq!(f128::from_bits(a_bits ^ sign_mask), -a);
/// assert_eq!(sign_mask, (-0.0f128).to_bits());
/// # }
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
/// Exponent mask
pub(crate) const EXP_MASK: u128 = 0x7fff_0000_0000_0000_0000_0000_0000_0000;
/// The mask of the bits used to encode the exponent of an [`f128`].
///
/// Note that the exponent is stored as a biased value, with a bias of 16383 for `f128`.
///
/// ```rust
/// #![feature(float_masks)]
/// #![feature(f128)]
/// # #[cfg(target_has_reliable_f128)] {
/// fn get_exp(a: f128) -> i128 {
/// let bias = 16383;
/// let biased = a.to_bits() & f128::EXPONENT_MASK;
/// (biased >> (f128::MANTISSA_DIGITS - 1)).cast_signed() - bias
/// }
///
/// assert_eq!(get_exp(0.5), -1);
/// assert_eq!(get_exp(1.0), 0);
/// assert_eq!(get_exp(2.0), 1);
/// assert_eq!(get_exp(4.0), 2);
/// # }
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const EXPONENT_MASK: u128 = 0x7fff_0000_0000_0000_0000_0000_0000_0000;
/// Mantissa mask
pub(crate) const MAN_MASK: u128 = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff;
/// The mask of the bits used to encode the mantissa of an [`f128`].
///
/// ```rust
/// #![feature(float_masks)]
/// #![feature(f128)]
/// # #[cfg(target_has_reliable_f128)] {
/// let mantissa_mask = f128::MANTISSA_MASK;
///
/// assert_eq!(0f128.to_bits() & mantissa_mask, 0x0);
/// assert_eq!(1f128.to_bits() & mantissa_mask, 0x0);
///
/// // multiplying a finite value by a power of 2 doesn't change its mantissa
/// // unless the result or initial value is not normal.
/// let a = 1.6552f128;
/// let b = 4.0 * a;
/// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask);
///
/// // The maximum and minimum values have a saturated significand
/// assert_eq!(f128::MAX.to_bits() & f128::MANTISSA_MASK, f128::MANTISSA_MASK);
/// assert_eq!(f128::MIN.to_bits() & f128::MANTISSA_MASK, f128::MANTISSA_MASK);
/// # }
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const MANTISSA_MASK: u128 = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff;
/// Minimum representable positive value (min subnormal)
const TINY_BITS: u128 = 0x1;
@@ -511,9 +575,9 @@ pub const fn is_normal(self) -> bool {
#[must_use]
pub const fn classify(self) -> FpCategory {
let bits = self.to_bits();
match (bits & Self::MAN_MASK, bits & Self::EXP_MASK) {
(0, Self::EXP_MASK) => FpCategory::Infinite,
(_, Self::EXP_MASK) => FpCategory::Nan,
match (bits & Self::MANTISSA_MASK, bits & Self::EXPONENT_MASK) {
(0, Self::EXPONENT_MASK) => FpCategory::Infinite,
(_, Self::EXPONENT_MASK) => FpCategory::Nan,
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
+75 -9
View File
@@ -333,14 +333,80 @@ impl f16 {
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
pub const MIN_EXACT_INTEGER: i16 = -Self::MAX_EXACT_INTEGER;
/// Sign bit
pub(crate) const SIGN_MASK: u16 = 0x8000;
/// The mask of the bit used to encode the sign of an [`f16`].
///
/// This bit is set when the sign is negative and unset when the sign is
/// positive.
/// If you only need to check whether a value is positive or negative,
/// [`is_sign_positive`] or [`is_sign_negative`] can be used.
///
/// [`is_sign_positive`]: f16::is_sign_positive
/// [`is_sign_negative`]: f16::is_sign_negative
/// ```rust
/// #![feature(float_masks)]
/// #![feature(f16)]
/// # #[cfg(target_has_reliable_f16)] {
/// let sign_mask = f16::SIGN_MASK;
/// let a = 1.6552f16;
/// let a_bits = a.to_bits();
///
/// assert_eq!(a_bits & sign_mask, 0x0);
/// assert_eq!(f16::from_bits(a_bits ^ sign_mask), -a);
/// assert_eq!(sign_mask, (-0.0f16).to_bits());
/// # }
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const SIGN_MASK: u16 = 0x8000;
/// Exponent mask
pub(crate) const EXP_MASK: u16 = 0x7c00;
/// The mask of the bits used to encode the exponent of an [`f16`].
///
/// Note that the exponent is stored as a biased value, with a bias of 15 for `f16`.
///
/// ```rust
/// #![feature(float_masks)]
/// #![feature(f16)]
/// # #[cfg(target_has_reliable_f16)] {
/// let exponent_mask = f16::EXPONENT_MASK;
///
/// fn get_exp(a: f16) -> i16 {
/// let bias = 15;
/// let biased = a.to_bits() & f16::EXPONENT_MASK;
/// (biased >> (f16::MANTISSA_DIGITS - 1)).cast_signed() - bias
/// }
///
/// assert_eq!(get_exp(0.5), -1);
/// assert_eq!(get_exp(1.0), 0);
/// assert_eq!(get_exp(2.0), 1);
/// assert_eq!(get_exp(4.0), 2);
/// # }
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const EXPONENT_MASK: u16 = 0x7c00;
/// Mantissa mask
pub(crate) const MAN_MASK: u16 = 0x03ff;
/// The mask of the bits used to encode the mantissa of an [`f16`].
///
/// ```rust
/// #![feature(float_masks)]
/// #![feature(f16)]
/// # #[cfg(target_has_reliable_f16)] {
/// let mantissa_mask = f16::MANTISSA_MASK;
///
/// assert_eq!(0f16.to_bits() & mantissa_mask, 0x0);
/// assert_eq!(1f16.to_bits() & mantissa_mask, 0x0);
///
/// // multiplying a finite value by a power of 2 doesn't change its mantissa
/// // unless the result or initial value is not normal.
/// let a = 1.6552f16;
/// let b = 4.0 * a;
/// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask);
///
/// // The maximum and minimum values have a saturated significand
/// assert_eq!(f16::MAX.to_bits() & f16::MANTISSA_MASK, f16::MANTISSA_MASK);
/// assert_eq!(f16::MIN.to_bits() & f16::MANTISSA_MASK, f16::MANTISSA_MASK);
/// # }
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const MANTISSA_MASK: u16 = 0x03ff;
/// Minimum representable positive value (min subnormal)
const TINY_BITS: u16 = 0x1;
@@ -503,9 +569,9 @@ pub const fn is_normal(self) -> bool {
#[must_use]
pub const fn classify(self) -> FpCategory {
let b = self.to_bits();
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
(0, Self::EXP_MASK) => FpCategory::Infinite,
(_, Self::EXP_MASK) => FpCategory::Nan,
match (b & Self::MANTISSA_MASK, b & Self::EXPONENT_MASK) {
(0, Self::EXPONENT_MASK) => FpCategory::Infinite,
(_, Self::EXPONENT_MASK) => FpCategory::Nan,
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
+64 -9
View File
@@ -572,14 +572,69 @@ impl f32 {
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
pub const MIN_EXACT_INTEGER: i32 = -Self::MAX_EXACT_INTEGER;
/// Sign bit
pub(crate) const SIGN_MASK: u32 = 0x8000_0000;
/// The mask of the bit used to encode the sign of an [`f32`].
///
/// This bit is set when the sign is negative and unset when the sign is
/// positive.
/// If you only need to check whether a value is positive or negative,
/// [`is_sign_positive`] or [`is_sign_negative`] can be used.
///
/// [`is_sign_positive`]: f32::is_sign_positive
/// [`is_sign_negative`]: f32::is_sign_negative
/// ```rust
/// #![feature(float_masks)]
/// let sign_mask = f32::SIGN_MASK;
/// let a = 1.6552f32;
/// let a_bits = a.to_bits();
///
/// assert_eq!(a_bits & sign_mask, 0x0);
/// assert_eq!(f32::from_bits(a_bits ^ sign_mask), -a);
/// assert_eq!(sign_mask, (-0.0f32).to_bits());
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const SIGN_MASK: u32 = 0x8000_0000;
/// Exponent mask
pub(crate) const EXP_MASK: u32 = 0x7f80_0000;
/// The mask of the bits used to encode the exponent of an [`f32`].
///
/// Note that the exponent is stored as a biased value, with a bias of 127 for `f32`.
///
/// ```rust
/// #![feature(float_masks)]
/// fn get_exp(a: f32) -> i32 {
/// let bias = 127;
/// let biased = a.to_bits() & f32::EXPONENT_MASK;
/// (biased >> (f32::MANTISSA_DIGITS - 1)).cast_signed() - bias
/// }
///
/// assert_eq!(get_exp(0.5), -1);
/// assert_eq!(get_exp(1.0), 0);
/// assert_eq!(get_exp(2.0), 1);
/// assert_eq!(get_exp(4.0), 2);
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const EXPONENT_MASK: u32 = 0x7f80_0000;
/// Mantissa mask
pub(crate) const MAN_MASK: u32 = 0x007f_ffff;
/// The mask of the bits used to encode the mantissa of an [`f32`].
///
/// ```rust
/// #![feature(float_masks)]
/// let mantissa_mask = f32::MANTISSA_MASK;
///
/// assert_eq!(0f32.to_bits() & mantissa_mask, 0x0);
/// assert_eq!(1f32.to_bits() & mantissa_mask, 0x0);
///
/// // multiplying a finite value by a power of 2 doesn't change its mantissa
/// // unless the result or initial value is not normal.
/// let a = 1.6552f32;
/// let b = 4.0 * a;
/// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask);
///
/// // The maximum and minimum values have a saturated significand
/// assert_eq!(f32::MAX.to_bits() & f32::MANTISSA_MASK, f32::MANTISSA_MASK);
/// assert_eq!(f32::MIN.to_bits() & f32::MANTISSA_MASK, f32::MANTISSA_MASK);
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const MANTISSA_MASK: u32 = 0x007f_ffff;
/// Minimum representable positive value (min subnormal)
const TINY_BITS: u32 = 0x1;
@@ -731,9 +786,9 @@ pub const fn classify(self) -> FpCategory {
// of our tests is able to find any difference between the complicated and the naive
// version, so now we are back to the naive version.
let b = self.to_bits();
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
(0, Self::EXP_MASK) => FpCategory::Infinite,
(_, Self::EXP_MASK) => FpCategory::Nan,
match (b & Self::MANTISSA_MASK, b & Self::EXPONENT_MASK) {
(0, Self::EXPONENT_MASK) => FpCategory::Infinite,
(_, Self::EXPONENT_MASK) => FpCategory::Nan,
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
+64 -9
View File
@@ -571,14 +571,69 @@ impl f64 {
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
pub const MIN_EXACT_INTEGER: i64 = -Self::MAX_EXACT_INTEGER;
/// Sign bit
pub(crate) const SIGN_MASK: u64 = 0x8000_0000_0000_0000;
/// The mask of the bit used to encode the sign of an [`f64`].
///
/// This bit is set when the sign is negative and unset when the sign is
/// positive.
/// If you only need to check whether a value is positive or negative,
/// [`is_sign_positive`] or [`is_sign_negative`] can be used.
///
/// [`is_sign_positive`]: f64::is_sign_positive
/// [`is_sign_negative`]: f64::is_sign_negative
/// ```rust
/// #![feature(float_masks)]
/// let sign_mask = f64::SIGN_MASK;
/// let a = 1.6552f64;
/// let a_bits = a.to_bits();
///
/// assert_eq!(a_bits & sign_mask, 0x0);
/// assert_eq!(f64::from_bits(a_bits ^ sign_mask), -a);
/// assert_eq!(sign_mask, (-0.0f64).to_bits());
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const SIGN_MASK: u64 = 0x8000_0000_0000_0000;
/// Exponent mask
pub(crate) const EXP_MASK: u64 = 0x7ff0_0000_0000_0000;
/// The mask of the bits used to encode the exponent of an [`f64`].
///
/// Note that the exponent is stored as a biased value, with a bias of 1024 for `f64`.
///
/// ```rust
/// #![feature(float_masks)]
/// fn get_exp(a: f64) -> i64 {
/// let bias = 1023;
/// let biased = a.to_bits() & f64::EXPONENT_MASK;
/// (biased >> (f64::MANTISSA_DIGITS - 1)).cast_signed() - bias
/// }
///
/// assert_eq!(get_exp(0.5), -1);
/// assert_eq!(get_exp(1.0), 0);
/// assert_eq!(get_exp(2.0), 1);
/// assert_eq!(get_exp(4.0), 2);
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const EXPONENT_MASK: u64 = 0x7ff0_0000_0000_0000;
/// Mantissa mask
pub(crate) const MAN_MASK: u64 = 0x000f_ffff_ffff_ffff;
/// The mask of the bits used to encode the mantissa of an [`f64`].
///
/// ```rust
/// #![feature(float_masks)]
/// let mantissa_mask = f64::MANTISSA_MASK;
///
/// assert_eq!(0f64.to_bits() & mantissa_mask, 0x0);
/// assert_eq!(1f64.to_bits() & mantissa_mask, 0x0);
///
/// // multiplying a finite value by a power of 2 doesn't change its mantissa
/// // unless the result or initial value is not normal.
/// let a = 1.6552f64;
/// let b = 4.0 * a;
/// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask);
///
/// // The maximum and minimum values have a saturated significand
/// assert_eq!(f64::MAX.to_bits() & f64::MANTISSA_MASK, f64::MANTISSA_MASK);
/// assert_eq!(f64::MIN.to_bits() & f64::MANTISSA_MASK, f64::MANTISSA_MASK);
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const MANTISSA_MASK: u64 = 0x000f_ffff_ffff_ffff;
/// Minimum representable positive value (min subnormal)
const TINY_BITS: u64 = 0x1;
@@ -730,9 +785,9 @@ pub const fn classify(self) -> FpCategory {
// of our tests is able to find any difference between the complicated and the naive
// version, so now we are back to the naive version.
let b = self.to_bits();
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
(0, Self::EXP_MASK) => FpCategory::Infinite,
(_, Self::EXP_MASK) => FpCategory::Nan,
match (b & Self::MANTISSA_MASK, b & Self::EXPONENT_MASK) {
(0, Self::EXPONENT_MASK) => FpCategory::Infinite,
(_, Self::EXPONENT_MASK) => FpCategory::Nan,
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
+6 -6
View File
@@ -204,8 +204,8 @@ impl Float for f16 {
const BITS: u32 = 16;
const SIG_TOTAL_BITS: u32 = Self::MANTISSA_DIGITS;
const EXP_MASK: Self::Int = Self::EXP_MASK;
const SIG_MASK: Self::Int = Self::MAN_MASK;
const EXP_MASK: Self::Int = Self::EXPONENT_MASK;
const SIG_MASK: Self::Int = Self::MANTISSA_MASK;
const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -22;
const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 5;
@@ -238,8 +238,8 @@ impl Float for f32 {
const BITS: u32 = 32;
const SIG_TOTAL_BITS: u32 = Self::MANTISSA_DIGITS;
const EXP_MASK: Self::Int = Self::EXP_MASK;
const SIG_MASK: Self::Int = Self::MAN_MASK;
const EXP_MASK: Self::Int = Self::EXPONENT_MASK;
const SIG_MASK: Self::Int = Self::MANTISSA_MASK;
const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -17;
const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10;
@@ -271,8 +271,8 @@ impl Float for f64 {
const BITS: u32 = 64;
const SIG_TOTAL_BITS: u32 = Self::MANTISSA_DIGITS;
const EXP_MASK: Self::Int = Self::EXP_MASK;
const SIG_MASK: Self::Int = Self::MAN_MASK;
const EXP_MASK: Self::Int = Self::EXPONENT_MASK;
const SIG_MASK: Self::Int = Self::MANTISSA_MASK;
const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -4;
const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23;
+5 -16
View File
@@ -2448,17 +2448,7 @@ pub(crate) fn update_submodule<'a>(
return;
}
// Submodule updating actually happens during in the dry run mode. We need to make sure that
// all the git commands below are actually executed, because some follow-up code
// in bootstrap might depend on the submodules being checked out. Furthermore, not all
// the command executions below work with an empty output (produced during dry run).
// Therefore, all commands below are marked with `run_in_dry_run()`, so that they also run in
// dry run mode.
let submodule_git = || {
let mut cmd = helpers::git(Some(&absolute_path));
cmd.run_in_dry_run();
cmd
};
let submodule_git = || helpers::git(Some(&absolute_path));
// Determine commit checked out in submodule.
let checked_out_hash =
@@ -2466,7 +2456,7 @@ pub(crate) fn update_submodule<'a>(
let checked_out_hash = checked_out_hash.trim_end();
// Determine commit that the submodule *should* have.
let recorded = helpers::git(Some(dwn_ctx.src))
.run_in_dry_run()
.run_in_dry_run() // otherwise parsing `actual_hash` fails
.args(["ls-tree", "HEAD"])
.arg(relative_path)
.run_capture_stdout(dwn_ctx.exec_ctx)
@@ -2482,11 +2472,12 @@ pub(crate) fn update_submodule<'a>(
return;
}
println!("Updating submodule {relative_path}");
if !dwn_ctx.exec_ctx.dry_run() {
println!("Updating submodule {relative_path}");
};
helpers::git(Some(dwn_ctx.src))
.allow_failure()
.run_in_dry_run()
.args(["submodule", "-q", "sync"])
.arg(relative_path)
.run(dwn_ctx.exec_ctx);
@@ -2497,12 +2488,10 @@ pub(crate) fn update_submodule<'a>(
// even though that has no relation to the upstream for the submodule.
let current_branch = helpers::git(Some(dwn_ctx.src))
.allow_failure()
.run_in_dry_run()
.args(["symbolic-ref", "--short", "HEAD"])
.run_capture(dwn_ctx.exec_ctx);
let mut git = helpers::git(Some(dwn_ctx.src)).allow_failure();
git.run_in_dry_run();
if current_branch.is_success() {
// If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name.
// This syntax isn't accepted by `branch.{branch}`. Strip it.
+4
View File
@@ -676,6 +676,10 @@ pub fn require_submodule(&self, submodule: &str, err_hint: Option<&str>) {
return;
}
if self.config.dry_run() {
return;
}
// When testing bootstrap itself, it is much faster to ignore
// submodules. Almost all Steps work fine without their submodules.
if cfg!(test) && !self.config.submodules() {
+31 -24
View File
@@ -108,8 +108,6 @@ class DefaultSyntheticProvider:
return self.valobj.GetNumChildren()
def get_child_index(self, name: str) -> int:
if self.is_ptr and name == "$$dereference$$":
return self.valobj.Dereference().GetSyntheticValue()
return self.valobj.GetIndexOfChildWithName(name)
def get_child_at_index(self, index: int) -> Optional[SBValue]:
@@ -133,13 +131,17 @@ class IndirectionSyntheticProvider:
return 1
def get_child_index(self, name: str) -> int:
if self.is_ptr and name == "$$dereference$$":
if name == "$$dereference$$":
return 0
return -1
def get_child_at_index(self, index: int) -> Optional[SBValue]:
if index == 0:
return self.valobj.Dereference().GetSyntheticValue()
value = self.valobj.Dereference()
if (synth := value.GetSyntheticValue()).IsValid():
return synth
else:
return value
return None
def update(self):
@@ -266,7 +268,7 @@ def aggregate_field_summary(valobj: SBValue, _dict) -> Generator[str, None, None
if summary is None:
summary = child.value
if summary is None:
if is_tuple_fields(child):
if is_tuple_fields(child.GetType().fields):
summary = TupleSummaryProvider(child, _dict)
else:
summary = StructSummaryProvider(child, _dict)
@@ -569,7 +571,9 @@ class ClangEncodedEnumProvider:
self.variant = all_variants.GetChildAtIndex(index)
self.value = self.variant.GetChildMemberWithName(
ClangEncodedEnumProvider.VALUE_MEMBER_NAME
).GetSyntheticValue()
)
if (synth := self.value.GetSyntheticValue()).IsValid():
self.value = synth
def _getCurrentVariantIndex(self, all_variants: SBValue) -> int:
default_index = 0
@@ -651,9 +655,10 @@ class MSVCEnumSyntheticProvider:
).GetValueAsUnsigned()
if tag == discr:
self.variant = child
self.value = child.GetChildMemberWithName(
"value"
).GetSyntheticValue()
self.value = child.GetChildMemberWithName("value")
if (synth := self.value.GetSyntheticValue()).IsValid():
self.value = synth
return
else: # if invalid, DISCR must be a range
begin: int = (
@@ -671,16 +676,18 @@ class MSVCEnumSyntheticProvider:
if begin < end:
if begin <= tag <= end:
self.variant = child
self.value = child.GetChildMemberWithName(
"value"
).GetSyntheticValue()
self.value = child.GetChildMemberWithName("value")
if (synth := self.value.GetSyntheticValue()).IsValid():
self.value = synth
return
else:
if tag >= begin or tag <= end:
self.variant = child
self.value = child.GetChildMemberWithName(
"value"
).GetSyntheticValue()
self.value = child.GetChildMemberWithName("value")
if (synth := self.value.GetSyntheticValue()).IsValid():
self.value = synth
return
else: # if invalid, tag is a 128 bit value
tag_lo: int = self.valobj.GetChildMemberWithName(
@@ -714,9 +721,9 @@ class MSVCEnumSyntheticProvider:
discr: int = (exact_hi << 64) | exact_lo
if tag == discr:
self.variant = child
self.value = child.GetChildMemberWithName(
"value"
).GetSyntheticValue()
self.value = child.GetChildMemberWithName("value")
if (synth := self.value.GetSyntheticValue()).IsValid():
self.value = synth
return
else: # if invalid, DISCR must be a range
begin_lo: int = (
@@ -748,16 +755,16 @@ class MSVCEnumSyntheticProvider:
if begin < end:
if begin <= tag <= end:
self.variant = child
self.value = child.GetChildMemberWithName(
"value"
).GetSyntheticValue()
self.value = child.GetChildMemberWithName("value")
if (synth := self.value.GetSyntheticValue()).IsValid():
self.value = synth
return
else:
if tag >= begin or tag <= end:
self.variant = child
self.value = child.GetChildMemberWithName(
"value"
).GetSyntheticValue()
self.value = child.GetChildMemberWithName("value")
if (synth := self.value.GetSyntheticValue()).IsValid():
self.value = synth
return
def num_children(self) -> int:
@@ -0,0 +1,15 @@
- // MIR for `move_index` before DeadStoreElimination-final
+ // MIR for `move_index` after DeadStoreElimination-final
fn move_index(_1: [usize; 10], _2: usize) -> () {
let mut _0: ();
bb0: {
_1[_2] = passthrough_usize(copy _2) -> [return: bb1, unwind unreachable];
}
bb1: {
return;
}
}
@@ -0,0 +1,15 @@
- // MIR for `move_index` before DeadStoreElimination-final
+ // MIR for `move_index` after DeadStoreElimination-final
fn move_index(_1: [usize; 10], _2: usize) -> () {
let mut _0: ();
bb0: {
_1[_2] = passthrough_usize(copy _2) -> [return: bb1, unwind continue];
}
bb1: {
return;
}
}
@@ -40,7 +40,31 @@ fn move_packed(packed: Packed) {
}
}
#[inline(never)]
fn passthrough_usize(a: usize) -> usize {
a
}
// EMIT_MIR call_arg_copy.move_index.DeadStoreElimination-final.diff
#[custom_mir(dialect = "analysis")]
fn move_index(a: [usize; 10], b: usize) {
// CHECK-LABEL: fn move_index(
// CHECK: = passthrough_usize(copy _2)
mir! {
{
// The index is used again after the operand is evaluated to
// evaluate the destionation place, so the argument cannot be turned
// into a move.
Call(a[b] = passthrough_usize(b), ReturnTo(ret), UnwindContinue())
}
ret = {
Return()
}
}
}
fn main() {
move_simple(1);
move_packed(Packed { x: 0, y: 1 });
move_index([0; _], 1);
}
@@ -2,6 +2,6 @@
use std::rc::Rc;
pub fn main() {
let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2]).clone()).into_iter();
let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2])).into_iter();
//~^ ERROR [E0507]
}
@@ -12,10 +12,6 @@ help: you can `clone` the value and consume it, but this might not be your desir
|
LL | let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2])).into_iter();
| ++++++++++++++++++++++++++++ +
help: consider cloning the value if the performance cost is acceptable
|
LL | let _x = Rc::new(vec![1, 2]).clone().into_iter();
| ++++++++
error: aborting due to 1 previous error
@@ -7,5 +7,5 @@ impl Foo {
}
fn main() {
let foo = &Foo;
<Foo as Clone>::clone(&foo.clone()).foo(); //~ ERROR cannot move out
foo.clone().foo(); //~ ERROR cannot move out
}
@@ -11,10 +11,6 @@ note: `Foo::foo` takes ownership of the receiver `self`, which moves `*foo`
|
LL | fn foo(self) {}
| ^^^^
help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | <Foo as Clone>::clone(&(*foo)).foo();
| +++++++++++++++++++++++ +
help: consider cloning the value if the performance cost is acceptable
|
LL - (*foo).foo();
@@ -9,7 +9,7 @@ fn call<F>(f: F) where F : Fn() {
fn main() {
let y = vec![format!("World")];
call(|| {
<Vec<String> as Clone>::clone(&y.clone()).into_iter();
y.clone().into_iter();
//~^ ERROR cannot move out of `y`, a captured variable in an `Fn` closure
});
}
@@ -17,10 +17,6 @@ LL | fn call<F>(f: F) where F : Fn() {
| ^^^^
note: `into_iter` takes ownership of the receiver `self`, which moves `y`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | <Vec<String> as Clone>::clone(&y).into_iter();
| +++++++++++++++++++++++++++++++ +
help: consider cloning the value if the performance cost is acceptable
|
LL | y.clone().into_iter();
@@ -13,6 +13,10 @@ macro_rules! unused_macro {
( $name ) => {}; //~ ERROR missing fragment
}
macro_rules! accidental_dollar_prefix {
( $test:$tt ) => {}; //~ ERROR missing fragment
}
fn main() {
used_arm!();
used_macro_unused_arm!();
+15 -1
View File
@@ -37,5 +37,19 @@ help: try adding a specifier here
LL | ( $name:spec ) => {};
| +++++
error: aborting due to 3 previous errors
error: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:17:13
|
LL | ( $test:$tt ) => {};
| ^
|
= note: fragment specifiers must be provided
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
help: fragment specifiers should not be prefixed with `$`
|
LL - ( $test:$tt ) => {};
LL + ( $test:tt ) => {};
|
error: aborting due to 4 previous errors
+1 -1
View File
@@ -7,5 +7,5 @@ impl Foo {
}
fn main() {
let foo = &Foo;
<Foo as Clone>::clone(&foo.clone()).foo(); //~ ERROR cannot move out
foo.clone().foo(); //~ ERROR cannot move out
}
-4
View File
@@ -11,10 +11,6 @@ note: `Foo::foo` takes ownership of the receiver `self`, which moves `*foo`
|
LL | fn foo(self) {}
| ^^^^
help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | <Foo as Clone>::clone(&foo).foo();
| +++++++++++++++++++++++ +
help: consider cloning the value if the performance cost is acceptable
|
LL | foo.clone().foo();
@@ -7,7 +7,7 @@ impl LipogramCorpora {
pub fn validate_all(&mut self) -> Result<(), char> {
for selection in &self.selections {
if selection.1.is_some() {
if <Option<String> as Clone>::clone(&selection.1.clone()).as_mut().as_ref().unwrap().contains(selection.0) {
if selection.1.clone().as_mut().as_ref().unwrap().contains(selection.0) {
//~^ ERROR cannot move out of `selection.1`
return Err(selection.0);
}
@@ -25,7 +25,7 @@ impl LipogramCorpora2 {
pub fn validate_all(&mut self) -> Result<(), char> {
for selection in &self.selections {
if selection.1.is_ok() {
if <Result<String, String> as Clone>::clone(&selection.1.clone()).as_mut().as_ref().unwrap().contains(selection.0) {
if selection.1.clone().as_mut().as_ref().unwrap().contains(selection.0) {
//~^ ERROR cannot move out of `selection.1`
return Err(selection.0);
}
@@ -16,10 +16,6 @@ help: consider calling `.as_mut()` to mutably borrow the value's contents
|
LL | if selection.1.as_mut().unwrap().contains(selection.0) {
| +++++++++
help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | if <Option<String> as Clone>::clone(&selection.1).unwrap().contains(selection.0) {
| ++++++++++++++++++++++++++++++++++ +
help: consider cloning the value if the performance cost is acceptable
|
LL | if selection.1.clone().unwrap().contains(selection.0) {
@@ -43,10 +39,6 @@ help: consider calling `.as_mut()` to mutably borrow the value's contents
|
LL | if selection.1.as_mut().unwrap().contains(selection.0) {
| +++++++++
help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | if <Result<String, String> as Clone>::clone(&selection.1).unwrap().contains(selection.0) {
| ++++++++++++++++++++++++++++++++++++++++++ +
help: consider cloning the value if the performance cost is acceptable
|
LL | if selection.1.clone().unwrap().contains(selection.0) {
@@ -0,0 +1,16 @@
//@ run-rustfix
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub fn main() {
let _x = <Vec<i32> as Clone>::clone(&MyBox(vec![1, 2])).into_iter();
//~^ ERROR cannot move out of dereference of `MyBox<Vec<i32>>`
}
@@ -0,0 +1,16 @@
//@ run-rustfix
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub fn main() {
let _x = MyBox(vec![1, 2]).into_iter();
//~^ ERROR cannot move out of dereference of `MyBox<Vec<i32>>`
}
@@ -0,0 +1,14 @@
error[E0507]: cannot move out of dereference of `MyBox<Vec<i32>>`
--> $DIR/ufcs-for-deref-inner-clone.rs:14:14
|
LL | let _x = MyBox(vec![1, 2]).into_iter();
| ^^^^^^^^^^^^^^^^^ move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
|
help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | let _x = <Vec<i32> as Clone>::clone(&MyBox(vec![1, 2])).into_iter();
| ++++++++++++++++++++++++++++ +
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0507`.