diff options
| author | Ben Kimock <kimockb@gmail.com> | 2025-08-04 13:10:09 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-04 13:10:09 +0000 |
| commit | ee1b237215ee90df2c0102457fa2d0e9c2df8753 (patch) | |
| tree | d7b99f917db35f8a07550c15b2544e0563612b5e /compiler/rustc_mir_build/src | |
| parent | ee00b998177899c10bea83a38c46627f27496ba2 (diff) | |
| parent | ab7c35995d9489821cc8b70ac1da069090ee56c9 (diff) | |
| download | rust-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.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/check_tail_calls.rs | 71 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/errors.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/cx/expr.rs | 4 |
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 { |
