about summary refs log tree commit diff
path: root/compiler/rustc_mir_build/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_build/src')
-rw-r--r--compiler/rustc_mir_build/src/build/expr/stmt.rs35
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs1
-rw-r--r--compiler/rustc_mir_build/src/lints.rs2
3 files changed, 36 insertions, 2 deletions
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index 2bdeb579a02..60ab843257d 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -2,7 +2,9 @@ use crate::build::scope::BreakableTarget;
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
+use rustc_middle::span_bug;
 use rustc_middle::thir::*;
+use rustc_span::source_map::Spanned;
 use tracing::debug;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -91,9 +93,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             ExprKind::Return { value } => {
                 this.break_scope(block, value, BreakableTarget::Return, source_info)
             }
-            // FIXME(explicit_tail_calls): properly lower tail calls here
             ExprKind::Become { value } => {
-                this.break_scope(block, Some(value), BreakableTarget::Return, source_info)
+                let v = &this.thir[value];
+                let ExprKind::Scope { value, .. } = v.kind else {
+                    span_bug!(v.span, "`thir_check_tail_calls` should have disallowed this {v:?}")
+                };
+
+                let v = &this.thir[value];
+                let ExprKind::Call { ref args, fun, fn_span, .. } = v.kind else {
+                    span_bug!(v.span, "`thir_check_tail_calls` should have disallowed this {v:?}")
+                };
+
+                let fun = unpack!(block = this.as_local_operand(block, fun));
+                let args: Vec<_> = args
+                    .into_iter()
+                    .copied()
+                    .map(|arg| Spanned {
+                        node: unpack!(block = this.as_local_call_operand(block, arg)),
+                        span: this.thir.exprs[arg].span,
+                    })
+                    .collect();
+
+                this.record_operands_moved(&args);
+
+                debug!("expr_into_dest: fn_span={:?}", fn_span);
+
+                this.cfg.terminate(
+                    block,
+                    source_info,
+                    TerminatorKind::TailCall { func: fun, args, fn_span },
+                );
+
+                this.cfg.start_new_block().unit()
             }
             _ => {
                 assert!(
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 5b6de39bb2e..9e7534a283d 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -1523,6 +1523,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
             | TerminatorKind::UnwindResume
             | TerminatorKind::UnwindTerminate(_)
             | TerminatorKind::Return
+            | TerminatorKind::TailCall { .. }
             | TerminatorKind::Unreachable
             | TerminatorKind::Yield { .. }
             | TerminatorKind::CoroutineDrop
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index 1c7aa9f9ed0..3cb83a48ffe 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -196,6 +196,8 @@ impl<'mir, 'tcx, C: TerminatorClassifier<'tcx>> TriColorVisitor<BasicBlocks<'tcx
             | TerminatorKind::CoroutineDrop
             | TerminatorKind::UnwindResume
             | TerminatorKind::Return
+            // FIXME(explicit_tail_calls) Is this right??
+            | TerminatorKind::TailCall { .. }
             | TerminatorKind::Unreachable
             | TerminatorKind::Yield { .. } => ControlFlow::Break(NonRecursive),