about summary refs log tree commit diff
path: root/compiler/rustc_mir_build/src
diff options
context:
space:
mode:
authorBen Kimock <kimockb@gmail.com>2025-08-04 13:10:09 +0000
committerGitHub <noreply@github.com>2025-08-04 13:10:09 +0000
commitee1b237215ee90df2c0102457fa2d0e9c2df8753 (patch)
treed7b99f917db35f8a07550c15b2544e0563612b5e /compiler/rustc_mir_build/src
parentee00b998177899c10bea83a38c46627f27496ba2 (diff)
parentab7c35995d9489821cc8b70ac1da069090ee56c9 (diff)
downloadrust-ee1b237215ee90df2c0102457fa2d0e9c2df8753.tar.gz
rust-ee1b237215ee90df2c0102457fa2d0e9c2df8753.zip
Merge pull request #4513 from rust-lang/rustup-2025-08-04
Automatic Rustup
Diffstat (limited to 'compiler/rustc_mir_build/src')
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/as_operand.rs4
-rw-r--r--compiler/rustc_mir_build/src/check_tail_calls.rs71
-rw-r--r--compiler/rustc_mir_build/src/errors.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs4
4 files changed, 73 insertions, 10 deletions
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_operand.rs b/compiler/rustc_mir_build/src/builder/expr/as_operand.rs
index 982e7aa8246..6a422223990 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_operand.rs
@@ -57,7 +57,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// ```
     /// #![feature(unsized_fn_params)]
     /// # use core::fmt::Debug;
-    /// fn foo(_p: dyn Debug) { /* ... */ }
+    /// fn foo(_p: dyn Debug) {
+    ///     /* ... */
+    /// }
     ///
     /// fn bar(box_p: Box<dyn Debug>) { foo(*box_p); }
     /// ```
diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs
index 18db8c1debb..b4c8b20e50f 100644
--- a/compiler/rustc_mir_build/src/check_tail_calls.rs
+++ b/compiler/rustc_mir_build/src/check_tail_calls.rs
@@ -89,22 +89,39 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
             self.report_op(ty, args, fn_span, expr);
         }
 
-        // Closures in thir look something akin to
-        // `for<'a> extern "rust-call" fn(&'a [closure@...], ()) -> <[closure@...] as FnOnce<()>>::Output {<[closure@...] as Fn<()>>::call}`
-        // So we have to check for them in this weird way...
         if let &ty::FnDef(did, args) = ty.kind() {
+            // Closures in thir look something akin to
+            // `for<'a> extern "rust-call" fn(&'a [closure@...], ()) -> <[closure@...] as FnOnce<()>>::Output {<[closure@...] as Fn<()>>::call}`
+            // So we have to check for them in this weird way...
             let parent = self.tcx.parent(did);
             if self.tcx.fn_trait_kind_from_def_id(parent).is_some()
-                && args.first().and_then(|arg| arg.as_type()).is_some_and(Ty::is_closure)
+                && let Some(this) = args.first()
+                && let Some(this) = this.as_type()
             {
-                self.report_calling_closure(&self.thir[fun], args[1].as_type().unwrap(), expr);
+                if this.is_closure() {
+                    self.report_calling_closure(&self.thir[fun], args[1].as_type().unwrap(), expr);
+                } else {
+                    // This can happen when tail calling `Box` that wraps a function
+                    self.report_nonfn_callee(fn_span, self.thir[fun].span, this);
+                }
 
                 // Tail calling is likely to cause unrelated errors (ABI, argument mismatches),
                 // skip them, producing an error about calling a closure is enough.
                 return;
             };
+
+            if self.tcx.intrinsic(did).is_some() {
+                self.report_calling_intrinsic(expr);
+            }
         }
 
+        let (ty::FnDef(..) | ty::FnPtr(..)) = ty.kind() else {
+            self.report_nonfn_callee(fn_span, self.thir[fun].span, ty);
+
+            // `fn_sig` below panics otherwise
+            return;
+        };
+
         // Erase regions since tail calls don't care about lifetimes
         let callee_sig =
             self.tcx.normalize_erasing_late_bound_regions(self.typing_env, ty.fn_sig(self.tcx));
@@ -280,6 +297,50 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
         self.found_errors = Err(err);
     }
 
+    fn report_calling_intrinsic(&mut self, expr: &Expr<'_>) {
+        let err = self
+            .tcx
+            .dcx()
+            .struct_span_err(expr.span, "tail calling intrinsics is not allowed")
+            .emit();
+
+        self.found_errors = Err(err);
+    }
+
+    fn report_nonfn_callee(&mut self, call_sp: Span, fun_sp: Span, ty: Ty<'_>) {
+        let mut err = self
+            .tcx
+            .dcx()
+            .struct_span_err(
+                call_sp,
+                "tail calls can only be performed with function definitions or pointers",
+            )
+            .with_note(format!("callee has type `{ty}`"));
+
+        let mut ty = ty;
+        let mut refs = 0;
+        while ty.is_box() || ty.is_ref() {
+            ty = ty.builtin_deref(false).unwrap();
+            refs += 1;
+        }
+
+        if refs > 0 && ty.is_fn() {
+            let thing = if ty.is_fn_ptr() { "pointer" } else { "definition" };
+
+            let derefs =
+                std::iter::once('(').chain(std::iter::repeat_n('*', refs)).collect::<String>();
+
+            err.multipart_suggestion(
+                format!("consider dereferencing the expression to get a function {thing}"),
+                vec![(fun_sp.shrink_to_lo(), derefs), (fun_sp.shrink_to_hi(), ")".to_owned())],
+                Applicability::MachineApplicable,
+            );
+        }
+
+        let err = err.emit();
+        self.found_errors = Err(err);
+    }
+
     fn report_abi_mismatch(&mut self, sp: Span, caller_abi: ExternAbi, callee_abi: ExternAbi) {
         let err = self
             .tcx
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index f1fbd5c4a49..1a52c6c85cb 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1254,8 +1254,8 @@ pub(crate) struct ConstContinueBadConst {
 }
 
 #[derive(Diagnostic)]
-#[diag(mir_build_const_continue_missing_value)]
-pub(crate) struct ConstContinueMissingValue {
+#[diag(mir_build_const_continue_missing_label_or_value)]
+pub(crate) struct ConstContinueMissingLabelOrValue {
     #[primary_span]
     pub span: Span,
 }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index a0d3913c159..81b0e21a5f5 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -852,9 +852,9 @@ impl<'tcx> ThirBuildCx<'tcx> {
                 if find_attr!(self.tcx.hir_attrs(expr.hir_id), AttributeKind::ConstContinue(_)) {
                     match dest.target_id {
                         Ok(target_id) => {
-                            let Some(value) = value else {
+                            let (Some(value), Some(_)) = (value, dest.label) else {
                                 let span = expr.span;
-                                self.tcx.dcx().emit_fatal(ConstContinueMissingValue { span })
+                                self.tcx.dcx().emit_fatal(ConstContinueMissingLabelOrValue { span })
                             };
 
                             ExprKind::ConstContinue {