Skip to content

Commit d1c644c

Browse files
committed
Merge Call and DivergingCall diffs into CallKind
This merges two separate Call terminators and uses a separate CallKind sub-enum instead. A little bit unrelatedly, copying into destination value for a certain kind of invoke, is also implemented here. See the associated comment in code for various details that arise with this implementation.
1 parent 5010703 commit d1c644c

File tree

6 files changed

+197
-179
lines changed

6 files changed

+197
-179
lines changed

src/librustc/mir/repr.rs

+63-53
Original file line numberDiff line numberDiff line change
@@ -250,51 +250,58 @@ pub enum Terminator<'tcx> {
250250
func: Operand<'tcx>,
251251
/// Arguments the function is called with
252252
args: Vec<Operand<'tcx>>,
253-
/// Location to write the return value into
254-
destination: Lvalue<'tcx>,
255-
targets: CallTargets,
253+
/// The kind of call with associated information
254+
kind: CallKind<'tcx>,
256255
},
257-
258-
/// Block ends with a call of a diverging function.
259-
DivergingCall {
260-
/// The function that’s being called
261-
func: Operand<'tcx>,
262-
/// Arguments the function is called with
263-
args: Vec<Operand<'tcx>>,
264-
/// Some, if there’s any cleanup to be done when function unwinds
265-
cleanup: Option<BasicBlock>,
266-
}
267256
}
268257

269-
#[derive(Clone, Copy, RustcEncodable, RustcDecodable)]
270-
pub enum CallTargets {
271-
/// The only target that should be entered when function returns normally.
272-
Return(BasicBlock),
273-
/// In addition to the normal-return block, function has associated cleanup that should be done
274-
/// when function unwinds.
275-
WithCleanup((BasicBlock, BasicBlock))
258+
#[derive(Clone, RustcEncodable, RustcDecodable)]
259+
pub enum CallKind<'tcx> {
260+
/// Diverging function without associated cleanup
261+
Diverging,
262+
/// Diverging function with associated cleanup
263+
DivergingCleanup(BasicBlock),
264+
/// Converging function without associated cleanup
265+
Converging {
266+
/// Destination where the call result is written
267+
destination: Lvalue<'tcx>,
268+
/// Block to branch into on successful return
269+
target: BasicBlock,
270+
},
271+
ConvergingCleanup {
272+
/// Destination where the call result is written
273+
destination: Lvalue<'tcx>,
274+
/// First target is branched to on successful return.
275+
/// Second block contains the cleanups to do on unwind.
276+
targets: (BasicBlock, BasicBlock)
277+
}
276278
}
277279

278-
impl CallTargets {
279-
pub fn new(ret: BasicBlock, cleanup: Option<BasicBlock>) -> CallTargets {
280-
if let Some(c) = cleanup {
281-
CallTargets::WithCleanup((ret, c))
282-
} else {
283-
CallTargets::Return(ret)
280+
impl<'tcx> CallKind<'tcx> {
281+
pub fn successors(&self) -> &[BasicBlock] {
282+
match *self {
283+
CallKind::Diverging => &[],
284+
CallKind::DivergingCleanup(ref b) |
285+
CallKind::Converging { target: ref b, .. } => slice::ref_slice(b),
286+
CallKind::ConvergingCleanup { ref targets, .. } => targets.as_slice(),
284287
}
285288
}
286289

287-
pub fn as_slice(&self) -> &[BasicBlock] {
290+
pub fn successors_mut(&mut self) -> &mut [BasicBlock] {
288291
match *self {
289-
CallTargets::Return(ref b) => slice::ref_slice(b),
290-
CallTargets::WithCleanup(ref bs) => bs.as_slice()
292+
CallKind::Diverging => &mut [],
293+
CallKind::DivergingCleanup(ref mut b) |
294+
CallKind::Converging { target: ref mut b, .. } => slice::mut_ref_slice(b),
295+
CallKind::ConvergingCleanup { ref mut targets, .. } => targets.as_mut_slice(),
291296
}
292297
}
293298

294-
pub fn as_mut_slice(&mut self) -> &mut [BasicBlock] {
299+
pub fn destination(&self) -> Option<Lvalue<'tcx>> {
295300
match *self {
296-
CallTargets::Return(ref mut b) => slice::mut_ref_slice(b),
297-
CallTargets::WithCleanup(ref mut bs) => bs.as_mut_slice()
301+
CallKind::Converging { ref destination, .. } |
302+
CallKind::ConvergingCleanup { ref destination, .. } => Some(destination.clone()),
303+
CallKind::Diverging |
304+
CallKind::DivergingCleanup(_) => None
298305
}
299306
}
300307
}
@@ -309,12 +316,7 @@ impl<'tcx> Terminator<'tcx> {
309316
SwitchInt { targets: ref b, .. } => b,
310317
Resume => &[],
311318
Return => &[],
312-
Call { targets: ref b, .. } => b.as_slice(),
313-
DivergingCall { cleanup: ref b, .. } => if let Some(b) = b.as_ref() {
314-
slice::ref_slice(b)
315-
} else {
316-
&mut []
317-
},
319+
Call { ref kind, .. } => kind.successors(),
318320
}
319321
}
320322

@@ -327,12 +329,7 @@ impl<'tcx> Terminator<'tcx> {
327329
SwitchInt { targets: ref mut b, .. } => b,
328330
Resume => &mut [],
329331
Return => &mut [],
330-
Call { targets: ref mut b, .. } => b.as_mut_slice(),
331-
DivergingCall { cleanup: ref mut b, .. } => if let Some(b) = b.as_mut() {
332-
slice::mut_ref_slice(b)
333-
} else {
334-
&mut []
335-
},
332+
Call { ref mut kind, .. } => kind.successors_mut(),
336333
}
337334
}
338335
}
@@ -399,13 +396,18 @@ impl<'tcx> Terminator<'tcx> {
399396
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
400397
Return => write!(fmt, "return"),
401398
Resume => write!(fmt, "resume"),
402-
Call { .. } => {
403-
// the author didn’t bother rebasing this
404-
unimplemented!()
405-
},
406-
DivergingCall { .. } => {
407-
// the author didn’t bother rebasing this
408-
unimplemented!()
399+
Call { ref kind, ref func, ref args } => {
400+
if let Some(destination) = kind.destination() {
401+
try!(write!(fmt, "{:?} = ", destination));
402+
}
403+
try!(write!(fmt, "{:?}(", func));
404+
for (index, arg) in args.iter().enumerate() {
405+
if index > 0 {
406+
try!(write!(fmt, ", "));
407+
}
408+
try!(write!(fmt, "{:?}", arg));
409+
}
410+
write!(fmt, ")")
409411
}
410412
}
411413
}
@@ -417,8 +419,6 @@ impl<'tcx> Terminator<'tcx> {
417419
Return | Resume => vec![],
418420
Goto { .. } => vec!["".into_cow()],
419421
If { .. } => vec!["true".into_cow(), "false".into_cow()],
420-
Call { .. } => vec!["return".into_cow(), "unwind".into_cow()],
421-
DivergingCall { .. } => vec!["unwind".into_cow()],
422422
Switch { ref adt_def, .. } => {
423423
adt_def.variants
424424
.iter()
@@ -435,6 +435,16 @@ impl<'tcx> Terminator<'tcx> {
435435
.chain(iter::once(String::from("otherwise").into_cow()))
436436
.collect()
437437
}
438+
Call { ref kind, .. } => match *kind {
439+
CallKind::Diverging =>
440+
vec![],
441+
CallKind::DivergingCleanup(..) =>
442+
vec!["unwind".into_cow()],
443+
CallKind::Converging { .. } =>
444+
vec!["return".into_cow()],
445+
CallKind::ConvergingCleanup { .. } =>
446+
vec!["return".into_cow(), "unwind".into_cow()],
447+
},
438448
}
439449
}
440450
}

src/librustc/mir/visit.rs

+8-27
Original file line numberDiff line numberDiff line change
@@ -136,23 +136,15 @@ pub trait Visitor<'tcx> {
136136
Terminator::Return => {
137137
}
138138

139-
Terminator::Call { ref func, ref args, ref destination, ref targets } => {
140-
self.visit_lvalue(destination, LvalueContext::Store);
141-
self.visit_operand(func);
142-
for arg in args {
143-
self.visit_operand(arg);
144-
}
145-
for &target in targets.as_slice() {
146-
self.visit_branch(block, target);
139+
Terminator::Call { ref func, ref args, ref kind } => {
140+
if let Some(ref destination) = kind.destination() {
141+
self.visit_lvalue(destination, LvalueContext::Store);
147142
}
148-
}
149-
150-
Terminator::DivergingCall { ref func, ref args, ref cleanup } => {
151143
self.visit_operand(func);
152144
for arg in args {
153145
self.visit_operand(arg);
154146
}
155-
for &target in cleanup.as_ref() {
147+
for &target in kind.successors() {
156148
self.visit_branch(block, target);
157149
}
158150
}
@@ -432,26 +424,15 @@ pub trait MutVisitor<'tcx> {
432424
Terminator::Return => {
433425
}
434426

435-
Terminator::Call { ref mut func,
436-
ref mut args,
437-
ref mut destination,
438-
ref mut targets } => {
439-
self.visit_lvalue(destination, LvalueContext::Store);
440-
self.visit_operand(func);
441-
for arg in args {
442-
self.visit_operand(arg);
443-
}
444-
for &target in targets.as_slice() {
445-
self.visit_branch(block, target);
427+
Terminator::Call { ref mut func, ref mut args, ref mut kind } => {
428+
if let Some(ref mut destination) = kind.destination() {
429+
self.visit_lvalue(destination, LvalueContext::Store);
446430
}
447-
}
448-
449-
Terminator::DivergingCall { ref mut func, ref mut args, ref mut cleanup } => {
450431
self.visit_operand(func);
451432
for arg in args {
452433
self.visit_operand(arg);
453434
}
454-
for &target in cleanup.as_ref() {
435+
for &target in kind.successors() {
455436
self.visit_branch(block, target);
456437
}
457438
}

src/librustc_mir/build/expr/into.rs

+15-10
Original file line numberDiff line numberDiff line change
@@ -224,17 +224,22 @@ impl<'a,'tcx> Builder<'a,'tcx> {
224224

225225
let success = this.cfg.start_new_block();
226226
let cleanup = this.diverge_cleanup();
227-
let term = if diverges {
228-
Terminator::DivergingCall { func: fun, args: args, cleanup: cleanup }
229-
} else {
230-
Terminator::Call {
231-
func: fun,
232-
args: args,
233-
destination: destination.clone(),
234-
targets: CallTargets::new(success, cleanup)
227+
this.cfg.terminate(block, Terminator::Call {
228+
func: fun,
229+
args: args,
230+
kind: match (cleanup, diverges) {
231+
(None, true) => CallKind::Diverging,
232+
(Some(c), true) => CallKind::DivergingCleanup(c),
233+
(None, false) => CallKind::Converging {
234+
destination: destination.clone(),
235+
target: success
236+
},
237+
(Some(c), false) => CallKind::ConvergingCleanup {
238+
destination: destination.clone(),
239+
targets: (success, c)
240+
}
235241
}
236-
};
237-
this.cfg.terminate(block, term);
242+
});
238243
success.unit()
239244
}
240245

src/librustc_mir/build/scope.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,6 @@ impl<'a,'tcx> Builder<'a,'tcx> {
302302
index: Operand<'tcx>,
303303
len: Operand<'tcx>,
304304
span: Span) {
305-
let cleanup = self.diverge_cleanup();
306305
let func = self.lang_function(lang_items::PanicBoundsCheckFnLangItem);
307306
let str_ty = self.hir.tcx().mk_static_str();
308307
let tup_ty = self.hir.tcx().mk_tup(vec![str_ty, self.hir.tcx().types.u32]);
@@ -316,16 +315,19 @@ impl<'a,'tcx> Builder<'a,'tcx> {
316315
// FIXME: ReStatic might be wrong here?
317316
self.cfg.push_assign(block, DUMMY_SP, &tuple_ref, // tuple_ref = &tuple;
318317
Rvalue::Ref(*ref_region, BorrowKind::Unique, tuple));
319-
self.cfg.terminate(block, Terminator::DivergingCall {
318+
let cleanup = self.diverge_cleanup();
319+
self.cfg.terminate(block, Terminator::Call {
320320
func: func,
321321
args: vec![Operand::Consume(tuple_ref), index, len],
322-
cleanup: cleanup,
322+
kind: match cleanup {
323+
None => CallKind::Diverging,
324+
Some(c) => CallKind::DivergingCleanup(c)
325+
}
323326
});
324327
}
325328

326329
/// Create diverge cleanup and branch to it from `block`.
327330
pub fn panic(&mut self, block: BasicBlock, msg: &'static str, span: Span) {
328-
let cleanup = self.diverge_cleanup();
329331
let func = self.lang_function(lang_items::PanicFnLangItem);
330332

331333
let str_ty = self.hir.tcx().mk_static_str();
@@ -348,11 +350,14 @@ impl<'a,'tcx> Builder<'a,'tcx> {
348350
// FIXME: ReStatic might be wrong here?
349351
self.cfg.push_assign(block, DUMMY_SP, &tuple_ref, // tuple_ref = &tuple;
350352
Rvalue::Ref(*ref_region, BorrowKind::Unique, tuple));
351-
352-
self.cfg.terminate(block, Terminator::DivergingCall {
353+
let cleanup = self.diverge_cleanup();
354+
self.cfg.terminate(block, Terminator::Call {
353355
func: func,
354356
args: vec![Operand::Consume(tuple_ref)],
355-
cleanup: cleanup,
357+
kind: match cleanup {
358+
None => CallKind::Diverging,
359+
Some(c) => CallKind::DivergingCleanup(c)
360+
}
356361
});
357362
}
358363

src/librustc_mir/transform/erase_regions.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,10 @@ impl<'a, 'tcx> EraseRegions<'a, 'tcx> {
9393
self.erase_regions_lvalue(discr);
9494
*switch_ty = self.tcx.erase_regions(switch_ty);
9595
},
96-
Terminator::Call { ref mut destination, ref mut func, ref mut args, .. } => {
97-
self.erase_regions_lvalue(destination);
98-
self.erase_regions_operand(func);
99-
for arg in &mut *args {
100-
self.erase_regions_operand(arg);
96+
Terminator::Call { ref mut func, ref mut args, ref mut kind } => {
97+
if let Some(ref mut destination) = kind.destination() {
98+
self.erase_regions_lvalue(destination);
10199
}
102-
}
103-
Terminator::DivergingCall { ref mut func, ref mut args, .. } => {
104100
self.erase_regions_operand(func);
105101
for arg in &mut *args {
106102
self.erase_regions_operand(arg);

0 commit comments

Comments
 (0)