Skip to content

Commit fc2f90e

Browse files
committed
Auto merge of rust-lang#15419 - HKalbasi:mir, r=HKalbasi
Add mir lower support for tuple destructing assignment And some other changes in mir eval
2 parents ddbbd6a + 021802c commit fc2f90e

File tree

7 files changed

+247
-27
lines changed

7 files changed

+247
-27
lines changed

crates/base-db/src/fixture.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ impl ChangeFixture {
130130
let mut default_crate_root: Option<FileId> = None;
131131
let mut default_target_data_layout: Option<String> = None;
132132
let mut default_cfg = CfgOptions::default();
133+
let mut default_env = Env::new_for_test_fixture();
133134

134135
let mut file_set = FileSet::default();
135136
let mut current_source_root_kind = SourceRootKind::Local;
@@ -200,6 +201,7 @@ impl ChangeFixture {
200201
assert!(default_crate_root.is_none());
201202
default_crate_root = Some(file_id);
202203
default_cfg = meta.cfg;
204+
default_env.extend(meta.env.iter().map(|(x, y)| (x.to_owned(), y.to_owned())));
203205
default_target_data_layout = meta.target_data_layout;
204206
}
205207

@@ -220,7 +222,7 @@ impl ChangeFixture {
220222
None,
221223
default_cfg,
222224
Default::default(),
223-
Env::new_for_test_fixture(),
225+
default_env,
224226
false,
225227
CrateOrigin::Local { repo: None, name: None },
226228
default_target_data_layout

crates/base-db/src/input.rs

+6
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,12 @@ impl fmt::Display for Edition {
686686
}
687687
}
688688

689+
impl Extend<(String, String)> for Env {
690+
fn extend<T: IntoIterator<Item = (String, String)>>(&mut self, iter: T) {
691+
self.entries.extend(iter);
692+
}
693+
}
694+
689695
impl FromIterator<(String, String)> for Env {
690696
fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self {
691697
Env { entries: FromIterator::from_iter(iter) }

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

+49-4
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,27 @@ fn destructing_assignment() {
12031203
"#,
12041204
5,
12051205
);
1206+
check_number(
1207+
r#"
1208+
const GOAL: u8 = {
1209+
let (mut a, mut b) = (2, 5);
1210+
(a, b) = (b, a);
1211+
a * 10 + b
1212+
};
1213+
"#,
1214+
52,
1215+
);
1216+
check_number(
1217+
r#"
1218+
struct Point { x: i32, y: i32 }
1219+
const GOAL: i32 = {
1220+
let mut p = Point { x: 5, y: 6 };
1221+
(p.x, _) = (p.y, p.x);
1222+
p.x * 10 + p.y
1223+
};
1224+
"#,
1225+
66,
1226+
);
12061227
}
12071228

12081229
#[test]
@@ -1432,6 +1453,30 @@ fn from_trait() {
14321453
);
14331454
}
14341455

1456+
#[test]
1457+
fn closure_clone() {
1458+
check_number(
1459+
r#"
1460+
//- minicore: clone, fn
1461+
struct S(u8);
1462+
1463+
impl Clone for S(u8) {
1464+
fn clone(&self) -> S {
1465+
S(self.0 + 5)
1466+
}
1467+
}
1468+
1469+
const GOAL: u8 = {
1470+
let s = S(3);
1471+
let cl = move || s;
1472+
let cl = cl.clone();
1473+
cl().0
1474+
}
1475+
"#,
1476+
8,
1477+
);
1478+
}
1479+
14351480
#[test]
14361481
fn builtin_derive_macro() {
14371482
check_number(
@@ -2396,14 +2441,14 @@ fn const_loop() {
23962441
fn const_transfer_memory() {
23972442
check_number(
23982443
r#"
2399-
//- minicore: slice, index, coerce_unsized
2444+
//- minicore: slice, index, coerce_unsized, option
24002445
const A1: &i32 = &1;
24012446
const A2: &i32 = &10;
24022447
const A3: [&i32; 3] = [&1, &2, &100];
2403-
const A4: (i32, &i32) = (1, &1000);
2404-
const GOAL: i32 = *A1 + *A2 + *A3[2] + *A4.1;
2448+
const A4: (i32, &i32, Option<&i32>) = (1, &1000, Some(&10000));
2449+
const GOAL: i32 = *A1 + *A2 + *A3[2] + *A4.1 + *A4.2.unwrap_or(&5);
24052450
"#,
2406-
1111,
2451+
11111,
24072452
);
24082453
}
24092454

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

+22-1
Original file line numberDiff line numberDiff line change
@@ -2007,7 +2007,28 @@ impl Evaluator<'_> {
20072007
}
20082008
}
20092009
AdtId::UnionId(_) => (),
2010-
AdtId::EnumId(_) => (),
2010+
AdtId::EnumId(e) => {
2011+
if let Some((variant, layout)) = detect_variant_from_bytes(
2012+
&layout,
2013+
self.db,
2014+
self.trait_env.clone(),
2015+
self.read_memory(addr, layout.size.bytes_usize())?,
2016+
e,
2017+
) {
2018+
let ev = EnumVariantId { parent: e, local_id: variant };
2019+
for (i, (_, ty)) in self.db.field_types(ev.into()).iter().enumerate() {
2020+
let offset = layout.fields.offset(i).bytes_usize();
2021+
let ty = ty.clone().substitute(Interner, subst);
2022+
self.patch_addresses(
2023+
patch_map,
2024+
old_vtable,
2025+
addr.offset(offset),
2026+
&ty,
2027+
locals,
2028+
)?;
2029+
}
2030+
}
2031+
}
20112032
},
20122033
TyKind::Tuple(_, subst) => {
20132034
for (id, ty) in subst.iter(Interner).enumerate() {

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

+81-21
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,10 @@ impl Evaluator<'_> {
136136
not_supported!("wrong generic arg kind for clone");
137137
};
138138
// Clone has special impls for tuples and function pointers
139-
if matches!(self_ty.kind(Interner), TyKind::Function(_) | TyKind::Tuple(..)) {
139+
if matches!(
140+
self_ty.kind(Interner),
141+
TyKind::Function(_) | TyKind::Tuple(..) | TyKind::Closure(..)
142+
) {
140143
self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
141144
return Ok(true);
142145
}
@@ -167,32 +170,26 @@ impl Evaluator<'_> {
167170
return destination
168171
.write_from_interval(self, Interval { addr, size: destination.size });
169172
}
173+
TyKind::Closure(id, subst) => {
174+
let [arg] = args else {
175+
not_supported!("wrong arg count for clone");
176+
};
177+
let addr = Address::from_bytes(arg.get(self)?)?;
178+
let (closure_owner, _) = self.db.lookup_intern_closure((*id).into());
179+
let infer = self.db.infer(closure_owner);
180+
let (captures, _) = infer.closure_info(id);
181+
let layout = self.layout(&self_ty)?;
182+
let ty_iter = captures.iter().map(|c| c.ty(subst));
183+
self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?;
184+
}
170185
TyKind::Tuple(_, subst) => {
171186
let [arg] = args else {
172187
not_supported!("wrong arg count for clone");
173188
};
174189
let addr = Address::from_bytes(arg.get(self)?)?;
175190
let layout = self.layout(&self_ty)?;
176-
for (i, ty) in subst.iter(Interner).enumerate() {
177-
let ty = ty.assert_ty_ref(Interner);
178-
let size = self.layout(ty)?.size.bytes_usize();
179-
let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
180-
let arg = IntervalAndTy {
181-
interval: Interval { addr: tmp, size: self.ptr_size() },
182-
ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone())
183-
.intern(Interner),
184-
};
185-
let offset = layout.fields.offset(i).bytes_usize();
186-
self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
187-
self.exec_clone(
188-
def,
189-
&[arg],
190-
ty.clone(),
191-
locals,
192-
destination.slice(offset..offset + size),
193-
span,
194-
)?;
195-
}
191+
let ty_iter = subst.iter(Interner).map(|ga| ga.assert_ty_ref(Interner).clone());
192+
self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?;
196193
}
197194
_ => {
198195
self.exec_fn_with_args(
@@ -209,6 +206,37 @@ impl Evaluator<'_> {
209206
Ok(())
210207
}
211208

209+
fn exec_clone_for_fields(
210+
&mut self,
211+
ty_iter: impl Iterator<Item = Ty>,
212+
layout: Arc<Layout>,
213+
addr: Address,
214+
def: FunctionId,
215+
locals: &Locals,
216+
destination: Interval,
217+
span: MirSpan,
218+
) -> Result<()> {
219+
for (i, ty) in ty_iter.enumerate() {
220+
let size = self.layout(&ty)?.size.bytes_usize();
221+
let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
222+
let arg = IntervalAndTy {
223+
interval: Interval { addr: tmp, size: self.ptr_size() },
224+
ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone()).intern(Interner),
225+
};
226+
let offset = layout.fields.offset(i).bytes_usize();
227+
self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
228+
self.exec_clone(
229+
def,
230+
&[arg],
231+
ty,
232+
locals,
233+
destination.slice(offset..offset + size),
234+
span,
235+
)?;
236+
}
237+
Ok(())
238+
}
239+
212240
fn exec_alloc_fn(
213241
&mut self,
214242
alloc_fn: &str,
@@ -473,6 +501,38 @@ impl Evaluator<'_> {
473501
self.write_memory_using_ref(destination.addr, destination.size)?.fill(0);
474502
Ok(())
475503
}
504+
"getenv" => {
505+
let [name] = args else {
506+
return Err(MirEvalError::TypeError("libc::write args are not provided"));
507+
};
508+
let mut name_buf = vec![];
509+
let name = {
510+
let mut index = Address::from_bytes(name.get(self)?)?;
511+
loop {
512+
let byte = self.read_memory(index, 1)?[0];
513+
index = index.offset(1);
514+
if byte == 0 {
515+
break;
516+
}
517+
name_buf.push(byte);
518+
}
519+
String::from_utf8_lossy(&name_buf)
520+
};
521+
let value = self.db.crate_graph()[self.crate_id].env.get(&name);
522+
match value {
523+
None => {
524+
// Write null as fail
525+
self.write_memory_using_ref(destination.addr, destination.size)?.fill(0);
526+
}
527+
Some(mut value) => {
528+
value.push('\0');
529+
let addr = self.heap_allocate(value.len(), 1)?;
530+
self.write_memory(addr, value.as_bytes())?;
531+
self.write_memory(destination.addr, &addr.to_bytes())?;
532+
}
533+
}
534+
Ok(())
535+
}
476536
_ => not_supported!("unknown external function {as_str}"),
477537
}
478538
}

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

+42
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,48 @@ fn main() {
729729
)
730730
}
731731

732+
#[test]
733+
fn posix_getenv() {
734+
check_pass(
735+
r#"
736+
//- /main.rs env:foo=bar
737+
738+
type c_char = u8;
739+
740+
extern "C" {
741+
pub fn getenv(s: *const c_char) -> *mut c_char;
742+
}
743+
744+
fn should_not_reach() {
745+
_ // FIXME: replace this function with panic when that works
746+
}
747+
748+
fn main() {
749+
let result = getenv(b"foo\0" as *const _);
750+
if *result != b'b' {
751+
should_not_reach();
752+
}
753+
let result = (result as usize + 1) as *const c_char;
754+
if *result != b'a' {
755+
should_not_reach();
756+
}
757+
let result = (result as usize + 1) as *const c_char;
758+
if *result != b'r' {
759+
should_not_reach();
760+
}
761+
let result = (result as usize + 1) as *const c_char;
762+
if *result != 0 {
763+
should_not_reach();
764+
}
765+
let result = getenv(b"not found\0" as *const _);
766+
if result as usize != 0 {
767+
should_not_reach();
768+
}
769+
}
770+
"#,
771+
);
772+
}
773+
732774
#[test]
733775
fn posix_tls() {
734776
check_pass(

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

+44
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,41 @@ impl<'ctx> MirLowerCtx<'ctx> {
12441244
}
12451245
}
12461246

1247+
fn lower_destructing_assignment(
1248+
&mut self,
1249+
mut current: BasicBlockId,
1250+
lhs: ExprId,
1251+
rhs: Place,
1252+
span: MirSpan,
1253+
) -> Result<Option<BasicBlockId>> {
1254+
match &self.body.exprs[lhs] {
1255+
Expr::Tuple { exprs, is_assignee_expr: _ } => {
1256+
for (i, expr) in exprs.iter().enumerate() {
1257+
let Some(c) = self.lower_destructing_assignment(
1258+
current,
1259+
*expr,
1260+
rhs.project(ProjectionElem::TupleOrClosureField(i)),
1261+
span,
1262+
)? else {
1263+
return Ok(None);
1264+
};
1265+
current = c;
1266+
}
1267+
Ok(Some(current))
1268+
}
1269+
Expr::Underscore => Ok(Some(current)),
1270+
_ => {
1271+
let Some((lhs_place, current)) =
1272+
self.lower_expr_as_place(current, lhs, false)?
1273+
else {
1274+
return Ok(None);
1275+
};
1276+
self.push_assignment(current, lhs_place, Operand::Copy(rhs).into(), span);
1277+
Ok(Some(current))
1278+
}
1279+
}
1280+
}
1281+
12471282
fn lower_assignment(
12481283
&mut self,
12491284
current: BasicBlockId,
@@ -1259,6 +1294,15 @@ impl<'ctx> MirLowerCtx<'ctx> {
12591294
if matches!(&self.body.exprs[lhs], Expr::Underscore) {
12601295
return Ok(Some(current));
12611296
}
1297+
if matches!(
1298+
&self.body.exprs[lhs],
1299+
Expr::Tuple { .. } | Expr::RecordLit { .. } | Expr::Call { .. }
1300+
) {
1301+
let temp = self.temp(self.expr_ty_after_adjustments(rhs), current, rhs.into())?;
1302+
let temp = Place::from(temp);
1303+
self.push_assignment(current, temp.clone(), rhs_op.into(), span);
1304+
return self.lower_destructing_assignment(current, lhs, temp, span);
1305+
}
12621306
let Some((lhs_place, current)) =
12631307
self.lower_expr_as_place(current, lhs, false)?
12641308
else {

0 commit comments

Comments
 (0)