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:
bors 2025-07-25 10:40:01 +00:00
commit a955f1cd09
50 changed files with 512 additions and 262 deletions

View file

@ -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;
}

View file

@ -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 {

View file

@ -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));
}

View file

@ -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);
}

View file

@ -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());

View file

@ -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();
}
}

View file

@ -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,

View file

@ -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),
}

View file

@ -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())?;
")"
}

View file

@ -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,

View file

@ -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(

View file

@ -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) => {

View file

@ -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(

View file

@ -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),

View file

@ -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);
}

View file

@ -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 {

View file

@ -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,
}

View file

@ -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.

View file

@ -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:?}");

View file

@ -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
}
}

View file

@ -590,7 +590,7 @@ mod impls {
#[inline(always)]
#[rustc_diagnostic_item = "noop_method_clone"]
fn clone(&self) -> Self {
*self
self
}
}

View file

@ -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.

View file

@ -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
}
}

View file

@ -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));

View file

@ -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
}
}

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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()

View file

@ -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)
}

View file

@ -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

View file

@ -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

View file

@ -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"));
}

View file

@ -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
|

View file

@ -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

View file

@ -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

View file

@ -38,3 +38,6 @@ pub fn main() { }
#[cfg(target_arch = "loongarch64")]
pub fn main() { }
#[cfg(target_arch = "arm64ec")]
pub fn main() { }

View file

@ -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,
}

View file

@ -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`.

View file

@ -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
|

View file

@ -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]

View file

@ -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
|

View file

@ -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
|

View file

@ -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")) {

View file

@ -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

View file

@ -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
|

View file

@ -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() {}

View file

@ -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`.

View file

@ -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