Skip to content

Commit 29c5a02

Browse files
committed
Auto merge of rust-lang#99309 - RalfJung:no-large-copies, r=oli-obk
interpret: make some large types not Copy Also remove some unused trait impls (mostly HashStable). This didn't find any unnecessary copies that I managed to avoid, but it might still be better to require explicit clone for these types? Not sure. r? `@oli-obk`
2 parents a289cfc + 213a25d commit 29c5a02

File tree

9 files changed

+54
-82
lines changed

9 files changed

+54
-82
lines changed

compiler/rustc_const_eval/src/interpret/eval_context.rs

+6-38
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ use std::cell::Cell;
22
use std::fmt;
33
use std::mem;
44

5-
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
65
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
76
use rustc_index::vec::IndexVec;
8-
use rustc_macros::HashStable;
97
use rustc_middle::mir;
108
use rustc_middle::mir::interpret::{InterpError, InvalidProgramInfo};
119
use rustc_middle::ty::layout::{
@@ -16,7 +14,6 @@ use rustc_middle::ty::{
1614
self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
1715
};
1816
use rustc_mir_dataflow::storage::always_storage_live_locals;
19-
use rustc_query_system::ich::StableHashingContext;
2017
use rustc_session::Limit;
2118
use rustc_span::{Pos, Span};
2219
use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout};
@@ -142,7 +139,7 @@ pub struct FrameInfo<'tcx> {
142139
}
143140

144141
/// Unwind information.
145-
#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)]
142+
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
146143
pub enum StackPopUnwind {
147144
/// The cleanup block.
148145
Cleanup(mir::BasicBlock),
@@ -152,7 +149,7 @@ pub enum StackPopUnwind {
152149
NotAllowed,
153150
}
154151

155-
#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these
152+
#[derive(Clone, Copy, Eq, PartialEq, Debug)] // Miri debug-prints these
156153
pub enum StackPopCleanup {
157154
/// Jump to the next block in the caller, or cause UB if None (that's a function
158155
/// that may never return). Also store layout of return place so
@@ -168,16 +165,15 @@ pub enum StackPopCleanup {
168165
}
169166

170167
/// State of a local variable including a memoized layout
171-
#[derive(Clone, Debug, PartialEq, Eq, HashStable)]
168+
#[derive(Clone, Debug)]
172169
pub struct LocalState<'tcx, Tag: Provenance = AllocId> {
173170
pub value: LocalValue<Tag>,
174171
/// Don't modify if `Some`, this is only used to prevent computing the layout twice
175-
#[stable_hasher(ignore)]
176172
pub layout: Cell<Option<TyAndLayout<'tcx>>>,
177173
}
178174

179175
/// Current value of a local variable
180-
#[derive(Copy, Clone, PartialEq, Eq, HashStable, Debug)] // Miri debug-prints these
176+
#[derive(Copy, Clone, Debug)] // Miri debug-prints these
181177
pub enum LocalValue<Tag: Provenance = AllocId> {
182178
/// This local is not currently alive, and cannot be used at all.
183179
Dead,
@@ -678,7 +674,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
678674
body,
679675
loc: Err(body.span), // Span used for errors caused during preamble.
680676
return_to_block,
681-
return_place: *return_place,
677+
return_place: return_place.clone(),
682678
// empty local array, we fill it in below, after we are inside the stack frame and
683679
// all methods actually know about the frame
684680
locals: IndexVec::new(),
@@ -799,7 +795,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
799795
let op = self
800796
.local_to_op(self.frame(), mir::RETURN_PLACE, None)
801797
.expect("return place should always be live");
802-
let dest = self.frame().return_place;
798+
let dest = self.frame().return_place.clone();
803799
let err = self.copy_op(&op, &dest, /*allow_transmute*/ true);
804800
trace!("return value: {:?}", self.dump_place(*dest));
805801
// We delay actually short-circuiting on this error until *after* the stack frame is
@@ -1021,31 +1017,3 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug
10211017
}
10221018
}
10231019
}
1024-
1025-
impl<'ctx, 'mir, 'tcx, Tag: Provenance, Extra> HashStable<StableHashingContext<'ctx>>
1026-
for Frame<'mir, 'tcx, Tag, Extra>
1027-
where
1028-
Extra: HashStable<StableHashingContext<'ctx>>,
1029-
Tag: HashStable<StableHashingContext<'ctx>>,
1030-
{
1031-
fn hash_stable(&self, hcx: &mut StableHashingContext<'ctx>, hasher: &mut StableHasher) {
1032-
// Exhaustive match on fields to make sure we forget no field.
1033-
let Frame {
1034-
body,
1035-
instance,
1036-
return_to_block,
1037-
return_place,
1038-
locals,
1039-
loc,
1040-
extra,
1041-
tracing_span: _,
1042-
} = self;
1043-
body.hash_stable(hcx, hasher);
1044-
instance.hash_stable(hcx, hasher);
1045-
return_to_block.hash_stable(hcx, hasher);
1046-
return_place.hash_stable(hcx, hasher);
1047-
locals.hash_stable(hcx, hasher);
1048-
loc.hash_stable(hcx, hasher);
1049-
extra.hash_stable(hcx, hasher);
1050-
}
1051-
}

compiler/rustc_const_eval/src/interpret/intrinsics.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
455455

456456
for i in 0..dest_len {
457457
let place = self.mplace_index(&dest, i)?;
458-
let value =
459-
if i == index { *elem } else { self.mplace_index(&input, i)?.into() };
458+
let value = if i == index {
459+
elem.clone()
460+
} else {
461+
self.mplace_index(&input, i)?.into()
462+
};
460463
self.copy_op(&value, &place.into(), /*allow_transmute*/ false)?;
461464
}
462465
}

compiler/rustc_const_eval/src/interpret/operand.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
use std::fmt::Write;
55

66
use rustc_hir::def::Namespace;
7-
use rustc_macros::HashStable;
87
use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
98
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
109
use rustc_middle::ty::{ConstInt, DelaySpanBugEmitted, Ty};
@@ -25,7 +24,7 @@ use super::{
2524
/// operations and wide pointers. This idea was taken from rustc's codegen.
2625
/// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely
2726
/// defined on `Immediate`, and do not have to work with a `Place`.
28-
#[derive(Copy, Clone, PartialEq, Eq, HashStable, Hash, Debug)]
27+
#[derive(Copy, Clone, Debug)]
2928
pub enum Immediate<Tag: Provenance = AllocId> {
3029
/// A single scalar value (must have *initialized* `Scalar` ABI).
3130
/// FIXME: we also currently often use this for ZST.
@@ -112,7 +111,7 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> {
112111

113112
// ScalarPair needs a type to interpret, so we often have an immediate and a type together
114113
// as input for binary and cast operations.
115-
#[derive(Copy, Clone, Debug)]
114+
#[derive(Clone, Debug)]
116115
pub struct ImmTy<'tcx, Tag: Provenance = AllocId> {
117116
imm: Immediate<Tag>,
118117
pub layout: TyAndLayout<'tcx>,
@@ -182,13 +181,16 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for ImmTy<'tcx, Tag> {
182181
/// An `Operand` is the result of computing a `mir::Operand`. It can be immediate,
183182
/// or still in memory. The latter is an optimization, to delay reading that chunk of
184183
/// memory and to avoid having to store arbitrary-sized data here.
185-
#[derive(Copy, Clone, PartialEq, Eq, HashStable, Hash, Debug)]
184+
#[derive(Copy, Clone, Debug)]
186185
pub enum Operand<Tag: Provenance = AllocId> {
187186
Immediate(Immediate<Tag>),
188187
Indirect(MemPlace<Tag>),
189188
}
190189

191-
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
190+
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
191+
rustc_data_structures::static_assert_size!(Operand, 64);
192+
193+
#[derive(Clone, Debug)]
192194
pub struct OpTy<'tcx, Tag: Provenance = AllocId> {
193195
op: Operand<Tag>, // Keep this private; it helps enforce invariants.
194196
pub layout: TyAndLayout<'tcx>,

compiler/rustc_const_eval/src/interpret/place.rs

+19-20
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
use std::hash::Hash;
66

77
use rustc_ast::Mutability;
8-
use rustc_macros::HashStable;
98
use rustc_middle::mir;
109
use rustc_middle::ty;
1110
use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
@@ -17,7 +16,7 @@ use super::{
1716
Pointer, Provenance, Scalar, ScalarMaybeUninit,
1817
};
1918

20-
#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)]
19+
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
2120
/// Information required for the sound usage of a `MemPlace`.
2221
pub enum MemPlaceMeta<Tag: Provenance = AllocId> {
2322
/// The unsized payload (e.g. length for slices or vtable pointer for trait objects).
@@ -47,7 +46,7 @@ impl<Tag: Provenance> MemPlaceMeta<Tag> {
4746
}
4847
}
4948

50-
#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)]
49+
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
5150
pub struct MemPlace<Tag: Provenance = AllocId> {
5251
/// The pointer can be a pure integer, with the `None` tag.
5352
pub ptr: Pointer<Option<Tag>>,
@@ -60,7 +59,22 @@ pub struct MemPlace<Tag: Provenance = AllocId> {
6059
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
6160
rustc_data_structures::static_assert_size!(MemPlace, 40);
6261

63-
#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)]
62+
/// A MemPlace with its layout. Constructing it is only possible in this module.
63+
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
64+
pub struct MPlaceTy<'tcx, Tag: Provenance = AllocId> {
65+
mplace: MemPlace<Tag>,
66+
pub layout: TyAndLayout<'tcx>,
67+
/// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct:
68+
/// it needs to have a different alignment than the field type would usually have.
69+
/// So we represent this here with a separate field that "overwrites" `layout.align`.
70+
/// This means `layout.align` should never be used for a `MPlaceTy`!
71+
pub align: Align,
72+
}
73+
74+
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
75+
rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64);
76+
77+
#[derive(Copy, Clone, Debug)]
6478
pub enum Place<Tag: Provenance = AllocId> {
6579
/// A place referring to a value allocated in the `Memory` system.
6680
Ptr(MemPlace<Tag>),
@@ -73,7 +87,7 @@ pub enum Place<Tag: Provenance = AllocId> {
7387
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
7488
rustc_data_structures::static_assert_size!(Place, 48);
7589

76-
#[derive(Copy, Clone, Debug)]
90+
#[derive(Clone, Debug)]
7791
pub struct PlaceTy<'tcx, Tag: Provenance = AllocId> {
7892
place: Place<Tag>, // Keep this private; it helps enforce invariants.
7993
pub layout: TyAndLayout<'tcx>,
@@ -95,21 +109,6 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for PlaceTy<'tcx, Tag> {
95109
}
96110
}
97111

98-
/// A MemPlace with its layout. Constructing it is only possible in this module.
99-
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
100-
pub struct MPlaceTy<'tcx, Tag: Provenance = AllocId> {
101-
mplace: MemPlace<Tag>,
102-
pub layout: TyAndLayout<'tcx>,
103-
/// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct:
104-
/// it needs to have a different alignment than the field type would usually have.
105-
/// So we represent this here with a separate field that "overwrites" `layout.align`.
106-
/// This means `layout.align` should never be used for a `MPlaceTy`!
107-
pub align: Align,
108-
}
109-
110-
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
111-
rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64);
112-
113112
impl<'tcx, Tag: Provenance> std::ops::Deref for MPlaceTy<'tcx, Tag> {
114113
type Target = MemPlace<Tag>;
115114
#[inline(always)]

compiler/rustc_const_eval/src/interpret/projection.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ where
157157
variant: VariantIdx,
158158
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
159159
// Downcast just changes the layout
160-
let mut base = *base;
160+
let mut base = base.clone();
161161
base.layout = base.layout.for_variant(self, variant);
162162
Ok(base)
163163
}
@@ -168,7 +168,7 @@ where
168168
variant: VariantIdx,
169169
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
170170
// Downcast just changes the layout
171-
let mut base = *base;
171+
let mut base = base.clone();
172172
base.layout = base.layout.for_variant(self, variant);
173173
Ok(base)
174174
}
@@ -350,7 +350,7 @@ where
350350
use rustc_middle::mir::ProjectionElem::*;
351351
Ok(match proj_elem {
352352
OpaqueCast(ty) => {
353-
let mut place = *base;
353+
let mut place = base.clone();
354354
place.layout = self.layout_of(ty)?;
355355
place
356356
}
@@ -379,7 +379,7 @@ where
379379
use rustc_middle::mir::ProjectionElem::*;
380380
Ok(match proj_elem {
381381
OpaqueCast(ty) => {
382-
let mut op = *base;
382+
let mut op = base.clone();
383383
op.layout = self.layout_of(ty)?;
384384
op
385385
}

compiler/rustc_const_eval/src/interpret/terminator.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
444444
trace!("eval_fn_call: Will pass last argument by untupling");
445445
Cow::from(
446446
args.iter()
447-
.map(|&a| Ok(a))
447+
.map(|a| Ok(a.clone()))
448448
.chain(
449449
(0..untuple_arg.layout.fields.count())
450450
.map(|i| self.operand_field(untuple_arg, i)),
@@ -525,7 +525,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
525525
// We have to implement all "object safe receivers". So we have to go search for a
526526
// pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively
527527
// unwrap those newtypes until we are there.
528-
let mut receiver = args[0];
528+
let mut receiver = args[0].clone();
529529
let receiver_place = loop {
530530
match receiver.layout.ty.kind() {
531531
ty::Ref(..) | ty::RawPtr(..) => break self.deref_operand(&receiver)?,

compiler/rustc_const_eval/src/interpret/visitor.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use super::{InterpCx, MPlaceTy, Machine, OpTy, PlaceTy};
1313
/// A thing that we can project into, and that has a layout.
1414
/// This wouldn't have to depend on `Machine` but with the current type inference,
1515
/// that's just more convenient to work with (avoids repeating all the `Machine` bounds).
16-
pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy {
16+
pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized {
1717
/// Gets this value's layout.
1818
fn layout(&self) -> TyAndLayout<'tcx>;
1919

@@ -54,7 +54,7 @@ pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy {
5454
/// A thing that we can project into given *mutable* access to `ecx`, and that has a layout.
5555
/// This wouldn't have to depend on `Machine` but with the current type inference,
5656
/// that's just more convenient to work with (avoids repeating all the `Machine` bounds).
57-
pub trait ValueMut<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy {
57+
pub trait ValueMut<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized {
5858
/// Gets this value's layout.
5959
fn layout(&self) -> TyAndLayout<'tcx>;
6060

@@ -106,12 +106,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc
106106
&self,
107107
_ecx: &InterpCx<'mir, 'tcx, M>,
108108
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
109-
Ok(*self)
109+
Ok(self.clone())
110110
}
111111

112112
#[inline(always)]
113113
fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self {
114-
*op
114+
op.clone()
115115
}
116116

117117
#[inline(always)]
@@ -146,20 +146,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M>
146146
&self,
147147
_ecx: &InterpCx<'mir, 'tcx, M>,
148148
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
149-
Ok(*self)
149+
Ok(self.clone())
150150
}
151151

152152
#[inline(always)]
153153
fn to_op_for_proj(
154154
&self,
155155
_ecx: &mut InterpCx<'mir, 'tcx, M>,
156156
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
157-
Ok(*self)
157+
Ok(self.clone())
158158
}
159159

160160
#[inline(always)]
161161
fn from_op(op: &OpTy<'tcx, M::PointerTag>) -> Self {
162-
*op
162+
op.clone()
163163
}
164164

165165
#[inline(always)]

compiler/rustc_mir_transform/src/const_prop.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
516516
let l = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?));
517517
// Check for exceeding shifts *even if* we cannot evaluate the LHS.
518518
if op == BinOp::Shr || op == BinOp::Shl {
519-
let r = r?;
519+
let r = r.clone()?;
520520
// We need the type of the LHS. We cannot use `place_layout` as that is the type
521521
// of the result, which for checked binops is not the same!
522522
let left_ty = left.ty(self.local_decls, self.tcx);

compiler/rustc_mir_transform/src/const_prop_lint.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
584584
});
585585
// Check for exceeding shifts *even if* we cannot evaluate the LHS.
586586
if op == BinOp::Shr || op == BinOp::Shl {
587-
let r = r?;
587+
let r = r.clone()?;
588588
// We need the type of the LHS. We cannot use `place_layout` as that is the type
589589
// of the result, which for checked binops is not the same!
590590
let left_ty = left.ty(self.local_decls, self.tcx);
@@ -616,10 +616,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
616616
}
617617
}
618618

619-
if let (Some(l), Some(r)) = (&l, &r) {
619+
if let (Some(l), Some(r)) = (l, r) {
620620
// The remaining operators are handled through `overflowing_binary_op`.
621621
if self.use_ecx(source_info, |this| {
622-
let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
622+
let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, &l, &r)?;
623623
Ok(overflow)
624624
})? {
625625
self.report_assert_as_lint(

0 commit comments

Comments
 (0)