diff options
Diffstat (limited to 'compiler/rustc_middle/src')
| -rw-r--r-- | compiler/rustc_middle/src/mir/pretty.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/syntax.rs | 31 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/terminator.rs | 13 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/visit.rs | 11 |
4 files changed, 68 insertions, 4 deletions
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index af19ed95193..82625ae3d47 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -854,6 +854,16 @@ impl<'tcx> TerminatorKind<'tcx> { } write!(fmt, ")") } + TailCall { func, args, .. } => { + write!(fmt, "tailcall {func:?}(")?; + for (index, arg) in args.iter().enumerate() { + if index > 0 { + write!(fmt, ", ")?; + } + write!(fmt, "{:?}", arg)?; + } + write!(fmt, ")") + } Assert { cond, expected, msg, .. } => { write!(fmt, "assert(")?; if !expected { @@ -921,7 +931,12 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> { use self::TerminatorKind::*; match *self { - Return | UnwindResume | UnwindTerminate(_) | Unreachable | CoroutineDrop => vec![], + Return + | TailCall { .. } + | UnwindResume + | UnwindTerminate(_) + | Unreachable + | CoroutineDrop => vec![], Goto { .. } => vec!["".into()], SwitchInt { ref targets, .. } => targets .values diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 2c2884f1897..620fa962d79 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -744,6 +744,36 @@ pub enum TerminatorKind<'tcx> { fn_span: Span, }, + /// Tail call. + /// + /// Roughly speaking this is a chimera of [`Call`] and [`Return`], with some caveats. + /// Semantically tail calls consists of two actions: + /// - pop of the current stack frame + /// - a call to the `func`, with the return address of the **current** caller + /// - so that a `return` inside `func` returns to the caller of the caller + /// of the function that is currently being executed + /// + /// Note that in difference with [`Call`] this is missing + /// - `destination` (because it's always the return place) + /// - `target` (because it's always taken from the current stack frame) + /// - `unwind` (because it's always taken from the current stack frame) + /// + /// [`Call`]: TerminatorKind::Call + /// [`Return`]: TerminatorKind::Return + TailCall { + /// The function that’s being called. + func: Operand<'tcx>, + /// Arguments the function is called with. + /// These are owned by the callee, which is free to modify them. + /// This allows the memory occupied by "by-value" arguments to be + /// reused across function calls without duplicating the contents. + args: Box<[Spanned<Operand<'tcx>>]>, + // FIXME(explicit_tail_calls): should we have the span for `become`? is this span accurate? do we need it? + /// This `Span` is the span of the function, without the dot and receiver + /// (e.g. `foo(a, b)` in `x.foo(a, b)` + fn_span: Span, + }, + /// Evaluates the operand, which must have type `bool`. If it is not equal to `expected`, /// initiates a panic. Initiating a panic corresponds to a `Call` terminator with some /// unspecified constant as the function to call, all the operands stored in the `AssertMessage` @@ -870,6 +900,7 @@ impl TerminatorKind<'_> { TerminatorKind::Unreachable => "Unreachable", TerminatorKind::Drop { .. } => "Drop", TerminatorKind::Call { .. } => "Call", + TerminatorKind::TailCall { .. } => "TailCall", TerminatorKind::Assert { .. } => "Assert", TerminatorKind::Yield { .. } => "Yield", TerminatorKind::CoroutineDrop => "CoroutineDrop", diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index ed592612358..5b035d9579d 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -439,6 +439,7 @@ mod helper { | CoroutineDrop | Return | Unreachable + | TailCall { .. } | Call { target: None, unwind: _, .. } => (&[]).into_iter().copied().chain(None), InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => { targets.iter().copied().chain(Some(u)) @@ -479,6 +480,7 @@ mod helper { | CoroutineDrop | Return | Unreachable + | TailCall { .. } | Call { target: None, unwind: _, .. } => (&mut []).into_iter().chain(None), InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => { targets.iter_mut().chain(Some(u)) @@ -501,6 +503,7 @@ impl<'tcx> TerminatorKind<'tcx> { | TerminatorKind::UnwindResume | TerminatorKind::UnwindTerminate(_) | TerminatorKind::Return + | TerminatorKind::TailCall { .. } | TerminatorKind::Unreachable | TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } @@ -521,6 +524,7 @@ impl<'tcx> TerminatorKind<'tcx> { | TerminatorKind::UnwindResume | TerminatorKind::UnwindTerminate(_) | TerminatorKind::Return + | TerminatorKind::TailCall { .. } | TerminatorKind::Unreachable | TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } @@ -606,9 +610,12 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> { use TerminatorKind::*; match *self { - Return | UnwindResume | UnwindTerminate(_) | CoroutineDrop | Unreachable => { - TerminatorEdges::None - } + Return + | TailCall { .. } + | UnwindResume + | UnwindTerminate(_) + | CoroutineDrop + | Unreachable => TerminatorEdges::None, Goto { target } => TerminatorEdges::Single(target), diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 7628a1ed2fe..0d3c419748b 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -540,6 +540,17 @@ macro_rules! make_mir_visitor { ); } + TerminatorKind::TailCall { + func, + args, + fn_span: _, + } => { + self.visit_operand(func, location); + for arg in args { + self.visit_operand(&$($mutability)? arg.node, location); + } + }, + TerminatorKind::Assert { cond, expected: _, |
