Skip to content

Commit e1f1798

Browse files
committed
Handle unwinding, use a loop for arrays
1 parent df7be43 commit e1f1798

File tree

3 files changed

+308
-56
lines changed

3 files changed

+308
-56
lines changed

src/librustc_mir/shim.rs

+242-55
Original file line numberDiff line numberDiff line change
@@ -286,18 +286,26 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
286286
let mut local_decls = local_decls_for_sig(&sig, span);
287287
let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };
288288

289+
let rcvr = Lvalue::Local(Local::new(1+0)).deref();
290+
289291
let mut blocks = IndexVec::new();
290-
let block = |blocks: &mut IndexVec<_, _>, statement, kind| {
292+
let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
291293
blocks.push(BasicBlockData {
292-
statements: vec![statement],
294+
statements,
293295
terminator: Some(Terminator { source_info, kind }),
294-
is_cleanup: false
296+
is_cleanup,
295297
})
296298
};
297299

298-
let rcvr = Lvalue::Local(Local::new(1+0)).deref();
300+
let make_lvalue = |mutability, ty, local_decls: &mut IndexVec<_, _>| {
301+
Lvalue::Local(
302+
local_decls.push(temp_decl(mutability, ty, span))
303+
)
304+
};
299305

300-
let call_clone = |i, ty, rcvr_field, blocks: &mut _, local_decls: &mut IndexVec<_, _>| {
306+
let call_clone = |ty, rcvr_field, next, cleanup,
307+
blocks: &mut _, local_decls: &mut IndexVec<_, _>|
308+
{
301309
// `func == Clone::clone(&ty) -> ty`
302310
let substs = Substs::for_item(tcx, def_id, |_, _| tcx.types.re_erased, |_, _| ty);
303311
let func = Operand::Constant(box Constant {
@@ -308,102 +316,281 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
308316
},
309317
});
310318

311-
let ref_loc = Lvalue::Local(
312-
local_decls.push(temp_decl(
313-
Mutability::Not,
314-
tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut {
315-
ty,
316-
mutbl: hir::Mutability::MutImmutable,
317-
}),
318-
span
319-
))
320-
);
321-
322-
let loc = Lvalue::Local(
323-
local_decls.push(temp_decl(
324-
Mutability::Not,
319+
let ref_loc = make_lvalue(
320+
Mutability::Not,
321+
tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut {
325322
ty,
326-
span
327-
))
323+
mutbl: hir::Mutability::MutImmutable,
324+
}),
325+
local_decls
328326
);
329327

328+
let loc = make_lvalue(Mutability::Not, ty, local_decls);
329+
330330
// `let ref_loc: &ty = &rcvr_field;`
331331
let statement = Statement {
332-
source_info: source_info,
332+
source_info,
333333
kind: StatementKind::Assign(
334334
ref_loc.clone(),
335335
Rvalue::Ref(tcx.types.re_erased, BorrowKind::Shared, rcvr_field)
336336
)
337337
};
338338

339339
// `let loc = Clone::clone(ref_loc);`
340-
block(blocks, statement, TerminatorKind::Call {
340+
block(blocks, vec![statement], TerminatorKind::Call {
341341
func,
342342
args: vec![Operand::Consume(ref_loc)],
343-
destination: Some((loc.clone(), BasicBlock::new(i + 1))),
344-
cleanup: None,
345-
});
343+
destination: Some((loc.clone(), next)),
344+
cleanup: Some(cleanup),
345+
}, false);
346346

347347
loc
348348
};
349349

350350
let is_copy = !self_ty.moves_by_default(tcx, tcx.param_env(def_id), span);
351-
352351
match self_ty.sty {
353352
_ if is_copy => {
354353
// `return *self;`
355-
let statement = Statement {
356-
source_info: source_info,
354+
let ret_statement = Statement {
355+
source_info,
357356
kind: StatementKind::Assign(
358357
Lvalue::Local(RETURN_POINTER),
359358
Rvalue::Use(Operand::Consume(rcvr))
360359
)
361360
};
362-
block(&mut blocks, statement, TerminatorKind::Return);
361+
block(&mut blocks, vec![ret_statement], TerminatorKind::Return, false);
363362
}
364363
ty::TyArray(ty, len) => {
365-
let mut returns = Vec::new();
366-
for i in 0..len {
367-
let index = ConstUsize::new(i as u64, tcx.sess.target.uint_type).unwrap();
368-
let rcvr_field = rcvr.clone().index(
369-
Operand::Constant(box Constant {
370-
span,
371-
ty: tcx.types.usize,
372-
literal: Literal::Value {
373-
value: ConstVal::Integral(ConstInt::Usize(index))
374-
}
375-
})
364+
let make_loop = |beg, end, loop_body, loop_end,
365+
blocks: &mut _, local_decls: &mut _, is_cleanup|
366+
{
367+
let cond = make_lvalue(Mutability::Mut, tcx.types.bool, local_decls);
368+
let compute_cond = Statement {
369+
source_info,
370+
kind: StatementKind::Assign(
371+
cond.clone(),
372+
Rvalue::BinaryOp(BinOp::Ne, Operand::Consume(end), Operand::Consume(beg))
373+
)
374+
};
375+
376+
// `if end != beg { goto loop_body; } else { goto loop_end; }`
377+
block(
378+
blocks,
379+
vec![compute_cond],
380+
TerminatorKind::if_(tcx, Operand::Consume(cond), loop_body, loop_end),
381+
is_cleanup
376382
);
383+
};
377384

378-
// `returns[i] = Clone::clone(&rcvr[i]);`
379-
returns.push(call_clone(i, ty, rcvr_field, &mut blocks, &mut local_decls));
380-
}
385+
let make_usize = |value| {
386+
let value = ConstUsize::new(value as u64, tcx.sess.target.uint_type).unwrap();
387+
box Constant {
388+
span,
389+
ty: tcx.types.usize,
390+
literal: Literal::Value {
391+
value: ConstVal::Integral(ConstInt::Usize(value))
392+
}
393+
}
394+
};
381395

382-
// `return [returns[0], returns[1], ..., returns[len - 1]];`
383-
let statement = Statement {
396+
let beg = make_lvalue(Mutability::Mut, tcx.types.usize, &mut local_decls);
397+
let end = make_lvalue(Mutability::Not, tcx.types.usize, &mut local_decls);
398+
let ret = make_lvalue(Mutability::Mut, tcx.mk_array(ty, len), &mut local_decls);
399+
400+
// BB #0
401+
// `let mut beg = 0;`
402+
// `let end = len;`
403+
// `goto #1;`
404+
let inits = vec![
405+
Statement {
406+
source_info,
407+
kind: StatementKind::Assign(
408+
beg.clone(),
409+
Rvalue::Use(Operand::Constant(make_usize(0)))
410+
)
411+
},
412+
Statement {
413+
source_info,
414+
kind: StatementKind::Assign(
415+
end.clone(),
416+
Rvalue::Use(Operand::Constant(make_usize(len)))
417+
)
418+
}
419+
];
420+
block(&mut blocks, inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
421+
422+
// BB #1: loop {
423+
// BB #2;
424+
// BB #3;
425+
// }
426+
// BB #4;
427+
make_loop(
428+
beg.clone(),
429+
end,
430+
BasicBlock::new(2),
431+
BasicBlock::new(4),
432+
&mut blocks,
433+
&mut local_decls,
434+
false
435+
);
436+
437+
// BB #2
438+
// `let cloned = Clone::clone(rcvr[beg])`;
439+
// Goto #3 if ok, #5 if unwinding happens.
440+
let rcvr_field = rcvr.clone().index(Operand::Consume(beg.clone()));
441+
let cloned = call_clone(
442+
ty,
443+
rcvr_field,
444+
BasicBlock::new(3),
445+
BasicBlock::new(5),
446+
&mut blocks,
447+
&mut local_decls
448+
);
449+
450+
// BB #3
451+
// `ret[beg] = cloned;`
452+
// `beg = beg + 1;`
453+
// `goto #1`;
454+
let ret_field = ret.clone().index(Operand::Consume(beg.clone()));
455+
let statements = vec![
456+
Statement {
457+
source_info,
458+
kind: StatementKind::Assign(
459+
ret_field,
460+
Rvalue::Use(Operand::Consume(cloned))
461+
)
462+
},
463+
Statement {
464+
source_info,
465+
kind: StatementKind::Assign(
466+
beg.clone(),
467+
Rvalue::BinaryOp(
468+
BinOp::Add,
469+
Operand::Consume(beg.clone()),
470+
Operand::Constant(make_usize(1))
471+
)
472+
)
473+
}
474+
];
475+
block(
476+
&mut blocks,
477+
statements,
478+
TerminatorKind::Goto { target: BasicBlock::new(1) },
479+
false
480+
);
481+
482+
// BB #4
483+
// `return ret;`
484+
let ret_statement = Statement {
384485
source_info: source_info,
385486
kind: StatementKind::Assign(
386487
Lvalue::Local(RETURN_POINTER),
387-
Rvalue::Aggregate(
388-
box AggregateKind::Array(ty),
389-
returns.into_iter().map(Operand::Consume).collect()
488+
Rvalue::Use(Operand::Consume(ret.clone())),
489+
)
490+
};
491+
block(&mut blocks, vec![ret_statement], TerminatorKind::Return, false);
492+
493+
// BB #5 (cleanup)
494+
// `let end = beg;`
495+
// `let mut beg = 0;`
496+
// goto #6;
497+
let end = beg;
498+
let beg = make_lvalue(Mutability::Mut, tcx.types.usize, &mut local_decls);
499+
let init = Statement {
500+
source_info,
501+
kind: StatementKind::Assign(
502+
beg.clone(),
503+
Rvalue::Use(Operand::Constant(make_usize(0)))
504+
)
505+
};
506+
block(
507+
&mut blocks,
508+
vec![init],
509+
TerminatorKind::Goto { target: BasicBlock::new(6) },
510+
true
511+
);
512+
513+
// BB #6 (cleanup): loop {
514+
// BB #7;
515+
// BB #8;
516+
// }
517+
// BB #9;
518+
make_loop(
519+
beg.clone(),
520+
end,
521+
BasicBlock::new(7),
522+
BasicBlock::new(9),
523+
&mut blocks,
524+
&mut local_decls,
525+
true
526+
);
527+
528+
// BB #7 (cleanup)
529+
// `drop(ret[beg])`;
530+
block(&mut blocks, vec![], TerminatorKind::Drop {
531+
location: ret.index(Operand::Consume(beg.clone())),
532+
target: BasicBlock::new(8),
533+
unwind: None,
534+
}, true);
535+
536+
// BB #8 (cleanup)
537+
// `beg = beg + 1;`
538+
// `goto #6;`
539+
let statement = Statement {
540+
source_info,
541+
kind: StatementKind::Assign(
542+
beg.clone(),
543+
Rvalue::BinaryOp(
544+
BinOp::Add,
545+
Operand::Consume(beg.clone()),
546+
Operand::Constant(make_usize(1))
390547
)
391548
)
392549
};
393-
block(&mut blocks, statement, TerminatorKind::Return);
550+
block(
551+
&mut blocks,
552+
vec![statement],
553+
TerminatorKind::Goto { target: BasicBlock::new(6) },
554+
true
555+
);
556+
557+
// BB #9 (resume)
558+
block(&mut blocks, vec![], TerminatorKind::Resume, true);
394559
}
395560
ty::TyTuple(tys, _) => {
396561
let mut returns = Vec::new();
397562
for (i, ity) in tys.iter().enumerate() {
398563
let rcvr_field = rcvr.clone().field(Field::new(i), *ity);
399564

565+
// BB #(2i)
400566
// `returns[i] = Clone::clone(&rcvr.i);`
401-
returns.push(call_clone(i, *ity, rcvr_field, &mut blocks, &mut local_decls));
567+
// Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens.
568+
returns.push(call_clone(
569+
*ity,
570+
rcvr_field,
571+
BasicBlock::new(2 * i + 2),
572+
BasicBlock::new(2 * i + 1),
573+
&mut blocks,
574+
&mut local_decls
575+
));
576+
577+
// BB #(2i + 1) (cleanup)
578+
if i == 0 {
579+
// Nothing to drop, just resume.
580+
block(&mut blocks, vec![], TerminatorKind::Resume, true);
581+
} else {
582+
// Drop previous field and goto previous cleanup block.
583+
block(&mut blocks, vec![], TerminatorKind::Drop {
584+
location: returns[i - 1].clone(),
585+
target: BasicBlock::new(2 * i - 1),
586+
unwind: None,
587+
}, true);
588+
}
402589
}
403590

404591
// `return (returns[0], returns[1], ..., returns[tys.len() - 1]);`
405-
let statement = Statement {
406-
source_info: source_info,
592+
let ret_statement = Statement {
593+
source_info,
407594
kind: StatementKind::Assign(
408595
Lvalue::Local(RETURN_POINTER),
409596
Rvalue::Aggregate(
@@ -412,10 +599,10 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
412599
)
413600
)
414601
};
415-
block(&mut blocks, statement, TerminatorKind::Return);
602+
block(&mut blocks, vec![ret_statement], TerminatorKind::Return, false);
416603
}
417604
_ => {
418-
bug!("builtin shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty);
605+
bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty);
419606
}
420607
};
421608

0 commit comments

Comments
 (0)