Auto merge of #127796 - tgross35:rollup-ubo5hzb, r=tgross35

Rollup of 6 pull requests

Successful merges:

 - #120990 (Suggest a borrow when using dbg)
 - #127047 (fix least significant digits of f128 associated constants)
 - #127709 (match lowering: Move `MatchPair` tree creation to its own module)
 - #127770 (Update books)
 - #127780 (Make sure trait def ids match before zipping args in `note_function_argument_obligation`)
 - #127795 (Fix typos in RELEASES.md)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-07-16 08:33:11 +00:00
commit 5572759b8d
19 changed files with 635 additions and 280 deletions

View file

@ -67,7 +67,7 @@ Stabilized APIs
- [`NonNull::byte_add`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_add)
- [`NonNull::sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.sub)
- [`NonNull::byte_sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_sub)
- [`NonNull:offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from)
- [`NonNull::offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from)
- [`NonNull::byte_offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_offset_from)
- [`NonNull::read`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read)
- [`NonNull::read_volatile`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read_volatile)
@ -91,9 +91,9 @@ Stabilized APIs
- [`str::trim_ascii`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii)
- [`str::trim_ascii_start`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_start)
- [`str::trim_ascii_end`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_end)
- [`<[AsciiChar]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii)
- [`<[AsciiChar]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start)
- [`<[AsciiChar]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end)
- [`<[u8]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii)
- [`<[u8]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start)
- [`<[u8]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end)
- [`Ipv4Addr::BITS`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#associatedconstant.BITS)
- [`Ipv4Addr::to_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.to_bits)
- [`Ipv4Addr::from_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.from_bits)

View file

@ -4,7 +4,7 @@
#![allow(rustc::untranslatable_diagnostic)]
use either::Either;
use hir::ClosureKind;
use hir::{ClosureKind, Path};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
@ -16,6 +16,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
use rustc_middle::bug;
use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::VarDebugInfoContents;
use rustc_middle::mir::{
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
@ -546,7 +547,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
self.suggest_cloning(err, ty, expr, None, Some(move_spans));
}
}
if let Some(pat) = finder.pat {
self.suggest_ref_for_dbg_args(expr, place, move_span, err);
// it's useless to suggest inserting `ref` when the span don't comes from local code
if let Some(pat) = finder.pat
&& !move_span.is_dummy()
&& !self.infcx.tcx.sess.source_map().is_imported(move_span)
{
*in_pattern = true;
let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
if let Some(pat) = finder.parent_pat {
@ -561,6 +569,59 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
}
}
// for dbg!(x) which may take ownership, suggest dbg!(&x) instead
// but here we actually do not check whether the macro name is `dbg!`
// so that we may extend the scope a bit larger to cover more cases
fn suggest_ref_for_dbg_args(
&self,
body: &hir::Expr<'_>,
place: &Place<'tcx>,
move_span: Span,
err: &mut Diag<'infcx>,
) {
let var_info = self.body.var_debug_info.iter().find(|info| match info.value {
VarDebugInfoContents::Place(ref p) => p == place,
_ => false,
});
let arg_name = if let Some(var_info) = var_info {
var_info.name
} else {
return;
};
struct MatchArgFinder {
expr_span: Span,
match_arg_span: Option<Span>,
arg_name: Symbol,
}
impl Visitor<'_> for MatchArgFinder {
fn visit_expr(&mut self, e: &hir::Expr<'_>) {
// dbg! is expanded into a match pattern, we need to find the right argument span
if let hir::ExprKind::Match(expr, ..) = &e.kind
&& let hir::ExprKind::Path(hir::QPath::Resolved(
_,
path @ Path { segments: [seg], .. },
)) = &expr.kind
&& seg.ident.name == self.arg_name
&& self.expr_span.source_callsite().contains(expr.span)
{
self.match_arg_span = Some(path.span);
}
hir::intravisit::walk_expr(self, e);
}
}
let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name };
finder.visit_expr(body);
if let Some(macro_arg_span) = finder.match_arg_span {
err.span_suggestion_verbose(
macro_arg_span.shrink_to_lo(),
"consider borrowing instead of transferring ownership",
"&",
Applicability::MachineApplicable,
);
}
}
fn report_use_of_uninitialized(
&self,
mpi: MovePathIndex,

View file

@ -0,0 +1,254 @@
use rustc_middle::mir::*;
use rustc_middle::thir::{self, *};
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
use crate::build::matches::{FlatPat, MatchPair, TestCase};
use crate::build::Builder;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Builds and returns [`MatchPair`] trees, one for each pattern in
/// `subpatterns`, representing the fields of a [`PatKind::Variant`] or
/// [`PatKind::Leaf`].
///
/// Used internally by [`MatchPair::new`].
fn field_match_pairs<'pat>(
&mut self,
place: PlaceBuilder<'tcx>,
subpatterns: &'pat [FieldPat<'tcx>],
) -> Vec<MatchPair<'pat, 'tcx>> {
subpatterns
.iter()
.map(|fieldpat| {
let place =
place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
MatchPair::new(place, &fieldpat.pattern, self)
})
.collect()
}
/// Builds [`MatchPair`] trees for the prefix/middle/suffix parts of an
/// array pattern or slice pattern, and adds those trees to `match_pairs`.
///
/// Used internally by [`MatchPair::new`].
fn prefix_slice_suffix<'pat>(
&mut self,
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
place: &PlaceBuilder<'tcx>,
prefix: &'pat [Box<Pat<'tcx>>],
opt_slice: &'pat Option<Box<Pat<'tcx>>>,
suffix: &'pat [Box<Pat<'tcx>>],
) {
let tcx = self.tcx;
let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true),
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
}
} else {
((prefix.len() + suffix.len()).try_into().unwrap(), false)
};
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
let elem =
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
MatchPair::new(place.clone_project(elem), subpattern, self)
}));
if let Some(subslice_pat) = opt_slice {
let suffix_len = suffix.len() as u64;
let subslice = place.clone_project(PlaceElem::Subslice {
from: prefix.len() as u64,
to: if exact_size { min_length - suffix_len } else { suffix_len },
from_end: !exact_size,
});
match_pairs.push(MatchPair::new(subslice, subslice_pat, self));
}
match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
let end_offset = (idx + 1) as u64;
let elem = ProjectionElem::ConstantIndex {
offset: if exact_size { min_length - end_offset } else { end_offset },
min_length,
from_end: !exact_size,
};
let place = place.clone_project(elem);
MatchPair::new(place, subpattern, self)
}));
}
}
impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
/// Recursively builds a `MatchPair` tree for the given pattern and its
/// subpatterns.
pub(in crate::build) fn new(
mut place_builder: PlaceBuilder<'tcx>,
pattern: &'pat Pat<'tcx>,
cx: &mut Builder<'_, 'tcx>,
) -> MatchPair<'pat, 'tcx> {
// Force the place type to the pattern's type.
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
if let Some(resolved) = place_builder.resolve_upvar(cx) {
place_builder = resolved;
}
// Only add the OpaqueCast projection if the given place is an opaque type and the
// expected type from the pattern is not.
let may_need_cast = match place_builder.base() {
PlaceBase::Local(local) => {
let ty =
Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty;
ty != pattern.ty && ty.has_opaque_types()
}
_ => true,
};
if may_need_cast {
place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
}
let place = place_builder.try_to_place(cx);
let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
let mut subpairs = Vec::new();
let test_case = match pattern.kind {
PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
PatKind::Or { ref pats } => TestCase::Or {
pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
},
PatKind::Range(ref range) => {
if range.is_full_range(cx.tcx) == Some(true) {
default_irrefutable()
} else {
TestCase::Range(range)
}
}
PatKind::Constant { value } => TestCase::Constant { value },
PatKind::AscribeUserType {
ascription: thir::Ascription { ref annotation, variance },
ref subpattern,
..
} => {
// Apply the type ascription to the value at `match_pair.place`
let ascription = place.map(|source| super::Ascription {
annotation: annotation.clone(),
source,
variance,
});
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
TestCase::Irrefutable { ascription, binding: None }
}
PatKind::Binding { mode, var, ref subpattern, .. } => {
let binding = place.map(|source| super::Binding {
span: pattern.span,
source,
var_id: var,
binding_mode: mode,
});
if let Some(subpattern) = subpattern.as_ref() {
// this is the `x @ P` case; have to keep matching against `P` now
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
}
TestCase::Irrefutable { ascription: None, binding }
}
PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
// Apply a type ascription for the inline constant to the value at `match_pair.place`
let ascription = place.map(|source| {
let span = pattern.span;
let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
let args = ty::InlineConstArgs::new(
cx.tcx,
ty::InlineConstArgsParts {
parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
ty: cx.infcx.next_ty_var(span),
},
)
.args;
let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
def.to_def_id(),
ty::UserArgs { args, user_self_ty: None },
));
let annotation = ty::CanonicalUserTypeAnnotation {
inferred_ty: pattern.ty,
span,
user_ty: Box::new(user_ty),
};
super::Ascription { annotation, source, variance: ty::Contravariant }
});
subpairs.push(MatchPair::new(place_builder, pattern, cx));
TestCase::Irrefutable { ascription, binding: None }
}
PatKind::Array { ref prefix, ref slice, ref suffix } => {
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
default_irrefutable()
}
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
default_irrefutable()
} else {
TestCase::Slice {
len: prefix.len() + suffix.len(),
variable_length: slice.is_some(),
}
}
}
PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)`
subpairs = cx.field_match_pairs(downcast_place, subpatterns);
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
i == variant_index || {
(cx.tcx.features().exhaustive_patterns
|| cx.tcx.features().min_exhaustive_patterns)
&& !v
.inhabited_predicate(cx.tcx, adt_def)
.instantiate(cx.tcx, args)
.apply_ignore_module(cx.tcx, cx.param_env)
}
}) && (adt_def.did().is_local()
|| !adt_def.is_variant_list_non_exhaustive());
if irrefutable {
default_irrefutable()
} else {
TestCase::Variant { adt_def, variant_index }
}
}
PatKind::Leaf { ref subpatterns } => {
subpairs = cx.field_match_pairs(place_builder, subpatterns);
default_irrefutable()
}
PatKind::Deref { ref subpattern } => {
subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx));
default_irrefutable()
}
PatKind::DerefPattern { ref subpattern, mutability } => {
// Create a new temporary for each deref pattern.
// FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
let temp = cx.temp(
Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
pattern.span,
);
subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx));
TestCase::Deref { temp, mutability }
}
PatKind::Never => TestCase::Never,
};
MatchPair { place, test_case, subpairs, pattern }
}
}

View file

@ -24,6 +24,7 @@ use tracing::{debug, instrument};
use util::visit_bindings;
// helper functions, broken out by category:
mod match_pair;
mod simplify;
mod test;
mod util;
@ -1195,17 +1196,27 @@ impl<'pat, 'tcx> TestCase<'pat, 'tcx> {
}
}
/// Node in a tree of "match pairs", where each pair consists of a place to be
/// tested, and a test to perform on that place.
///
/// Each node also has a list of subpairs (possibly empty) that must also match,
/// and a reference to the THIR pattern it represents.
#[derive(Debug, Clone)]
pub(crate) struct MatchPair<'pat, 'tcx> {
/// This place...
// This can be `None` if it referred to a non-captured place in a closure.
// Invariant: place.is_none() => test_case is Irrefutable
// In other words this must be `Some(_)` after simplification.
///
/// ---
/// This can be `None` if it referred to a non-captured place in a closure.
///
/// Invariant: Can only be `None` when `test_case` is `Irrefutable`.
/// Therefore this must be `Some(_)` after simplification.
place: Option<Place<'tcx>>,
/// ... must pass this test...
// Invariant: after creation and simplification in `Candidate::new()`, this must not be
// `Irrefutable`.
///
/// ---
/// Invariant: after creation and simplification in [`FlatPat::new`],
/// this must not be [`TestCase::Irrefutable`].
test_case: TestCase<'pat, 'tcx>,
/// ... and these subpairs must match.

View file

@ -1,78 +1,15 @@
use std::marker::PhantomData;
use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
use crate::build::expr::as_place::PlaceBase;
use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase};
use crate::build::Builder;
use rustc_data_structures::fx::FxIndexMap;
use rustc_middle::mir::*;
use rustc_middle::thir::{self, *};
use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{self, Ty};
use rustc_middle::ty::Ty;
use rustc_span::Span;
use tracing::debug;
impl<'a, 'tcx> Builder<'a, 'tcx> {
pub(crate) fn field_match_pairs<'pat>(
&mut self,
place: PlaceBuilder<'tcx>,
subpatterns: &'pat [FieldPat<'tcx>],
) -> Vec<MatchPair<'pat, 'tcx>> {
subpatterns
.iter()
.map(|fieldpat| {
let place =
place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
MatchPair::new(place, &fieldpat.pattern, self)
})
.collect()
}
pub(crate) fn prefix_slice_suffix<'pat>(
&mut self,
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
place: &PlaceBuilder<'tcx>,
prefix: &'pat [Box<Pat<'tcx>>],
opt_slice: &'pat Option<Box<Pat<'tcx>>>,
suffix: &'pat [Box<Pat<'tcx>>],
) {
let tcx = self.tcx;
let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true),
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
}
} else {
((prefix.len() + suffix.len()).try_into().unwrap(), false)
};
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
let elem =
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
MatchPair::new(place.clone_project(elem), subpattern, self)
}));
if let Some(subslice_pat) = opt_slice {
let suffix_len = suffix.len() as u64;
let subslice = place.clone_project(PlaceElem::Subslice {
from: prefix.len() as u64,
to: if exact_size { min_length - suffix_len } else { suffix_len },
from_end: !exact_size,
});
match_pairs.push(MatchPair::new(subslice, subslice_pat, self));
}
match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
let end_offset = (idx + 1) as u64;
let elem = ProjectionElem::ConstantIndex {
offset: if exact_size { min_length - end_offset } else { end_offset },
min_length,
from_end: !exact_size,
};
let place = place.clone_project(elem);
MatchPair::new(place, subpattern, self)
}));
}
/// Creates a false edge to `imaginary_target` and a real edge to
/// real_target. If `imaginary_target` is none, or is the same as the real
/// target, a Goto is generated instead to simplify the generated MIR.
@ -96,181 +33,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
/// Recursively builds a `MatchPair` tree for the given pattern and its
/// subpatterns.
pub(in crate::build) fn new(
mut place_builder: PlaceBuilder<'tcx>,
pattern: &'pat Pat<'tcx>,
cx: &mut Builder<'_, 'tcx>,
) -> MatchPair<'pat, 'tcx> {
// Force the place type to the pattern's type.
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
if let Some(resolved) = place_builder.resolve_upvar(cx) {
place_builder = resolved;
}
// Only add the OpaqueCast projection if the given place is an opaque type and the
// expected type from the pattern is not.
let may_need_cast = match place_builder.base() {
PlaceBase::Local(local) => {
let ty =
Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty;
ty != pattern.ty && ty.has_opaque_types()
}
_ => true,
};
if may_need_cast {
place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
}
let place = place_builder.try_to_place(cx);
let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
let mut subpairs = Vec::new();
let test_case = match pattern.kind {
PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
PatKind::Or { ref pats } => TestCase::Or {
pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
},
PatKind::Range(ref range) => {
if range.is_full_range(cx.tcx) == Some(true) {
default_irrefutable()
} else {
TestCase::Range(range)
}
}
PatKind::Constant { value } => TestCase::Constant { value },
PatKind::AscribeUserType {
ascription: thir::Ascription { ref annotation, variance },
ref subpattern,
..
} => {
// Apply the type ascription to the value at `match_pair.place`
let ascription = place.map(|source| super::Ascription {
annotation: annotation.clone(),
source,
variance,
});
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
TestCase::Irrefutable { ascription, binding: None }
}
PatKind::Binding { mode, var, ref subpattern, .. } => {
let binding = place.map(|source| super::Binding {
span: pattern.span,
source,
var_id: var,
binding_mode: mode,
});
if let Some(subpattern) = subpattern.as_ref() {
// this is the `x @ P` case; have to keep matching against `P` now
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
}
TestCase::Irrefutable { ascription: None, binding }
}
PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
// Apply a type ascription for the inline constant to the value at `match_pair.place`
let ascription = place.map(|source| {
let span = pattern.span;
let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
let args = ty::InlineConstArgs::new(
cx.tcx,
ty::InlineConstArgsParts {
parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
ty: cx.infcx.next_ty_var(span),
},
)
.args;
let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
def.to_def_id(),
ty::UserArgs { args, user_self_ty: None },
));
let annotation = ty::CanonicalUserTypeAnnotation {
inferred_ty: pattern.ty,
span,
user_ty: Box::new(user_ty),
};
super::Ascription { annotation, source, variance: ty::Contravariant }
});
subpairs.push(MatchPair::new(place_builder, pattern, cx));
TestCase::Irrefutable { ascription, binding: None }
}
PatKind::Array { ref prefix, ref slice, ref suffix } => {
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
default_irrefutable()
}
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
default_irrefutable()
} else {
TestCase::Slice {
len: prefix.len() + suffix.len(),
variable_length: slice.is_some(),
}
}
}
PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)`
subpairs = cx.field_match_pairs(downcast_place, subpatterns);
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
i == variant_index || {
(cx.tcx.features().exhaustive_patterns
|| cx.tcx.features().min_exhaustive_patterns)
&& !v
.inhabited_predicate(cx.tcx, adt_def)
.instantiate(cx.tcx, args)
.apply_ignore_module(cx.tcx, cx.param_env)
}
}) && (adt_def.did().is_local()
|| !adt_def.is_variant_list_non_exhaustive());
if irrefutable {
default_irrefutable()
} else {
TestCase::Variant { adt_def, variant_index }
}
}
PatKind::Leaf { ref subpatterns } => {
subpairs = cx.field_match_pairs(place_builder, subpatterns);
default_irrefutable()
}
PatKind::Deref { ref subpattern } => {
subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx));
default_irrefutable()
}
PatKind::DerefPattern { ref subpattern, mutability } => {
// Create a new temporary for each deref pattern.
// FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
let temp = cx.temp(
Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
pattern.span,
);
subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx));
TestCase::Deref { temp, mutability }
}
PatKind::Never => TestCase::Never,
};
MatchPair { place, test_case, subpairs, pattern }
}
}
/// Determine the set of places that have to be stable across match guards.
///
/// Returns a list of places that need a fake borrow along with a local to store it.

View file

@ -3810,6 +3810,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
{
if let Some(where_pred) = where_pred.as_trait_clause()
&& let Some(failed_pred) = failed_pred.as_trait_clause()
&& where_pred.def_id() == failed_pred.def_id()
{
self.enter_forall(where_pred, |where_pred| {
let failed_pred = self.instantiate_binder_with_fresh_vars(

View file

@ -170,7 +170,7 @@ impl f128 {
/// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon
/// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS
#[unstable(feature = "f128", issue = "116909")]
pub const EPSILON: f128 = 1.92592994438723585305597794258492731e-34_f128;
pub const EPSILON: f128 = 1.92592994438723585305597794258492732e-34_f128;
/// Smallest finite `f128` value.
///
@ -178,7 +178,7 @@ impl f128 {
///
/// [`MAX`]: f128::MAX
#[unstable(feature = "f128", issue = "116909")]
pub const MIN: f128 = -1.18973149535723176508575932662800701e+4932_f128;
pub const MIN: f128 = -1.18973149535723176508575932662800702e+4932_f128;
/// Smallest positive normal `f128` value.
///
/// Equal to 2<sup>[`MIN_EXP`]&nbsp;&minus;&nbsp;1</sup>.
@ -194,7 +194,7 @@ impl f128 {
/// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS
/// [`MAX_EXP`]: f128::MAX_EXP
#[unstable(feature = "f128", issue = "116909")]
pub const MAX: f128 = 1.18973149535723176508575932662800701e+4932_f128;
pub const MAX: f128 = 1.18973149535723176508575932662800702e+4932_f128;
/// One greater than the minimum possible normal power of 2 exponent.
///

@ -1 +1 @@
Subproject commit f1e49bf7a8ea6c31ce016a52b8a4f6e1ffcfbc64
Subproject commit 67fa536768013d9d5a13f3a06790521d511ef711

@ -1 +1 @@
Subproject commit 941db8b3df45fd46cd87b50a5c86714b91dcde9c
Subproject commit 5454de3d12b9ccc6375b629cf7ccda8264640aac

@ -1 +1 @@
Subproject commit b10c6acaf0f43481f6600e95d4b5013446e29f7a
Subproject commit 019f3928d8b939ec71b63722dcc2e46330156441

@ -1 +1 @@
Subproject commit 1ae3deebc3ac16e276b6558e01420f8e605def08
Subproject commit e2f0bdc4031866734661dcdb548184bde1450baf

@ -1 +1 @@
Subproject commit 658c6c27cb975b92227936024816986c2d3716fb
Subproject commit 89aecb6951b77bc746da73df8c9f2b2ceaad494a

@ -1 +1 @@
Subproject commit d6e3a32a557db5902e714604def8015d6bb7e0f7
Subproject commit 0c4d55cb59fe440d1a630e4e5774d043968edb3f

View file

@ -1,20 +0,0 @@
//@ known-bug: rust-lang/rust#126416
trait Output<'a, T: 'a> {
type Type;
}
struct Wrapper;
impl Wrapper {
fn do_something_wrapper<O, F>(&mut self, _: F)
where
F: for<'a> FnOnce(<F as Output<i32>>::Type),
{
}
}
fn main() {
let mut wrapper = Wrapper;
wrapper.do_something_wrapper(|value| ());
}

View file

@ -0,0 +1,68 @@
fn s() -> String {
let a = String::new();
dbg!(a);
return a; //~ ERROR use of moved value:
}
fn m() -> String {
let a = String::new();
dbg!(1, 2, a, 1, 2);
return a; //~ ERROR use of moved value:
}
fn t(a: String) -> String {
let b: String = "".to_string();
dbg!(a, b);
return b; //~ ERROR use of moved value:
}
fn x(a: String) -> String {
let b: String = "".to_string();
dbg!(a, b);
return a; //~ ERROR use of moved value:
}
macro_rules! my_dbg {
() => {
eprintln!("[{}:{}:{}]", file!(), line!(), column!())
};
($val:expr $(,)?) => {
match $val {
tmp => {
eprintln!("[{}:{}:{}] {} = {:#?}",
file!(), line!(), column!(), stringify!($val), &tmp);
tmp
}
}
};
($($val:expr),+ $(,)?) => {
($(my_dbg!($val)),+,)
};
}
fn test_my_dbg() -> String {
let b: String = "".to_string();
my_dbg!(b, 1);
return b; //~ ERROR use of moved value:
}
fn test_not_macro() -> String {
let a = String::new();
let _b = match a {
tmp => {
eprintln!("dbg: {}", tmp);
tmp
}
};
return a; //~ ERROR use of moved value:
}
fn get_expr(_s: String) {}
fn test() {
let a: String = "".to_string();
let _res = get_expr(dbg!(a));
let _l = a.len(); //~ ERROR borrow of moved value
}
fn main() {}

View file

@ -0,0 +1,117 @@
error[E0382]: use of moved value: `a`
--> $DIR/dbg-issue-120327.rs:4:12
|
LL | let a = String::new();
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
LL | dbg!(a);
| ------- value moved here
LL | return a;
| ^ value used here after move
|
help: consider borrowing instead of transferring ownership
|
LL | dbg!(&a);
| +
error[E0382]: use of moved value: `a`
--> $DIR/dbg-issue-120327.rs:10:12
|
LL | let a = String::new();
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
LL | dbg!(1, 2, a, 1, 2);
| ------------------- value moved here
LL | return a;
| ^ value used here after move
|
help: consider borrowing instead of transferring ownership
|
LL | dbg!(1, 2, &a, 1, 2);
| +
error[E0382]: use of moved value: `b`
--> $DIR/dbg-issue-120327.rs:16:12
|
LL | let b: String = "".to_string();
| - move occurs because `b` has type `String`, which does not implement the `Copy` trait
LL | dbg!(a, b);
| ---------- value moved here
LL | return b;
| ^ value used here after move
|
help: consider borrowing instead of transferring ownership
|
LL | dbg!(a, &b);
| +
error[E0382]: use of moved value: `a`
--> $DIR/dbg-issue-120327.rs:22:12
|
LL | fn x(a: String) -> String {
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
LL | let b: String = "".to_string();
LL | dbg!(a, b);
| ---------- value moved here
LL | return a;
| ^ value used here after move
|
help: consider borrowing instead of transferring ownership
|
LL | dbg!(&a, b);
| +
error[E0382]: use of moved value: `b`
--> $DIR/dbg-issue-120327.rs:46:12
|
LL | tmp => {
| --- value moved here
...
LL | let b: String = "".to_string();
| - move occurs because `b` has type `String`, which does not implement the `Copy` trait
LL | my_dbg!(b, 1);
LL | return b;
| ^ value used here after move
|
help: consider borrowing instead of transferring ownership
|
LL | my_dbg!(&b, 1);
| +
help: borrow this binding in the pattern to avoid moving the value
|
LL | ref tmp => {
| +++
error[E0382]: use of moved value: `a`
--> $DIR/dbg-issue-120327.rs:57:12
|
LL | let a = String::new();
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
LL | let _b = match a {
LL | tmp => {
| --- value moved here
...
LL | return a;
| ^ value used here after move
|
help: borrow this binding in the pattern to avoid moving the value
|
LL | ref tmp => {
| +++
error[E0382]: borrow of moved value: `a`
--> $DIR/dbg-issue-120327.rs:65:14
|
LL | let a: String = "".to_string();
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
LL | let _res = get_expr(dbg!(a));
| ------- value moved here
LL | let _l = a.len();
| ^ value borrowed here after move
|
help: consider borrowing instead of transferring ownership
|
LL | let _res = get_expr(dbg!(&a));
| +
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0382`.

View file

@ -0,0 +1,23 @@
trait Output<'a> {
type Type;
}
struct Wrapper;
impl Wrapper {
fn do_something_wrapper<O, F>(self, _: F)
//~^ ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied
//~| ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied
where
F: for<'a> FnOnce(<F as Output<'a>>::Type),
//~^ ERROR the trait bound `F: Output<'_>` is not satisfied
//~| ERROR the trait bound `F: Output<'_>` is not satisfied
{
}
}
fn main() {
let mut wrapper = Wrapper;
wrapper.do_something_wrapper(|value| ());
//~^ ERROR expected a `FnOnce
}

View file

@ -0,0 +1,74 @@
error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied
--> $DIR/filter-relevant-fn-bounds.rs:8:5
|
LL | / fn do_something_wrapper<O, F>(self, _: F)
LL | |
LL | |
LL | | where
LL | | F: for<'a> FnOnce(<F as Output<'a>>::Type),
| |___________________________________________________^ the trait `for<'a> Output<'a>` is not implemented for `F`
|
help: consider further restricting this bound
|
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + for<'a> Output<'a>,
| ++++++++++++++++++++
error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied
--> $DIR/filter-relevant-fn-bounds.rs:8:8
|
LL | fn do_something_wrapper<O, F>(self, _: F)
| ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Output<'a>` is not implemented for `F`
|
help: consider further restricting this bound
|
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + for<'a> Output<'a>,
| ++++++++++++++++++++
error[E0277]: the trait bound `F: Output<'_>` is not satisfied
--> $DIR/filter-relevant-fn-bounds.rs:12:12
|
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F`
|
help: consider further restricting this bound
|
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + Output<'_>,
| ++++++++++++
error[E0277]: the trait bound `F: Output<'_>` is not satisfied
--> $DIR/filter-relevant-fn-bounds.rs:12:20
|
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F`
|
help: consider further restricting this bound
|
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + Output<'_>,
| ++++++++++++
error[E0277]: expected a `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
--> $DIR/filter-relevant-fn-bounds.rs:21:34
|
LL | wrapper.do_something_wrapper(|value| ());
| -------------------- ^^^^^^^^^^ expected an `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
| |
| required by a bound introduced by this call
|
= help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
help: this trait has no implementations, consider adding one
--> $DIR/filter-relevant-fn-bounds.rs:1:1
|
LL | trait Output<'a> {
| ^^^^^^^^^^^^^^^^
note: required by a bound in `Wrapper::do_something_wrapper`
--> $DIR/filter-relevant-fn-bounds.rs:12:12
|
LL | fn do_something_wrapper<O, F>(self, _: F)
| -------------------- required by a bound in this associated function
...
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper`
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -9,6 +9,10 @@ LL | let _ = dbg!(a);
| ^^^^^^^ value used here after move
|
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider borrowing instead of transferring ownership
|
LL | let _ = dbg!(&a);
| +
error: aborting due to 1 previous error