Auto merge of #144440 - matthiaskrgr:rollup-peb88gb, r=matthiaskrgr
Rollup of 12 pull requests Successful merges: - rust-lang/rust#142569 (Suggest clone in user-write-code instead of inside macro) - rust-lang/rust#143401 (tests: Don't check for self-printed output in std-backtrace.rs test) - rust-lang/rust#143424 (clippy fix: rely on autoderef) - rust-lang/rust#143970 (Update core::mem::copy documentation) - rust-lang/rust#143979 (Test fixes for Arm64EC Windows) - rust-lang/rust#144200 (Tweak output for non-`Clone` values moved into closures) - rust-lang/rust#144209 (Don't emit two `assume`s in transmutes when one is a subset of the other) - rust-lang/rust#144314 (Hint that choose_pivot returns index in bounds) - rust-lang/rust#144340 (UI test suite clarity changes: Rename `tests/ui/SUMMARY.md` and update rustc dev guide on `error-pattern`) - rust-lang/rust#144368 (resolve: Remove `Scope::CrateRoot`) - rust-lang/rust#144390 (Remove dead code and extend test coverage and diagnostics around it) - rust-lang/rust#144392 (rustc_public: Remove movability from `RigidTy/AggregateKind::Coroutine`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a955f1cd09
50 changed files with 512 additions and 262 deletions
|
|
@ -313,7 +313,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
scalar_valid_range: (Bound<u128>, Bound<u128>),
|
||||
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
|
||||
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
|
||||
dont_niche_optimize_enum: bool,
|
||||
always_sized: bool,
|
||||
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
|
||||
let (present_first, present_second) = {
|
||||
|
|
@ -352,13 +351,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
// structs. (We have also handled univariant enums
|
||||
// that allow representation optimization.)
|
||||
assert!(is_enum);
|
||||
self.layout_of_enum(
|
||||
repr,
|
||||
variants,
|
||||
discr_range_of_repr,
|
||||
discriminants,
|
||||
dont_niche_optimize_enum,
|
||||
)
|
||||
self.layout_of_enum(repr, variants, discr_range_of_repr, discriminants)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -599,7 +592,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
||||
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
|
||||
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
|
||||
dont_niche_optimize_enum: bool,
|
||||
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
|
||||
// Until we've decided whether to use the tagged or
|
||||
// niche filling LayoutData, we don't want to intern the
|
||||
|
|
@ -618,7 +610,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
}
|
||||
|
||||
let calculate_niche_filling_layout = || -> Option<TmpLayout<FieldIdx, VariantIdx>> {
|
||||
if dont_niche_optimize_enum {
|
||||
if repr.inhibit_enum_layout_opt() {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1376,6 +1376,28 @@ impl WrappingRange {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if all the values in `other` are contained in this range,
|
||||
/// when the values are considered as having width `size`.
|
||||
#[inline(always)]
|
||||
pub fn contains_range(&self, other: Self, size: Size) -> bool {
|
||||
if self.is_full_for(size) {
|
||||
true
|
||||
} else {
|
||||
let trunc = |x| size.truncate(x);
|
||||
|
||||
let delta = self.start;
|
||||
let max = trunc(self.end.wrapping_sub(delta));
|
||||
|
||||
let other_start = trunc(other.start.wrapping_sub(delta));
|
||||
let other_end = trunc(other.end.wrapping_sub(delta));
|
||||
|
||||
// Having shifted both input ranges by `delta`, now we only need to check
|
||||
// whether `0..=max` contains `other_start..=other_end`, which can only
|
||||
// happen if the other doesn't wrap since `self` isn't everything.
|
||||
(other_start <= other_end) && (other_end <= max)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `self` with replaced `start`
|
||||
#[inline(always)]
|
||||
fn with_start(mut self, start: u128) -> Self {
|
||||
|
|
|
|||
|
|
@ -5,3 +5,66 @@ fn align_constants() {
|
|||
assert_eq!(Align::ONE, Align::from_bytes(1).unwrap());
|
||||
assert_eq!(Align::EIGHT, Align::from_bytes(8).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapping_range_contains_range() {
|
||||
let size16 = Size::from_bytes(16);
|
||||
|
||||
let a = WrappingRange { start: 10, end: 20 };
|
||||
assert!(a.contains_range(a, size16));
|
||||
assert!(a.contains_range(WrappingRange { start: 11, end: 19 }, size16));
|
||||
assert!(a.contains_range(WrappingRange { start: 10, end: 10 }, size16));
|
||||
assert!(a.contains_range(WrappingRange { start: 20, end: 20 }, size16));
|
||||
assert!(!a.contains_range(WrappingRange { start: 10, end: 21 }, size16));
|
||||
assert!(!a.contains_range(WrappingRange { start: 9, end: 20 }, size16));
|
||||
assert!(!a.contains_range(WrappingRange { start: 4, end: 6 }, size16));
|
||||
assert!(!a.contains_range(WrappingRange { start: 24, end: 26 }, size16));
|
||||
|
||||
assert!(!a.contains_range(WrappingRange { start: 16, end: 14 }, size16));
|
||||
|
||||
let b = WrappingRange { start: 20, end: 10 };
|
||||
assert!(b.contains_range(b, size16));
|
||||
assert!(b.contains_range(WrappingRange { start: 20, end: 20 }, size16));
|
||||
assert!(b.contains_range(WrappingRange { start: 10, end: 10 }, size16));
|
||||
assert!(b.contains_range(WrappingRange { start: 0, end: 10 }, size16));
|
||||
assert!(b.contains_range(WrappingRange { start: 20, end: 30 }, size16));
|
||||
assert!(b.contains_range(WrappingRange { start: 20, end: 9 }, size16));
|
||||
assert!(b.contains_range(WrappingRange { start: 21, end: 10 }, size16));
|
||||
assert!(b.contains_range(WrappingRange { start: 999, end: 9999 }, size16));
|
||||
assert!(b.contains_range(WrappingRange { start: 999, end: 9 }, size16));
|
||||
assert!(!b.contains_range(WrappingRange { start: 19, end: 19 }, size16));
|
||||
assert!(!b.contains_range(WrappingRange { start: 11, end: 11 }, size16));
|
||||
assert!(!b.contains_range(WrappingRange { start: 19, end: 11 }, size16));
|
||||
assert!(!b.contains_range(WrappingRange { start: 11, end: 19 }, size16));
|
||||
|
||||
let f = WrappingRange { start: 0, end: u128::MAX };
|
||||
assert!(f.contains_range(WrappingRange { start: 10, end: 20 }, size16));
|
||||
assert!(f.contains_range(WrappingRange { start: 20, end: 10 }, size16));
|
||||
|
||||
let g = WrappingRange { start: 2, end: 1 };
|
||||
assert!(g.contains_range(WrappingRange { start: 10, end: 20 }, size16));
|
||||
assert!(g.contains_range(WrappingRange { start: 20, end: 10 }, size16));
|
||||
|
||||
let size1 = Size::from_bytes(1);
|
||||
let u8r = WrappingRange { start: 0, end: 255 };
|
||||
let i8r = WrappingRange { start: 128, end: 127 };
|
||||
assert!(u8r.contains_range(i8r, size1));
|
||||
assert!(i8r.contains_range(u8r, size1));
|
||||
assert!(!u8r.contains_range(i8r, size16));
|
||||
assert!(i8r.contains_range(u8r, size16));
|
||||
|
||||
let boolr = WrappingRange { start: 0, end: 1 };
|
||||
assert!(u8r.contains_range(boolr, size1));
|
||||
assert!(i8r.contains_range(boolr, size1));
|
||||
assert!(!boolr.contains_range(u8r, size1));
|
||||
assert!(!boolr.contains_range(i8r, size1));
|
||||
|
||||
let cmpr = WrappingRange { start: 255, end: 1 };
|
||||
assert!(u8r.contains_range(cmpr, size1));
|
||||
assert!(i8r.contains_range(cmpr, size1));
|
||||
assert!(!cmpr.contains_range(u8r, size1));
|
||||
assert!(!cmpr.contains_range(i8r, size1));
|
||||
|
||||
assert!(!boolr.contains_range(cmpr, size1));
|
||||
assert!(cmpr.contains_range(boolr, size1));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,10 +115,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
fn append_to_grouped_errors(
|
||||
&self,
|
||||
grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
|
||||
error: MoveError<'tcx>,
|
||||
MoveError { place: original_path, location, kind }: MoveError<'tcx>,
|
||||
) {
|
||||
let MoveError { place: original_path, location, kind } = error;
|
||||
|
||||
// Note: that the only time we assign a place isn't a temporary
|
||||
// to a user variable is when initializing it.
|
||||
// If that ever stops being the case, then the ever initialized
|
||||
|
|
@ -251,54 +249,47 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
|
||||
fn report(&mut self, error: GroupedMoveError<'tcx>) {
|
||||
let (mut err, err_span) = {
|
||||
let (span, use_spans, original_path, kind) = match error {
|
||||
GroupedMoveError::MovesFromPlace { span, original_path, ref kind, .. }
|
||||
| GroupedMoveError::MovesFromValue { span, original_path, ref kind, .. } => {
|
||||
(span, None, original_path, kind)
|
||||
}
|
||||
GroupedMoveError::OtherIllegalMove { use_spans, original_path, ref kind } => {
|
||||
(use_spans.args_or_use(), Some(use_spans), original_path, kind)
|
||||
}
|
||||
};
|
||||
debug!(
|
||||
"report: original_path={:?} span={:?}, kind={:?} \
|
||||
original_path.is_upvar_field_projection={:?}",
|
||||
original_path,
|
||||
span,
|
||||
kind,
|
||||
self.is_upvar_field_projection(original_path.as_ref())
|
||||
);
|
||||
if self.has_ambiguous_copy(original_path.ty(self.body, self.infcx.tcx).ty) {
|
||||
// If the type may implement Copy, skip the error.
|
||||
// It's an error with the Copy implementation (e.g. duplicate Copy) rather than borrow check
|
||||
self.dcx().span_delayed_bug(
|
||||
span,
|
||||
"Type may implement copy, but there is no other error.",
|
||||
);
|
||||
return;
|
||||
let (span, use_spans, original_path, kind) = match error {
|
||||
GroupedMoveError::MovesFromPlace { span, original_path, ref kind, .. }
|
||||
| GroupedMoveError::MovesFromValue { span, original_path, ref kind, .. } => {
|
||||
(span, None, original_path, kind)
|
||||
}
|
||||
GroupedMoveError::OtherIllegalMove { use_spans, original_path, ref kind } => {
|
||||
(use_spans.args_or_use(), Some(use_spans), original_path, kind)
|
||||
}
|
||||
};
|
||||
debug!(
|
||||
"report: original_path={:?} span={:?}, kind={:?} \
|
||||
original_path.is_upvar_field_projection={:?}",
|
||||
original_path,
|
||||
span,
|
||||
kind,
|
||||
self.is_upvar_field_projection(original_path.as_ref())
|
||||
);
|
||||
if self.has_ambiguous_copy(original_path.ty(self.body, self.infcx.tcx).ty) {
|
||||
// If the type may implement Copy, skip the error.
|
||||
// It's an error with the Copy implementation (e.g. duplicate Copy) rather than borrow check
|
||||
self.dcx()
|
||||
.span_delayed_bug(span, "Type may implement copy, but there is no other error.");
|
||||
return;
|
||||
}
|
||||
let mut err = match kind {
|
||||
&IllegalMoveOriginKind::BorrowedContent { target_place } => self
|
||||
.report_cannot_move_from_borrowed_content(
|
||||
original_path,
|
||||
target_place,
|
||||
span,
|
||||
use_spans,
|
||||
),
|
||||
&IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
|
||||
self.cannot_move_out_of_interior_of_drop(span, ty)
|
||||
}
|
||||
&IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => {
|
||||
self.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index))
|
||||
}
|
||||
(
|
||||
match kind {
|
||||
&IllegalMoveOriginKind::BorrowedContent { target_place } => self
|
||||
.report_cannot_move_from_borrowed_content(
|
||||
original_path,
|
||||
target_place,
|
||||
span,
|
||||
use_spans,
|
||||
),
|
||||
&IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
|
||||
self.cannot_move_out_of_interior_of_drop(span, ty)
|
||||
}
|
||||
&IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => {
|
||||
self.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index))
|
||||
}
|
||||
},
|
||||
span,
|
||||
)
|
||||
};
|
||||
|
||||
self.add_move_hints(error, &mut err, err_span);
|
||||
self.add_move_hints(error, &mut err, span);
|
||||
self.buffer_error(err);
|
||||
}
|
||||
|
||||
|
|
@ -483,7 +474,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.cannot_move_out_of_interior_noncopy(span, ty, None)
|
||||
}
|
||||
ty::Closure(def_id, closure_args)
|
||||
if def_id.as_local() == Some(self.mir_def_id()) && upvar_field.is_some() =>
|
||||
if def_id.as_local() == Some(self.mir_def_id())
|
||||
&& let Some(upvar_field) = upvar_field =>
|
||||
{
|
||||
let closure_kind_ty = closure_args.as_closure().kind_ty();
|
||||
let closure_kind = match closure_kind_ty.to_opt_closure_kind() {
|
||||
|
|
@ -496,7 +488,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
let capture_description =
|
||||
format!("captured variable in an `{closure_kind}` closure");
|
||||
|
||||
let upvar = &self.upvars[upvar_field.unwrap().index()];
|
||||
let upvar = &self.upvars[upvar_field.index()];
|
||||
let upvar_hir_id = upvar.get_root_variable();
|
||||
let upvar_name = upvar.to_string(tcx);
|
||||
let upvar_span = tcx.hir_span(upvar_hir_id);
|
||||
|
|
@ -606,7 +598,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
// No binding. Nothing to suggest.
|
||||
GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => {
|
||||
let use_span = use_spans.var_or_use();
|
||||
let mut use_span = use_spans.var_or_use();
|
||||
let place_ty = original_path.ty(self.body, self.infcx.tcx).ty;
|
||||
let place_desc = match self.describe_place(original_path.as_ref()) {
|
||||
Some(desc) => format!("`{desc}`"),
|
||||
|
|
@ -623,6 +615,36 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
if let Some(upvar_field) = self
|
||||
.prefixes(original_path.as_ref(), PrefixSet::All)
|
||||
.find_map(|p| self.is_upvar_field_projection(p))
|
||||
{
|
||||
// Look for the introduction of the original binding being moved.
|
||||
let upvar = &self.upvars[upvar_field.index()];
|
||||
let upvar_hir_id = upvar.get_root_variable();
|
||||
use_span = match self.infcx.tcx.parent_hir_node(upvar_hir_id) {
|
||||
hir::Node::Param(param) => {
|
||||
// Instead of pointing at the path where we access the value within a
|
||||
// closure, we point at the type of the outer `fn` argument.
|
||||
param.ty_span
|
||||
}
|
||||
hir::Node::LetStmt(stmt) => match (stmt.ty, stmt.init) {
|
||||
// We point at the type of the outer let-binding.
|
||||
(Some(ty), _) => ty.span,
|
||||
// We point at the initializer of the outer let-binding, but only if it
|
||||
// isn't something that spans multiple lines, like a closure, as the
|
||||
// ASCII art gets messy.
|
||||
(None, Some(init))
|
||||
if !self.infcx.tcx.sess.source_map().is_multiline(init.span) =>
|
||||
{
|
||||
init.span
|
||||
}
|
||||
_ => use_span,
|
||||
},
|
||||
_ => use_span,
|
||||
};
|
||||
}
|
||||
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
|
|
@ -630,12 +652,22 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
span: use_span,
|
||||
});
|
||||
|
||||
let mut pointed_at_span = false;
|
||||
use_spans.args_subdiag(err, |args_span| {
|
||||
if args_span == span || args_span == use_span {
|
||||
pointed_at_span = true;
|
||||
}
|
||||
crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
|
||||
place: place_desc,
|
||||
place: place_desc.clone(),
|
||||
args_span,
|
||||
}
|
||||
});
|
||||
if !pointed_at_span && use_span != span {
|
||||
err.subdiagnostic(crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
|
||||
place: place_desc,
|
||||
args_span: span,
|
||||
});
|
||||
}
|
||||
|
||||
self.add_note_for_packed_struct_derive(err, original_path.local);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
// valid ranges. For example, `char`s are passed as just `i32`, with no
|
||||
// way for LLVM to know that they're 0x10FFFF at most. Thus we assume
|
||||
// the range of the input value too, not just the output range.
|
||||
assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
|
||||
assume_scalar_range(bx, imm, from_scalar, from_backend_ty, None);
|
||||
|
||||
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
|
||||
(Int(_, is_signed), Int(..)) => bx.intcast(imm, to_backend_ty, is_signed),
|
||||
|
|
@ -1064,7 +1064,7 @@ pub(super) fn transmute_scalar<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// That said, last time we tried removing this, it didn't actually help
|
||||
// the rustc-perf results, so might as well keep doing it
|
||||
// <https://github.com/rust-lang/rust/pull/135610#issuecomment-2599275182>
|
||||
assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
|
||||
assume_scalar_range(bx, imm, from_scalar, from_backend_ty, Some(&to_scalar));
|
||||
|
||||
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
|
||||
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
|
||||
|
|
@ -1092,22 +1092,42 @@ pub(super) fn transmute_scalar<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// since it's never passed to something with parameter metadata (especially
|
||||
// after MIR inlining) so the only way to tell the backend about the
|
||||
// constraint that the `transmute` introduced is to `assume` it.
|
||||
assume_scalar_range(bx, imm, to_scalar, to_backend_ty);
|
||||
assume_scalar_range(bx, imm, to_scalar, to_backend_ty, Some(&from_scalar));
|
||||
|
||||
imm = bx.to_immediate_scalar(imm, to_scalar);
|
||||
imm
|
||||
}
|
||||
|
||||
/// Emits an `assume` call that `imm`'s value is within the known range of `scalar`.
|
||||
///
|
||||
/// If `known` is `Some`, only emits the assume if it's more specific than
|
||||
/// whatever is already known from the range of *that* scalar.
|
||||
fn assume_scalar_range<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
imm: Bx::Value,
|
||||
scalar: abi::Scalar,
|
||||
backend_ty: Bx::Type,
|
||||
known: Option<&abi::Scalar>,
|
||||
) {
|
||||
if matches!(bx.cx().sess().opts.optimize, OptLevel::No) || scalar.is_always_valid(bx.cx()) {
|
||||
if matches!(bx.cx().sess().opts.optimize, OptLevel::No) {
|
||||
return;
|
||||
}
|
||||
|
||||
match (scalar, known) {
|
||||
(abi::Scalar::Union { .. }, _) => return,
|
||||
(_, None) => {
|
||||
if scalar.is_always_valid(bx.cx()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
(abi::Scalar::Initialized { valid_range, .. }, Some(known)) => {
|
||||
let known_range = known.valid_range(bx.cx());
|
||||
if valid_range.contains_range(known_range, scalar.size(bx.cx())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match scalar.primitive() {
|
||||
abi::Primitive::Int(..) => {
|
||||
let range = scalar.valid_range(bx.cx());
|
||||
|
|
|
|||
|
|
@ -1642,20 +1642,40 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
|
||||
if def.repr().int.is_none() {
|
||||
let is_unit = |var: &ty::VariantDef| matches!(var.ctor_kind(), Some(CtorKind::Const));
|
||||
let has_disr = |var: &ty::VariantDef| matches!(var.discr, ty::VariantDiscr::Explicit(_));
|
||||
let get_disr = |var: &ty::VariantDef| match var.discr {
|
||||
ty::VariantDiscr::Explicit(disr) => Some(disr),
|
||||
ty::VariantDiscr::Relative(_) => None,
|
||||
};
|
||||
|
||||
let has_non_units = def.variants().iter().any(|var| !is_unit(var));
|
||||
let disr_units = def.variants().iter().any(|var| is_unit(var) && has_disr(var));
|
||||
let disr_non_unit = def.variants().iter().any(|var| !is_unit(var) && has_disr(var));
|
||||
let non_unit = def.variants().iter().find(|var| !is_unit(var));
|
||||
let disr_unit =
|
||||
def.variants().iter().filter(|var| is_unit(var)).find_map(|var| get_disr(var));
|
||||
let disr_non_unit =
|
||||
def.variants().iter().filter(|var| !is_unit(var)).find_map(|var| get_disr(var));
|
||||
|
||||
if disr_non_unit || (disr_units && has_non_units) {
|
||||
struct_span_code_err!(
|
||||
if disr_non_unit.is_some() || (disr_unit.is_some() && non_unit.is_some()) {
|
||||
let mut err = struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
tcx.def_span(def_id),
|
||||
E0732,
|
||||
"`#[repr(inttype)]` must be specified"
|
||||
)
|
||||
.emit();
|
||||
"`#[repr(inttype)]` must be specified for enums with explicit discriminants and non-unit variants"
|
||||
);
|
||||
if let Some(disr_non_unit) = disr_non_unit {
|
||||
err.span_label(
|
||||
tcx.def_span(disr_non_unit),
|
||||
"explicit discriminant on non-unit variant specified here",
|
||||
);
|
||||
} else {
|
||||
err.span_label(
|
||||
tcx.def_span(disr_unit.unwrap()),
|
||||
"explicit discriminant specified here",
|
||||
);
|
||||
err.span_label(
|
||||
tcx.def_span(non_unit.unwrap().def_id),
|
||||
"non-unit discriminant declared here",
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1302,8 +1302,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
None => ".clone()".to_string(),
|
||||
};
|
||||
|
||||
let span = expr.span.find_oldest_ancestor_in_same_ctxt().shrink_to_hi();
|
||||
|
||||
diag.span_suggestion_verbose(
|
||||
expr.span.shrink_to_hi(),
|
||||
span,
|
||||
"consider using clone here",
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
|
|
|
|||
|
|
@ -654,9 +654,7 @@ impl Rvalue {
|
|||
)),
|
||||
AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)),
|
||||
AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())),
|
||||
AggregateKind::Coroutine(def, ref args, mov) => {
|
||||
Ok(Ty::new_coroutine(def, args.clone(), mov))
|
||||
}
|
||||
AggregateKind::Coroutine(def, ref args) => Ok(Ty::new_coroutine(def, args.clone())),
|
||||
AggregateKind::CoroutineClosure(def, ref args) => {
|
||||
Ok(Ty::new_coroutine_closure(def, args.clone()))
|
||||
}
|
||||
|
|
@ -674,8 +672,7 @@ pub enum AggregateKind {
|
|||
Tuple,
|
||||
Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
|
||||
Closure(ClosureDef, GenericArgs),
|
||||
// FIXME(rustc_public): Movability here is redundant
|
||||
Coroutine(CoroutineDef, GenericArgs, Movability),
|
||||
Coroutine(CoroutineDef, GenericArgs),
|
||||
CoroutineClosure(CoroutineClosureDef, GenericArgs),
|
||||
RawPtr(Ty, Mutability),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -428,7 +428,7 @@ fn pretty_aggregate<W: Write>(
|
|||
write!(writer, "{{closure@{}}}(", def.span().diagnostic())?;
|
||||
")"
|
||||
}
|
||||
AggregateKind::Coroutine(def, _, _) => {
|
||||
AggregateKind::Coroutine(def, _) => {
|
||||
write!(writer, "{{coroutine@{}}}(", def.span().diagnostic())?;
|
||||
")"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ impl Ty {
|
|||
}
|
||||
|
||||
/// Create a new coroutine type.
|
||||
pub fn new_coroutine(def: CoroutineDef, args: GenericArgs, mov: Movability) -> Ty {
|
||||
Ty::from_rigid_kind(RigidTy::Coroutine(def, args, mov))
|
||||
pub fn new_coroutine(def: CoroutineDef, args: GenericArgs) -> Ty {
|
||||
Ty::from_rigid_kind(RigidTy::Coroutine(def, args))
|
||||
}
|
||||
|
||||
/// Create a new closure type.
|
||||
|
|
@ -560,8 +560,7 @@ pub enum RigidTy {
|
|||
FnDef(FnDef, GenericArgs),
|
||||
FnPtr(PolyFnSig),
|
||||
Closure(ClosureDef, GenericArgs),
|
||||
// FIXME(rustc_public): Movability here is redundant
|
||||
Coroutine(CoroutineDef, GenericArgs, Movability),
|
||||
Coroutine(CoroutineDef, GenericArgs),
|
||||
CoroutineClosure(CoroutineClosureDef, GenericArgs),
|
||||
Dynamic(Vec<Binder<ExistentialPredicate>>, Region, DynKind),
|
||||
Never,
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ impl RustcInternal for RigidTy {
|
|||
RigidTy::Closure(def, args) => {
|
||||
rustc_ty::TyKind::Closure(def.0.internal(tables, tcx), args.internal(tables, tcx))
|
||||
}
|
||||
RigidTy::Coroutine(def, args, _mov) => {
|
||||
RigidTy::Coroutine(def, args) => {
|
||||
rustc_ty::TyKind::Coroutine(def.0.internal(tables, tcx), args.internal(tables, tcx))
|
||||
}
|
||||
RigidTy::CoroutineClosure(def, args) => rustc_ty::TyKind::CoroutineClosure(
|
||||
|
|
|
|||
|
|
@ -653,7 +653,6 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
|
|||
crate::mir::AggregateKind::Coroutine(
|
||||
tables.coroutine_def(*def_id),
|
||||
generic_arg.stable(tables, cx),
|
||||
cx.coroutine_movability(*def_id).stable(tables, cx),
|
||||
)
|
||||
}
|
||||
mir::AggregateKind::CoroutineClosure(def_id, generic_args) => {
|
||||
|
|
|
|||
|
|
@ -457,7 +457,6 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
|
|||
ty::Coroutine(def_id, generic_args) => TyKind::RigidTy(RigidTy::Coroutine(
|
||||
tables.coroutine_def(*def_id),
|
||||
generic_args.stable(tables, cx),
|
||||
cx.coroutine_movability(*def_id).stable(tables, cx),
|
||||
)),
|
||||
ty::Never => TyKind::RigidTy(RigidTy::Never),
|
||||
ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple(
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ impl Visitable for RigidTy {
|
|||
}
|
||||
RigidTy::Adt(_, args)
|
||||
| RigidTy::Closure(_, args)
|
||||
| RigidTy::Coroutine(_, args, _)
|
||||
| RigidTy::Coroutine(_, args)
|
||||
| RigidTy::CoroutineWitness(_, args)
|
||||
| RigidTy::CoroutineClosure(_, args)
|
||||
| RigidTy::FnDef(_, args) => args.visit(visitor),
|
||||
|
|
|
|||
|
|
@ -1076,11 +1076,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Scope::CrateRoot => {
|
||||
let root_ident = Ident::new(kw::PathRoot, ident.span);
|
||||
let root_module = this.resolve_crate_root(root_ident);
|
||||
this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
|
||||
}
|
||||
Scope::Module(module, _) => {
|
||||
this.add_module_candidates(module, &mut suggestions, filter_fn, None);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,20 +93,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
// 6. Language prelude: builtin attributes (closed, controlled).
|
||||
|
||||
let rust_2015 = ctxt.edition().is_rust_2015();
|
||||
let (ns, macro_kind, is_absolute_path) = match scope_set {
|
||||
ScopeSet::All(ns) => (ns, None, false),
|
||||
ScopeSet::AbsolutePath(ns) => (ns, None, true),
|
||||
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
|
||||
ScopeSet::Late(ns, ..) => (ns, None, false),
|
||||
let (ns, macro_kind) = match scope_set {
|
||||
ScopeSet::All(ns)
|
||||
| ScopeSet::ModuleAndExternPrelude(ns, _)
|
||||
| ScopeSet::Late(ns, ..) => (ns, None),
|
||||
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)),
|
||||
};
|
||||
let module = match scope_set {
|
||||
// Start with the specified module.
|
||||
ScopeSet::Late(_, module, _) => module,
|
||||
ScopeSet::Late(_, module, _) | ScopeSet::ModuleAndExternPrelude(_, module) => module,
|
||||
// Jump out of trait or enum modules, they do not act as scopes.
|
||||
_ => parent_scope.module.nearest_item_scope(),
|
||||
};
|
||||
let module_and_extern_prelude = matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..));
|
||||
let mut scope = match ns {
|
||||
_ if is_absolute_path => Scope::CrateRoot,
|
||||
_ if module_and_extern_prelude => Scope::Module(module, None),
|
||||
TypeNS | ValueNS => Scope::Module(module, None),
|
||||
MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
|
||||
};
|
||||
|
|
@ -134,11 +135,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
}
|
||||
true
|
||||
}
|
||||
Scope::CrateRoot => true,
|
||||
Scope::Module(..) => true,
|
||||
Scope::MacroUsePrelude => use_prelude || rust_2015,
|
||||
Scope::BuiltinAttrs => true,
|
||||
Scope::ExternPrelude => use_prelude || is_absolute_path,
|
||||
Scope::ExternPrelude => use_prelude || module_and_extern_prelude,
|
||||
Scope::ToolPrelude => use_prelude,
|
||||
Scope::StdLibPrelude => use_prelude || ns == MacroNS,
|
||||
Scope::BuiltinTypes => true,
|
||||
|
|
@ -174,7 +174,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
}
|
||||
MacroRulesScope::Empty => Scope::Module(module, None),
|
||||
},
|
||||
Scope::CrateRoot => match ns {
|
||||
Scope::Module(..) if module_and_extern_prelude => match ns {
|
||||
TypeNS => {
|
||||
ctxt.adjust(ExpnId::root());
|
||||
Scope::ExternPrelude
|
||||
|
|
@ -203,7 +203,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
}
|
||||
Scope::MacroUsePrelude => Scope::StdLibPrelude,
|
||||
Scope::BuiltinAttrs => break, // nowhere else to search
|
||||
Scope::ExternPrelude if is_absolute_path => break,
|
||||
Scope::ExternPrelude if module_and_extern_prelude => break,
|
||||
Scope::ExternPrelude => Scope::ToolPrelude,
|
||||
Scope::ToolPrelude => Scope::StdLibPrelude,
|
||||
Scope::StdLibPrelude => match ns {
|
||||
|
|
@ -404,10 +404,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
}
|
||||
|
||||
let (ns, macro_kind) = match scope_set {
|
||||
ScopeSet::All(ns) => (ns, None),
|
||||
ScopeSet::AbsolutePath(ns) => (ns, None),
|
||||
ScopeSet::All(ns)
|
||||
| ScopeSet::ModuleAndExternPrelude(ns, _)
|
||||
| ScopeSet::Late(ns, ..) => (ns, None),
|
||||
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)),
|
||||
ScopeSet::Late(ns, ..) => (ns, None),
|
||||
};
|
||||
|
||||
// This is *the* result, resolution from the scope closest to the resolved identifier.
|
||||
|
|
@ -487,31 +487,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined),
|
||||
_ => Err(Determinacy::Determined),
|
||||
},
|
||||
Scope::CrateRoot => {
|
||||
let root_ident = Ident::new(kw::PathRoot, ident.span);
|
||||
let root_module = this.resolve_crate_root(root_ident);
|
||||
let binding = this.resolve_ident_in_module(
|
||||
ModuleOrUniformRoot::Module(root_module),
|
||||
ident,
|
||||
ns,
|
||||
parent_scope,
|
||||
finalize,
|
||||
ignore_binding,
|
||||
ignore_import,
|
||||
);
|
||||
match binding {
|
||||
Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)),
|
||||
Err((Determinacy::Undetermined, Weak::No)) => {
|
||||
return Some(Err(Determinacy::determined(force)));
|
||||
}
|
||||
Err((Determinacy::Undetermined, Weak::Yes)) => {
|
||||
Err(Determinacy::Undetermined)
|
||||
}
|
||||
Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
|
||||
}
|
||||
}
|
||||
Scope::Module(module, derive_fallback_lint_id) => {
|
||||
let adjusted_parent_scope = &ParentScope { module, ..*parent_scope };
|
||||
let (adjusted_parent_scope, finalize) =
|
||||
if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) {
|
||||
(parent_scope, finalize)
|
||||
} else {
|
||||
(
|
||||
&ParentScope { module, ..*parent_scope },
|
||||
finalize.map(|f| Finalize { used: Used::Scope, ..f }),
|
||||
)
|
||||
};
|
||||
let binding = this.resolve_ident_in_module_unadjusted(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
|
|
@ -522,7 +507,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
} else {
|
||||
Shadowing::Restricted
|
||||
},
|
||||
finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
|
||||
finalize,
|
||||
ignore_binding,
|
||||
ignore_import,
|
||||
);
|
||||
|
|
@ -776,7 +761,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
ModuleOrUniformRoot::ExternPrelude => {
|
||||
ident.span.normalize_to_macros_2_0_and_adjust(ExpnId::root());
|
||||
}
|
||||
ModuleOrUniformRoot::CrateRootAndExternPrelude | ModuleOrUniformRoot::CurrentScope => {
|
||||
ModuleOrUniformRoot::ModuleAndExternPrelude(..) | ModuleOrUniformRoot::CurrentScope => {
|
||||
// No adjustments
|
||||
}
|
||||
}
|
||||
|
|
@ -810,11 +795,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
) -> Result<NameBinding<'ra>, (Determinacy, Weak)> {
|
||||
let module = match module {
|
||||
ModuleOrUniformRoot::Module(module) => module,
|
||||
ModuleOrUniformRoot::CrateRootAndExternPrelude => {
|
||||
ModuleOrUniformRoot::ModuleAndExternPrelude(module) => {
|
||||
assert_eq!(shadowing, Shadowing::Unrestricted);
|
||||
let binding = self.early_resolve_ident_in_lexical_scope(
|
||||
ident,
|
||||
ScopeSet::AbsolutePath(ns),
|
||||
ScopeSet::ModuleAndExternPrelude(ns, module),
|
||||
parent_scope,
|
||||
finalize,
|
||||
finalize.is_some(),
|
||||
|
|
@ -1531,7 +1516,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
&& self.tcx.sess.at_least_rust_2018()
|
||||
{
|
||||
// `::a::b` from 2015 macro on 2018 global edition
|
||||
module = Some(ModuleOrUniformRoot::CrateRootAndExternPrelude);
|
||||
let crate_root = self.resolve_crate_root(ident);
|
||||
module = Some(ModuleOrUniformRoot::ModuleAndExternPrelude(crate_root));
|
||||
continue;
|
||||
}
|
||||
if name == kw::PathRoot || name == kw::Crate || name == kw::DollarCrate {
|
||||
|
|
|
|||
|
|
@ -181,10 +181,10 @@ pub(crate) struct ImportData<'ra> {
|
|||
///
|
||||
/// | `module_path` | `imported_module` | remark |
|
||||
/// |-|-|-|
|
||||
/// |`use prefix::foo`| `ModuleOrUniformRoot::Module(prefix)` | - |
|
||||
/// |`use ::foo` | `ModuleOrUniformRoot::ExternPrelude` | 2018+ editions |
|
||||
/// |`use ::foo` | `ModuleOrUniformRoot::CrateRootAndExternPrelude` | a special case in 2015 edition |
|
||||
/// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - |
|
||||
/// |`use prefix::foo`| `ModuleOrUniformRoot::Module(prefix)` | - |
|
||||
/// |`use ::foo` | `ModuleOrUniformRoot::ExternPrelude` | 2018+ editions |
|
||||
/// |`use ::foo` | `ModuleOrUniformRoot::ModuleAndExternPrelude` | a special case in 2015 edition |
|
||||
/// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - |
|
||||
pub imported_module: Cell<Option<ModuleOrUniformRoot<'ra>>>,
|
||||
pub vis: Visibility,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,6 @@ enum Scope<'ra> {
|
|||
DeriveHelpers(LocalExpnId),
|
||||
DeriveHelpersCompat,
|
||||
MacroRules(MacroRulesScopeRef<'ra>),
|
||||
CrateRoot,
|
||||
// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
|
||||
// lint if it should be reported.
|
||||
Module(Module<'ra>, Option<NodeId>),
|
||||
|
|
@ -139,8 +138,8 @@ enum Scope<'ra> {
|
|||
enum ScopeSet<'ra> {
|
||||
/// All scopes with the given namespace.
|
||||
All(Namespace),
|
||||
/// Crate root, then extern prelude (used for mixed 2015-2018 mode in macros).
|
||||
AbsolutePath(Namespace),
|
||||
/// A module, then extern prelude (used for mixed 2015-2018 mode in macros).
|
||||
ModuleAndExternPrelude(Namespace, Module<'ra>),
|
||||
/// All scopes with macro namespace and the given macro kind restriction.
|
||||
Macro(MacroKind),
|
||||
/// All scopes with the given namespace, used for partially performing late resolution.
|
||||
|
|
@ -419,8 +418,10 @@ enum ModuleOrUniformRoot<'ra> {
|
|||
/// Regular module.
|
||||
Module(Module<'ra>),
|
||||
|
||||
/// Virtual module that denotes resolution in crate root with fallback to extern prelude.
|
||||
CrateRootAndExternPrelude,
|
||||
/// Virtual module that denotes resolution in a module with fallback to extern prelude.
|
||||
/// Used for paths starting with `::` coming from 2015 edition macros
|
||||
/// used in 2018+ edition crates.
|
||||
ModuleAndExternPrelude(Module<'ra>),
|
||||
|
||||
/// Virtual module that denotes resolution in extern prelude.
|
||||
/// Used for paths starting with `::` on 2018 edition.
|
||||
|
|
|
|||
|
|
@ -603,12 +603,6 @@ fn layout_of_uncached<'tcx>(
|
|||
.flatten()
|
||||
};
|
||||
|
||||
let dont_niche_optimize_enum = def.repr().inhibit_enum_layout_opt()
|
||||
|| def
|
||||
.variants()
|
||||
.iter_enumerated()
|
||||
.any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32()));
|
||||
|
||||
let maybe_unsized = def.is_struct()
|
||||
&& def.non_enum_variant().tail_opt().is_some_and(|last_field| {
|
||||
let typing_env = ty::TypingEnv::post_analysis(tcx, def.did());
|
||||
|
|
@ -625,7 +619,6 @@ fn layout_of_uncached<'tcx>(
|
|||
tcx.layout_scalar_valid_range(def.did()),
|
||||
get_discriminant_type,
|
||||
discriminants_iter(),
|
||||
dont_niche_optimize_enum,
|
||||
!maybe_unsized,
|
||||
)
|
||||
.map_err(|err| map_error(cx, ty, err))?;
|
||||
|
|
@ -651,7 +644,6 @@ fn layout_of_uncached<'tcx>(
|
|||
tcx.layout_scalar_valid_range(def.did()),
|
||||
get_discriminant_type,
|
||||
discriminants_iter(),
|
||||
dont_niche_optimize_enum,
|
||||
!maybe_unsized,
|
||||
) else {
|
||||
bug!("failed to compute unsized layout of {ty:?}");
|
||||
|
|
|
|||
|
|
@ -223,20 +223,20 @@ impl<T: ?Sized> BorrowMut<T> for T {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Borrow<T> for &T {
|
||||
fn borrow(&self) -> &T {
|
||||
&**self
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Borrow<T> for &mut T {
|
||||
fn borrow(&self) -> &T {
|
||||
&**self
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> BorrowMut<T> for &mut T {
|
||||
fn borrow_mut(&mut self) -> &mut T {
|
||||
&mut **self
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -590,7 +590,7 @@ mod impls {
|
|||
#[inline(always)]
|
||||
#[rustc_diagnostic_item = "noop_method_clone"]
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -960,7 +960,7 @@ pub fn drop<T>(_x: T) {}
|
|||
///
|
||||
/// This function is not magic; it is literally defined as
|
||||
/// ```
|
||||
/// pub fn copy<T: Copy>(x: &T) -> T { *x }
|
||||
/// pub const fn copy<T: Copy>(x: &T) -> T { *x }
|
||||
/// ```
|
||||
///
|
||||
/// It is useful when you want to pass a function pointer to a combinator, rather than defining a new closure.
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ impl<T: ?Sized> const Deref for &T {
|
|||
|
||||
#[rustc_diagnostic_item = "noop_method_deref"]
|
||||
fn deref(&self) -> &T {
|
||||
*self
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ impl<T: ?Sized> const Deref for &mut T {
|
|||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
*self
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -280,7 +280,7 @@ pub trait DerefMut: ~const Deref + PointeeSized {
|
|||
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
|
||||
impl<T: ?Sized> const DerefMut for &mut T {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
*self
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,8 +101,7 @@ fn partition_at_index_loop<'a, T, F>(
|
|||
// slice. Partition the slice into elements equal to and elements greater than the pivot.
|
||||
// This case is usually hit when the slice contains many duplicate elements.
|
||||
if let Some(p) = ancestor_pivot {
|
||||
// SAFETY: choose_pivot promises to return a valid pivot position.
|
||||
let pivot = unsafe { v.get_unchecked(pivot_pos) };
|
||||
let pivot = &v[pivot_pos];
|
||||
|
||||
if !is_less(p, pivot) {
|
||||
let num_lt = partition(v, pivot_pos, &mut |a, b| !is_less(b, a));
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! This module contains the logic for pivot selection.
|
||||
|
||||
use crate::intrinsics;
|
||||
use crate::{hint, intrinsics};
|
||||
|
||||
// Recursively select a pseudomedian if above this threshold.
|
||||
const PSEUDO_MEDIAN_REC_THRESHOLD: usize = 64;
|
||||
|
|
@ -9,6 +9,7 @@ const PSEUDO_MEDIAN_REC_THRESHOLD: usize = 64;
|
|||
///
|
||||
/// This chooses a pivot by sampling an adaptive amount of points, approximating
|
||||
/// the quality of a median of sqrt(n) elements.
|
||||
#[inline]
|
||||
pub fn choose_pivot<T, F: FnMut(&T, &T) -> bool>(v: &[T], is_less: &mut F) -> usize {
|
||||
// We use unsafe code and raw pointers here because we're dealing with
|
||||
// heavy recursion. Passing safe slices around would involve a lot of
|
||||
|
|
@ -22,7 +23,7 @@ pub fn choose_pivot<T, F: FnMut(&T, &T) -> bool>(v: &[T], is_less: &mut F) -> us
|
|||
// SAFETY: a, b, c point to initialized regions of len_div_8 elements,
|
||||
// satisfying median3 and median3_rec's preconditions as v_base points
|
||||
// to an initialized region of n = len elements.
|
||||
unsafe {
|
||||
let index = unsafe {
|
||||
let v_base = v.as_ptr();
|
||||
let len_div_8 = len / 8;
|
||||
|
||||
|
|
@ -35,6 +36,11 @@ pub fn choose_pivot<T, F: FnMut(&T, &T) -> bool>(v: &[T], is_less: &mut F) -> us
|
|||
} else {
|
||||
median3_rec(a, b, c, len_div_8, is_less).offset_from_unsigned(v_base)
|
||||
}
|
||||
};
|
||||
// SAFETY: preconditions must have been met for offset_from_unsigned()
|
||||
unsafe {
|
||||
hint::assert_unchecked(index < v.len());
|
||||
index
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,10 +37,6 @@ pub fn quicksort<T, F: FnMut(&T, &T) -> bool>(
|
|||
limit -= 1;
|
||||
|
||||
let pivot_pos = choose_pivot(v, is_less);
|
||||
// SAFETY: choose_pivot promises to return a valid pivot index.
|
||||
unsafe {
|
||||
intrinsics::assume(pivot_pos < v.len());
|
||||
}
|
||||
|
||||
// SAFETY: We only access the temporary copy for Freeze types, otherwise
|
||||
// self-modifications via `is_less` would not be observed and this would
|
||||
|
|
|
|||
|
|
@ -48,8 +48,7 @@ pub(crate) fn quicksort<'a, T, F>(
|
|||
// slice. Partition the slice into elements equal to and elements greater than the pivot.
|
||||
// This case is usually hit when the slice contains many duplicate elements.
|
||||
if let Some(p) = ancestor_pivot {
|
||||
// SAFETY: We assume choose_pivot yields an in-bounds position.
|
||||
if !is_less(p, unsafe { v.get_unchecked(pivot_pos) }) {
|
||||
if !is_less(p, &v[pivot_pos]) {
|
||||
let num_lt = partition(v, pivot_pos, &mut |a, b| !is_less(b, a));
|
||||
|
||||
// Continue sorting elements greater than the pivot. We know that `num_lt` contains
|
||||
|
|
|
|||
|
|
@ -309,7 +309,8 @@ fn main((ؼ
|
|||
|
||||
Use `//~?` to match an error without line information.
|
||||
`//~?` is precise and will not match errors if their line information is available.
|
||||
It should be preferred to using `error-pattern`, which is imprecise and non-exhaustive.
|
||||
For tests wishing to match against compiler diagnostics, error annotations should
|
||||
be preferred over //@ error-pattern, //@ error-pattern is imprecise and non-exhaustive.
|
||||
|
||||
```rust,ignore
|
||||
//@ compile-flags: --print yyyy
|
||||
|
|
@ -347,8 +348,6 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
Use of `error-pattern` is not recommended in general.
|
||||
|
||||
For strict testing of compile time output, try to use the line annotations `//~` as much as
|
||||
possible, including `//~?` annotations for diagnostics without spans.
|
||||
|
||||
|
|
@ -359,7 +358,8 @@ Some of the compiler messages can stay uncovered by annotations in this mode.
|
|||
|
||||
For checking runtime output, `//@ check-run-results` may be preferable.
|
||||
|
||||
Only use `error-pattern` if none of the above works.
|
||||
Only use `error-pattern` if none of the above works, such as when finding a
|
||||
specific string pattern in a runtime panic output.
|
||||
|
||||
Line annotations `//~` and `error-pattern` are compatible and can be used in the same test.
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
use std::{cmp, ops::Bound};
|
||||
|
||||
use hir_def::{
|
||||
AdtId, VariantId,
|
||||
layout::{Integer, ReprOptions, TargetDataLayout},
|
||||
signatures::{StructFlags, VariantFields},
|
||||
AdtId, VariantId,
|
||||
};
|
||||
use intern::sym;
|
||||
use rustc_index::IndexVec;
|
||||
|
|
@ -13,9 +13,9 @@ use smallvec::SmallVec;
|
|||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
Substitution, TraitEnvironment,
|
||||
db::HirDatabase,
|
||||
layout::{Layout, LayoutError, field_ty},
|
||||
layout::{field_ty, Layout, LayoutError},
|
||||
Substitution, TraitEnvironment,
|
||||
};
|
||||
|
||||
use super::LayoutCx;
|
||||
|
|
@ -85,16 +85,6 @@ pub fn layout_of_adt_query(
|
|||
let d = db.const_eval_discriminant(e.enum_variants(db).variants[id.0].0).ok()?;
|
||||
Some((id, d))
|
||||
}),
|
||||
// FIXME: The current code for niche-filling relies on variant indices
|
||||
// instead of actual discriminants, so enums with
|
||||
// explicit discriminants (RFC #2363) would misbehave and we should disable
|
||||
// niche optimization for them.
|
||||
// The code that do it in rustc:
|
||||
// repr.inhibit_enum_layout_opt() || def
|
||||
// .variants()
|
||||
// .iter_enumerated()
|
||||
// .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32()))
|
||||
repr.inhibit_enum_layout_opt(),
|
||||
!matches!(def, AdtId::EnumId(..))
|
||||
&& variants
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -163,11 +163,8 @@ pub unsafe fn check_swap_pair(x: (char, NonZero<u32>)) -> (NonZero<u32>, char) {
|
|||
pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool {
|
||||
// CHECK-NOT: icmp
|
||||
// CHECK-NOT: assume
|
||||
// OPT: %0 = sub i8 %x, -1
|
||||
// OPT: %1 = icmp ule i8 %0, 2
|
||||
// OPT: call void @llvm.assume(i1 %1)
|
||||
// OPT: %2 = icmp ule i8 %x, 1
|
||||
// OPT: call void @llvm.assume(i1 %2)
|
||||
// OPT: %0 = icmp ule i8 %x, 1
|
||||
// OPT: call void @llvm.assume(i1 %0)
|
||||
// CHECK-NOT: icmp
|
||||
// CHECK-NOT: assume
|
||||
// CHECK: %[[R:.+]] = trunc{{( nuw)?}} i8 %x to i1
|
||||
|
|
@ -184,9 +181,6 @@ pub unsafe fn check_bool_to_ordering(x: bool) -> std::cmp::Ordering {
|
|||
// CHECK-NOT: assume
|
||||
// OPT: %0 = icmp ule i8 %_0, 1
|
||||
// OPT: call void @llvm.assume(i1 %0)
|
||||
// OPT: %1 = sub i8 %_0, -1
|
||||
// OPT: %2 = icmp ule i8 %1, 2
|
||||
// OPT: call void @llvm.assume(i1 %2)
|
||||
// CHECK-NOT: icmp
|
||||
// CHECK-NOT: assume
|
||||
// CHECK: ret i8 %_0
|
||||
|
|
@ -221,3 +215,42 @@ pub unsafe fn check_ptr_to_nonnull(x: *const u8) -> NonNull<u8> {
|
|||
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
#[repr(usize)]
|
||||
pub enum FourOrEight {
|
||||
Four = 4,
|
||||
Eight = 8,
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @check_nonnull_to_four_or_eight(
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_nonnull_to_four_or_eight(x: NonNull<u8>) -> FourOrEight {
|
||||
// CHECK: start
|
||||
// CHECK-NEXT: %[[RET:.+]] = ptrtoint ptr %x to i64
|
||||
// CHECK-NOT: icmp
|
||||
// CHECK-NOT: assume
|
||||
// OPT: %0 = sub i64 %[[RET]], 4
|
||||
// OPT: %1 = icmp ule i64 %0, 4
|
||||
// OPT: call void @llvm.assume(i1 %1)
|
||||
// CHECK-NOT: icmp
|
||||
// CHECK-NOT: assume
|
||||
// CHECK: ret i64 %[[RET]]
|
||||
|
||||
transmute(x)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @check_four_or_eight_to_nonnull(
|
||||
#[no_mangle]
|
||||
pub unsafe fn check_four_or_eight_to_nonnull(x: FourOrEight) -> NonNull<u8> {
|
||||
// CHECK-NOT: icmp
|
||||
// CHECK-NOT: assume
|
||||
// OPT: %0 = sub i64 %x, 4
|
||||
// OPT: %1 = icmp ule i64 %0, 4
|
||||
// OPT: call void @llvm.assume(i1 %1)
|
||||
// CHECK-NOT: icmp
|
||||
// CHECK-NOT: assume
|
||||
// CHECK: %[[RET:.+]] = getelementptr i8, ptr null, i64 %x
|
||||
// CHECK-NEXT: ret ptr %[[RET]]
|
||||
|
||||
transmute(x)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
error[E0507]: cannot move out of `x` which is behind a mutable reference
|
||||
--> $DIR/closure-shim-borrowck-error.rs:11:18
|
||||
|
|
||||
LL | fn hello(x: Ty) {
|
||||
| -- move occurs because `x` has type `Ty`, which does not implement the `Copy` trait
|
||||
LL | needs_fn_mut(async || {
|
||||
| ^^^^^^^^ `x` is moved here
|
||||
LL |
|
||||
LL | x.hello();
|
||||
| -
|
||||
| |
|
||||
| variable moved due to use in coroutine
|
||||
| move occurs because `x` has type `Ty`, which does not implement the `Copy` trait
|
||||
| - variable moved due to use in coroutine
|
||||
|
|
||||
note: if `Ty` implemented `Clone`, you could clone the value
|
||||
--> $DIR/closure-shim-borrowck-error.rs:17:1
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
error[E0507]: cannot move out of `*x` which is behind a shared reference
|
||||
--> $DIR/move-out-of-ref.rs:9:9
|
||||
|
|
||||
LL | fn hello(x: &Ty) {
|
||||
| --- move occurs because `*x` has type `Ty`, which does not implement the `Copy` trait
|
||||
LL | let c = async || {
|
||||
LL | *x;
|
||||
| ^^ move occurs because `*x` has type `Ty`, which does not implement the `Copy` trait
|
||||
| ^^ `*x` is moved here
|
||||
|
|
||||
note: if `Ty` implemented `Clone`, you could clone the value
|
||||
--> $DIR/move-out-of-ref.rs:5:1
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ use std::str;
|
|||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() >= 2 && args[1] == "force" {
|
||||
println!("stack backtrace:\n{}", std::backtrace::Backtrace::force_capture());
|
||||
println!("{}", std::backtrace::Backtrace::force_capture());
|
||||
} else if args.len() >= 2 {
|
||||
println!("stack backtrace:\n{}", std::backtrace::Backtrace::capture());
|
||||
println!("{}", std::backtrace::Backtrace::capture());
|
||||
} else {
|
||||
runtest(&args[0]);
|
||||
println!("test ok");
|
||||
|
|
@ -28,7 +28,6 @@ fn runtest(me: &str) {
|
|||
|
||||
let p = Command::new(me).arg("a").env("RUST_BACKTRACE", "1").output().unwrap();
|
||||
assert!(p.status.success());
|
||||
assert!(String::from_utf8_lossy(&p.stdout).contains("stack backtrace:\n"));
|
||||
assert!(String::from_utf8_lossy(&p.stdout).contains("backtrace::main"));
|
||||
|
||||
let p = Command::new(me).arg("a").env("RUST_BACKTRACE", "0").output().unwrap();
|
||||
|
|
@ -46,7 +45,6 @@ fn runtest(me: &str) {
|
|||
.output()
|
||||
.unwrap();
|
||||
assert!(p.status.success());
|
||||
assert!(String::from_utf8_lossy(&p.stdout).contains("stack backtrace:\n"));
|
||||
|
||||
let p = Command::new(me)
|
||||
.arg("a")
|
||||
|
|
@ -64,9 +62,7 @@ fn runtest(me: &str) {
|
|||
.output()
|
||||
.unwrap();
|
||||
assert!(p.status.success());
|
||||
assert!(String::from_utf8_lossy(&p.stdout).contains("stack backtrace:\n"));
|
||||
|
||||
let p = Command::new(me).arg("force").output().unwrap();
|
||||
assert!(p.status.success());
|
||||
assert!(String::from_utf8_lossy(&p.stdout).contains("stack backtrace:\n"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
|
|||
--> $DIR/borrowck-in-static.rs:5:17
|
||||
|
|
||||
LL | let x = Box::new(0);
|
||||
| - captured outer variable
|
||||
| - ----------- move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| captured outer variable
|
||||
LL | Box::new(|| x)
|
||||
| -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
|
||||
| -- ^ `x` is moved here
|
||||
| |
|
||||
| captured by this `Fn` closure
|
||||
|
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closur
|
|||
--> $DIR/borrowck-move-by-capture.rs:9:29
|
||||
|
|
||||
LL | let bar: Box<_> = Box::new(3);
|
||||
| --- captured outer variable
|
||||
| --- ------ move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| captured outer variable
|
||||
LL | let _g = to_fn_mut(|| {
|
||||
| -- captured by this `FnMut` closure
|
||||
LL | let _h = to_fn_once(move || -> isize { *bar });
|
||||
| ^^^^^^^^^^^^^^^^ ----
|
||||
| | |
|
||||
| | variable moved due to use in closure
|
||||
| | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
|
||||
| ^^^^^^^^^^^^^^^^ ---- variable moved due to use in closure
|
||||
| |
|
||||
| `bar` is moved here
|
||||
|
|
||||
help: consider cloning the value before moving it into the closure
|
||||
|
|
|
|||
|
|
@ -2,13 +2,16 @@ error[E0507]: cannot move out of `self.b`, as `self` is a captured variable in a
|
|||
--> $DIR/issue-103624.rs:16:13
|
||||
|
|
||||
LL | async fn foo(&self) {
|
||||
| ----- captured outer variable
|
||||
| -----
|
||||
| |
|
||||
| captured outer variable
|
||||
| move occurs because `self.b` has type `StructB`, which does not implement the `Copy` trait
|
||||
LL | let bar = self.b.bar().await;
|
||||
LL | spawn_blocking(move || {
|
||||
| ------- captured by this `Fn` closure
|
||||
LL |
|
||||
LL | self.b;
|
||||
| ^^^^^^ move occurs because `self.b` has type `StructB`, which does not implement the `Copy` trait
|
||||
| ^^^^^^ `self.b` is moved here
|
||||
|
|
||||
note: if `StructB` implemented `Clone`, you could clone the value
|
||||
--> $DIR/issue-103624.rs:23:1
|
||||
|
|
|
|||
|
|
@ -38,3 +38,6 @@ pub fn main() { }
|
|||
|
||||
#[cfg(target_arch = "loongarch64")]
|
||||
pub fn main() { }
|
||||
|
||||
#[cfg(target_arch = "arm64ec")]
|
||||
pub fn main() { }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
#![crate_type="lib"]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// Test that if any variant is non-unit,
|
||||
// we need a repr.
|
||||
enum Enum {
|
||||
//~^ ERROR `#[repr(inttype)]` must be specified
|
||||
Unit = 1,
|
||||
Tuple() = 2,
|
||||
Struct{} = 3,
|
||||
//~^ ERROR `#[repr(inttype)]` must be specified
|
||||
Unit = 1,
|
||||
Tuple(),
|
||||
Struct {},
|
||||
}
|
||||
|
||||
// Test that if any non-unit variant has an explicit
|
||||
// discriminant we need a repr.
|
||||
enum Enum2 {
|
||||
//~^ ERROR `#[repr(inttype)]` must be specified
|
||||
Tuple() = 2,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,23 @@
|
|||
error[E0732]: `#[repr(inttype)]` must be specified
|
||||
--> $DIR/arbitrary_enum_discriminant-no-repr.rs:3:1
|
||||
error[E0732]: `#[repr(inttype)]` must be specified for enums with explicit discriminants and non-unit variants
|
||||
--> $DIR/arbitrary_enum_discriminant-no-repr.rs:5:1
|
||||
|
|
||||
LL | enum Enum {
|
||||
| ^^^^^^^^^
|
||||
LL |
|
||||
LL | Unit = 1,
|
||||
| - explicit discriminant specified here
|
||||
LL | Tuple(),
|
||||
| ----- non-unit discriminant declared here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error[E0732]: `#[repr(inttype)]` must be specified for enums with explicit discriminants and non-unit variants
|
||||
--> $DIR/arbitrary_enum_discriminant-no-repr.rs:14:1
|
||||
|
|
||||
LL | enum Enum2 {
|
||||
| ^^^^^^^^^^
|
||||
LL |
|
||||
LL | Tuple() = 2,
|
||||
| - explicit discriminant on non-unit variant specified here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0732`.
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@ error[E0507]: cannot move out of `*v`, as `v` is a captured variable in an `FnMu
|
|||
--> $DIR/issue-4335.rs:6:20
|
||||
|
|
||||
LL | fn f<'r, T>(v: &'r T) -> Box<dyn FnMut() -> T + 'r> {
|
||||
| - captured outer variable
|
||||
| - ----- move occurs because `*v` has type `T`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| captured outer variable
|
||||
LL | id(Box::new(|| *v))
|
||||
| -- ^^ move occurs because `*v` has type `T`, which does not implement the `Copy` trait
|
||||
| -- ^^ `*v` is moved here
|
||||
| |
|
||||
| captured by this `FnMut` closure
|
||||
|
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//@ compile-flags: --target=x86_64-unknown-linux-gnu -C linker-flavor=msvc --crate-type=rlib
|
||||
//@ needs-llvm-components:
|
||||
//@ needs-llvm-components: x86
|
||||
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@ error[E0507]: cannot move out of `i`, a captured variable in an `Fn` closure
|
|||
--> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:9:28
|
||||
|
|
||||
LL | let i = Box::new(3);
|
||||
| - captured outer variable
|
||||
| - ----------- move occurs because `i` has type `Box<usize>`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| captured outer variable
|
||||
LL | let _f = to_fn(|| test(i));
|
||||
| -- ^ move occurs because `i` has type `Box<usize>`, which does not implement the `Copy` trait
|
||||
| -- ^ `i` is moved here
|
||||
| |
|
||||
| captured by this `Fn` closure
|
||||
|
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@ error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn`
|
|||
--> $DIR/issue-52663-span-decl-captured-variable.rs:8:26
|
||||
|
|
||||
LL | let x = (vec![22], vec![44]);
|
||||
| - captured outer variable
|
||||
| - -------------------- move occurs because `x.0` has type `Vec<i32>`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| captured outer variable
|
||||
LL | expect_fn(|| drop(x.0));
|
||||
| -- ^^^ move occurs because `x.0` has type `Vec<i32>`, which does not implement the `Copy` trait
|
||||
| -- ^^^ `x.0` is moved here
|
||||
| |
|
||||
| captured by this `Fn` closure
|
||||
|
|
||||
|
|
|
|||
|
|
@ -43,12 +43,13 @@ macro_rules! dump_and_die {
|
|||
// rust-lang/rust to test it as well, but sometimes we just gotta keep
|
||||
// landing PRs.
|
||||
//
|
||||
// aarch64-msvc is broken as its backtraces are truncated.
|
||||
// aarch64-msvc/arm64ec-msvc is broken as its backtraces are truncated.
|
||||
// See https://github.com/rust-lang/rust/issues/140489
|
||||
if cfg!(any(target_os = "android",
|
||||
all(target_os = "linux", target_arch = "arm"),
|
||||
all(target_env = "msvc", target_arch = "x86"),
|
||||
all(target_env = "msvc", target_arch = "aarch64"),
|
||||
all(target_env = "msvc", target_arch = "arm64ec"),
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd")) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closur
|
|||
--> $DIR/option-content-move2.rs:11:9
|
||||
|
|
||||
LL | let mut var = None;
|
||||
| ------- captured outer variable
|
||||
| ------- ---- move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| captured outer variable
|
||||
LL | func(|| {
|
||||
| -- captured by this `FnMut` closure
|
||||
LL | // Shouldn't suggest `move ||.as_ref()` here
|
||||
|
|
@ -10,16 +12,15 @@ LL | move || {
|
|||
| ^^^^^^^ `var` is moved here
|
||||
LL |
|
||||
LL | var = Some(NotCopyable);
|
||||
| ---
|
||||
| |
|
||||
| variable moved due to use in closure
|
||||
| move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait
|
||||
| --- variable moved due to use in closure
|
||||
|
||||
error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
|
||||
--> $DIR/option-content-move2.rs:21:9
|
||||
|
|
||||
LL | let mut var = None;
|
||||
| ------- captured outer variable
|
||||
| ------- ---- move occurs because `var` has type `Option<NotCopyableButCloneable>`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| captured outer variable
|
||||
LL | func(|| {
|
||||
| -- captured by this `FnMut` closure
|
||||
LL | // Shouldn't suggest `move ||.as_ref()` nor to `clone()` here
|
||||
|
|
@ -27,10 +28,7 @@ LL | move || {
|
|||
| ^^^^^^^ `var` is moved here
|
||||
LL |
|
||||
LL | var = Some(NotCopyableButCloneable);
|
||||
| ---
|
||||
| |
|
||||
| variable moved due to use in closure
|
||||
| move occurs because `var` has type `Option<NotCopyableButCloneable>`, which does not implement the `Copy` trait
|
||||
| --- variable moved due to use in closure
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -26,17 +26,16 @@ error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closur
|
|||
--> $DIR/option-content-move3.rs:12:9
|
||||
|
|
||||
LL | let var = NotCopyable;
|
||||
| --- captured outer variable
|
||||
| --- ----------- move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| captured outer variable
|
||||
LL | func(|| {
|
||||
| -- captured by this `FnMut` closure
|
||||
LL | // Shouldn't suggest `move ||.as_ref()` here
|
||||
LL | move || {
|
||||
| ^^^^^^^ `var` is moved here
|
||||
LL | let x = var;
|
||||
| ---
|
||||
| |
|
||||
| variable moved due to use in closure
|
||||
| move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait
|
||||
| --- variable moved due to use in closure
|
||||
|
|
||||
note: if `NotCopyable` implemented `Clone`, you could clone the value
|
||||
--> $DIR/option-content-move3.rs:2:1
|
||||
|
|
@ -67,17 +66,16 @@ error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closur
|
|||
--> $DIR/option-content-move3.rs:23:9
|
||||
|
|
||||
LL | let var = NotCopyableButCloneable;
|
||||
| --- captured outer variable
|
||||
| --- ----------------------- move occurs because `var` has type `NotCopyableButCloneable`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| captured outer variable
|
||||
LL | func(|| {
|
||||
| -- captured by this `FnMut` closure
|
||||
LL | // Shouldn't suggest `move ||.as_ref()` here
|
||||
LL | move || {
|
||||
| ^^^^^^^ `var` is moved here
|
||||
LL | let x = var;
|
||||
| ---
|
||||
| |
|
||||
| variable moved due to use in closure
|
||||
| move occurs because `var` has type `NotCopyableButCloneable`, which does not implement the `Copy` trait
|
||||
| --- variable moved due to use in closure
|
||||
|
|
||||
help: consider cloning the value before moving it into the closure
|
||||
|
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
#[derive(Debug, Clone)]
|
||||
struct Struct { field: S }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct S;
|
||||
|
||||
macro_rules! expand {
|
||||
($ident:ident) => { Struct { $ident } }
|
||||
}
|
||||
|
||||
fn test1() {
|
||||
let field = &S;
|
||||
let a: Struct = dbg!(expand!(field)); //~ ERROR mismatched types [E0308]
|
||||
let b: Struct = dbg!(Struct { field }); //~ ERROR mismatched types [E0308]
|
||||
let c: S = dbg!(field); //~ ERROR mismatched types [E0308]
|
||||
let c: S = dbg!(dbg!(field)); //~ ERROR mismatched types [E0308]
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-clone-in-macro-issue-139253.rs:13:34
|
||||
|
|
||||
LL | let a: Struct = dbg!(expand!(field));
|
||||
| ^^^^^ expected `S`, found `&S`
|
||||
|
|
||||
help: consider using clone here
|
||||
|
|
||||
LL | let a: Struct = dbg!(expand!(field: field.clone()));
|
||||
| +++++++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-clone-in-macro-issue-139253.rs:14:35
|
||||
|
|
||||
LL | let b: Struct = dbg!(Struct { field });
|
||||
| ^^^^^ expected `S`, found `&S`
|
||||
|
|
||||
help: consider using clone here
|
||||
|
|
||||
LL | let b: Struct = dbg!(Struct { field: field.clone() });
|
||||
| +++++++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-clone-in-macro-issue-139253.rs:15:16
|
||||
|
|
||||
LL | let c: S = dbg!(field);
|
||||
| ^^^^^^^^^^^ expected `S`, found `&S`
|
||||
|
|
||||
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider using clone here
|
||||
|
|
||||
LL | let c: S = dbg!(field).clone();
|
||||
| ++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-clone-in-macro-issue-139253.rs:16:16
|
||||
|
|
||||
LL | let c: S = dbg!(dbg!(field));
|
||||
| ^^^^^^^^^^^^^^^^^ expected `S`, found `&S`
|
||||
|
|
||||
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider using clone here
|
||||
|
|
||||
LL | let c: S = dbg!(dbg!(field)).clone();
|
||||
| ++++++++
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
|
@ -2,9 +2,11 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
|
|||
--> $DIR/unboxed-closure-illegal-move.rs:15:31
|
||||
|
|
||||
LL | let x = Box::new(0);
|
||||
| - captured outer variable
|
||||
| - ----------- move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| captured outer variable
|
||||
LL | let f = to_fn(|| drop(x));
|
||||
| -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
|
||||
| -- ^ `x` is moved here
|
||||
| |
|
||||
| captured by this `Fn` closure
|
||||
|
|
||||
|
|
@ -17,9 +19,11 @@ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure
|
|||
--> $DIR/unboxed-closure-illegal-move.rs:19:35
|
||||
|
|
||||
LL | let x = Box::new(0);
|
||||
| - captured outer variable
|
||||
| - ----------- move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| captured outer variable
|
||||
LL | let f = to_fn_mut(|| drop(x));
|
||||
| -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
|
||||
| -- ^ `x` is moved here
|
||||
| |
|
||||
| captured by this `FnMut` closure
|
||||
|
|
||||
|
|
@ -32,9 +36,11 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
|
|||
--> $DIR/unboxed-closure-illegal-move.rs:28:36
|
||||
|
|
||||
LL | let x = Box::new(0);
|
||||
| - captured outer variable
|
||||
| - ----------- move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| captured outer variable
|
||||
LL | let f = to_fn(move || drop(x));
|
||||
| ------- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
|
||||
| ------- ^ `x` is moved here
|
||||
| |
|
||||
| captured by this `Fn` closure
|
||||
|
||||
|
|
@ -42,9 +48,11 @@ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure
|
|||
--> $DIR/unboxed-closure-illegal-move.rs:32:40
|
||||
|
|
||||
LL | let x = Box::new(0);
|
||||
| - captured outer variable
|
||||
| - ----------- move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| captured outer variable
|
||||
LL | let f = to_fn_mut(move || drop(x));
|
||||
| ------- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
|
||||
| ------- ^ `x` is moved here
|
||||
| |
|
||||
| captured by this `FnMut` closure
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue