Skip to content

Commit f442c4a

Browse files
committed
Auto merge of rust-lang#15353 - HKalbasi:mir, r=HKalbasi
Add manual implementation of clone for tuples in mir interpreter And some other minor changes. Clone for tuple is not implemented in the std and it is magically implemented by the compiler, so we need this.
2 parents 3eba6d3 + bd2a8ca commit f442c4a

File tree

6 files changed

+162
-15
lines changed

6 files changed

+162
-15
lines changed

crates/hir-ty/src/consteval/tests.rs

+37-5
Original file line numberDiff line numberDiff line change
@@ -1428,14 +1428,14 @@ fn builtin_derive_macro() {
14281428
#[derive(Clone)]
14291429
struct Y {
14301430
field1: i32,
1431-
field2: u8,
1431+
field2: ((i32, u8), i64),
14321432
}
14331433
14341434
const GOAL: u8 = {
1435-
let x = X(2, Z::Foo(Y { field1: 4, field2: 5 }), 8);
1435+
let x = X(2, Z::Foo(Y { field1: 4, field2: ((32, 5), 12) }), 8);
14361436
let x = x.clone();
14371437
let Z::Foo(t) = x.1;
1438-
t.field2
1438+
t.field2.0 .1
14391439
};
14401440
"#,
14411441
5,
@@ -1632,6 +1632,34 @@ const GOAL: i32 = {
16321632
);
16331633
}
16341634

1635+
#[test]
1636+
fn closure_capture_unsized_type() {
1637+
check_number(
1638+
r#"
1639+
//- minicore: fn, copy, slice, index, coerce_unsized
1640+
fn f<T: A>(x: &<T as A>::Ty) -> &<T as A>::Ty {
1641+
let c = || &*x;
1642+
c()
1643+
}
1644+
1645+
trait A {
1646+
type Ty;
1647+
}
1648+
1649+
impl A for i32 {
1650+
type Ty = [u8];
1651+
}
1652+
1653+
const GOAL: u8 = {
1654+
let k: &[u8] = &[1, 2, 3];
1655+
let k = f::<i32>(k);
1656+
k[0] + k[1] + k[2]
1657+
}
1658+
"#,
1659+
6,
1660+
);
1661+
}
1662+
16351663
#[test]
16361664
fn closure_and_impl_fn() {
16371665
check_number(
@@ -2521,12 +2549,16 @@ fn const_trait_assoc() {
25212549
);
25222550
check_number(
25232551
r#"
2524-
//- minicore: size_of
2552+
//- minicore: size_of, fn
25252553
//- /a/lib.rs crate:a
25262554
use core::mem::size_of;
25272555
pub struct S<T>(T);
25282556
impl<T> S<T> {
2529-
pub const X: usize = core::mem::size_of::<T>();
2557+
pub const X: usize = {
2558+
let k: T;
2559+
let f = || core::mem::size_of::<T>();
2560+
f()
2561+
};
25302562
}
25312563
//- /main.rs crate:main deps:a
25322564
use a::{S};

crates/hir-ty/src/consteval/tests/intrinsics.rs

+4
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,8 @@ fn atomic() {
438438
pub fn atomic_nand_seqcst<T: Copy>(dst: *mut T, src: T) -> T;
439439
pub fn atomic_or_release<T: Copy>(dst: *mut T, src: T) -> T;
440440
pub fn atomic_xor_seqcst<T: Copy>(dst: *mut T, src: T) -> T;
441+
pub fn atomic_fence_seqcst();
442+
pub fn atomic_singlethreadfence_acqrel();
441443
}
442444
443445
fn should_not_reach() {
@@ -452,13 +454,15 @@ fn atomic() {
452454
if (30, true) != atomic_cxchg_release_seqcst(&mut y, 30, 40) {
453455
should_not_reach();
454456
}
457+
atomic_fence_seqcst();
455458
if (40, false) != atomic_cxchg_release_seqcst(&mut y, 30, 50) {
456459
should_not_reach();
457460
}
458461
if (40, true) != atomic_cxchgweak_acquire_acquire(&mut y, 40, 30) {
459462
should_not_reach();
460463
}
461464
let mut z = atomic_xsub_seqcst(&mut x, -200);
465+
atomic_singlethreadfence_acqrel();
462466
atomic_xor_seqcst(&mut x, 1024);
463467
atomic_load_seqcst(&x) + z * 3 + atomic_load_seqcst(&y) * 2
464468
};

crates/hir-ty/src/layout.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use triomphe::Arc;
1414

1515
use crate::{
1616
consteval::try_const_usize, db::HirDatabase, infer::normalize, layout::adt::struct_variant_idx,
17-
utils::ClosureSubst, Interner, Substitution, TraitEnvironment, Ty,
17+
utils::ClosureSubst, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty,
1818
};
1919

2020
pub use self::{
@@ -279,7 +279,15 @@ pub fn layout_of_ty_query(
279279
// return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
280280
// }
281281

282-
let unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone());
282+
let mut unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone());
283+
if let TyKind::AssociatedType(id, subst) = unsized_part.kind(Interner) {
284+
unsized_part = TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy {
285+
associated_ty_id: *id,
286+
substitution: subst.clone(),
287+
}))
288+
.intern(Interner);
289+
}
290+
unsized_part = normalize(db, trait_env.clone(), unsized_part);
283291
let metadata = match unsized_part.kind(Interner) {
284292
TyKind::Slice(_) | TyKind::Str => {
285293
scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false))
@@ -362,8 +370,16 @@ pub fn layout_of_ty_query(
362370
return Err(LayoutError::NotImplemented)
363371
}
364372
TyKind::Error => return Err(LayoutError::HasErrorType),
365-
TyKind::AssociatedType(_, _)
366-
| TyKind::Alias(_)
373+
TyKind::AssociatedType(id, subst) => {
374+
// Try again with `TyKind::Alias` to normalize the associated type.
375+
let ty = TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy {
376+
associated_ty_id: *id,
377+
substitution: subst.clone(),
378+
}))
379+
.intern(Interner);
380+
return db.layout_of_ty(ty, trait_env);
381+
}
382+
TyKind::Alias(_)
367383
| TyKind::Placeholder(_)
368384
| TyKind::BoundVar(_)
369385
| TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder),

crates/hir-ty/src/mir/eval.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ pub enum MirEvalError {
313313
InvalidVTableId(usize),
314314
CoerceUnsizedError(Ty),
315315
LangItemNotFound(LangItem),
316+
BrokenLayout(Layout),
316317
}
317318

318319
impl MirEvalError {
@@ -399,6 +400,7 @@ impl MirEvalError {
399400
| MirEvalError::TargetDataLayoutNotAvailable
400401
| MirEvalError::CoerceUnsizedError(_)
401402
| MirEvalError::LangItemNotFound(_)
403+
| MirEvalError::BrokenLayout(_)
402404
| MirEvalError::InvalidVTableId(_) => writeln!(f, "{:?}", err)?,
403405
}
404406
Ok(())
@@ -433,6 +435,7 @@ impl std::fmt::Debug for MirEvalError {
433435
Self::CoerceUnsizedError(arg0) => {
434436
f.debug_tuple("CoerceUnsizedError").field(arg0).finish()
435437
}
438+
Self::BrokenLayout(arg0) => f.debug_tuple("BrokenLayout").field(arg0).finish(),
436439
Self::InvalidVTableId(arg0) => f.debug_tuple("InvalidVTableId").field(arg0).finish(),
437440
Self::NotSupported(arg0) => f.debug_tuple("NotSupported").field(arg0).finish(),
438441
Self::InvalidConst(arg0) => {
@@ -702,9 +705,7 @@ impl Evaluator<'_> {
702705
}
703706

704707
fn layout_adt(&self, adt: AdtId, subst: Substitution) -> Result<Arc<Layout>> {
705-
self.db.layout_of_adt(adt, subst.clone(), self.trait_env.clone()).map_err(|e| {
706-
MirEvalError::LayoutError(e, TyKind::Adt(chalk_ir::AdtId(adt), subst).intern(Interner))
707-
})
708+
self.layout(&TyKind::Adt(chalk_ir::AdtId(adt), subst).intern(Interner))
708709
}
709710

710711
fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals) -> Result<Ty> {
@@ -1543,12 +1544,18 @@ impl Evaluator<'_> {
15431544
) -> Result<Vec<u8>> {
15441545
let mut result = vec![0; size];
15451546
if let Some((offset, size, value)) = tag {
1546-
result[offset..offset + size].copy_from_slice(&value.to_le_bytes()[0..size]);
1547+
match result.get_mut(offset..offset + size) {
1548+
Some(it) => it.copy_from_slice(&value.to_le_bytes()[0..size]),
1549+
None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())),
1550+
}
15471551
}
15481552
for (i, op) in values.enumerate() {
15491553
let offset = variant_layout.fields.offset(i).bytes_usize();
15501554
let op = op.get(&self)?;
1551-
result[offset..offset + op.len()].copy_from_slice(op);
1555+
match result.get_mut(offset..offset + op.len()) {
1556+
Some(it) => it.copy_from_slice(op),
1557+
None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())),
1558+
}
15521559
}
15531560
Ok(result)
15541561
}

crates/hir-ty/src/mir/eval/shim.rs

+84-1
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,85 @@ impl Evaluator<'_> {
124124
destination.write_from_bytes(self, &result)?;
125125
return Ok(true);
126126
}
127+
if let ItemContainerId::TraitId(t) = def.lookup(self.db.upcast()).container {
128+
if self.db.lang_attr(t.into()) == Some(LangItem::Clone) {
129+
let [self_ty] = generic_args.as_slice(Interner) else {
130+
not_supported!("wrong generic arg count for clone");
131+
};
132+
let Some(self_ty) = self_ty.ty(Interner) else {
133+
not_supported!("wrong generic arg kind for clone");
134+
};
135+
// Clone has special impls for tuples and function pointers
136+
if matches!(self_ty.kind(Interner), TyKind::Function(_) | TyKind::Tuple(..)) {
137+
self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
138+
return Ok(true);
139+
}
140+
}
141+
}
127142
Ok(false)
128143
}
129144

145+
/// Clone has special impls for tuples and function pointers
146+
fn exec_clone(
147+
&mut self,
148+
def: FunctionId,
149+
args: &[IntervalAndTy],
150+
self_ty: Ty,
151+
locals: &Locals,
152+
destination: Interval,
153+
span: MirSpan,
154+
) -> Result<()> {
155+
match self_ty.kind(Interner) {
156+
TyKind::Function(_) => {
157+
let [arg] = args else {
158+
not_supported!("wrong arg count for clone");
159+
};
160+
let addr = Address::from_bytes(arg.get(self)?)?;
161+
return destination
162+
.write_from_interval(self, Interval { addr, size: destination.size });
163+
}
164+
TyKind::Tuple(_, subst) => {
165+
let [arg] = args else {
166+
not_supported!("wrong arg count for clone");
167+
};
168+
let addr = Address::from_bytes(arg.get(self)?)?;
169+
let layout = self.layout(&self_ty)?;
170+
for (i, ty) in subst.iter(Interner).enumerate() {
171+
let ty = ty.assert_ty_ref(Interner);
172+
let size = self.layout(ty)?.size.bytes_usize();
173+
let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
174+
let arg = IntervalAndTy {
175+
interval: Interval { addr: tmp, size: self.ptr_size() },
176+
ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone())
177+
.intern(Interner),
178+
};
179+
let offset = layout.fields.offset(i).bytes_usize();
180+
self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
181+
self.exec_clone(
182+
def,
183+
&[arg],
184+
ty.clone(),
185+
locals,
186+
destination.slice(offset..offset + size),
187+
span,
188+
)?;
189+
}
190+
}
191+
_ => {
192+
self.exec_fn_with_args(
193+
def,
194+
args,
195+
Substitution::from1(Interner, self_ty),
196+
locals,
197+
destination,
198+
None,
199+
span,
200+
)?;
201+
}
202+
}
203+
Ok(())
204+
}
205+
130206
fn exec_alloc_fn(
131207
&mut self,
132208
alloc_fn: &str,
@@ -1057,7 +1133,14 @@ impl Evaluator<'_> {
10571133
_span: MirSpan,
10581134
) -> Result<()> {
10591135
// We are a single threaded runtime with no UB checking and no optimization, so
1060-
// we can implement these as normal functions.
1136+
// we can implement atomic intrinsics as normal functions.
1137+
1138+
if name.starts_with("singlethreadfence_") || name.starts_with("fence_") {
1139+
return Ok(());
1140+
}
1141+
1142+
// The rest of atomic intrinsics have exactly one generic arg
1143+
10611144
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
10621145
return Err(MirEvalError::TypeError("atomic intrinsic generic arg is not provided"));
10631146
};

crates/hir-ty/src/mir/lower.rs

+5
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,11 @@ impl<'ctx> MirLowerCtx<'ctx> {
660660
expr_id.into(),
661661
)
662662
}
663+
TyKind::Closure(_, _) => {
664+
not_supported!(
665+
"method resolution not emitted for closure (Are Fn traits available?)"
666+
);
667+
}
663668
TyKind::Error => {
664669
return Err(MirLowerError::MissingFunctionDefinition(self.owner, expr_id))
665670
}

0 commit comments

Comments
 (0)