diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index 3ecccb422c463..f93c24ae708c9 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -3,12 +3,13 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::Applicability; use rustc_hir::LangItem; use rustc_hir::def::DefKind; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::span_bug; use rustc_middle::thir::visit::{self, Visitor}; use rustc_middle::thir::{BodyTy, Expr, ExprId, ExprKind, Thir}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::{DefId, LocalDefId}; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; +use rustc_span::{ErrorGuaranteed, Span}; pub(crate) fn check_tail_calls(tcx: TyCtxt<'_>, def: LocalDefId) -> Result<(), ErrorGuaranteed> { let (thir, expr) = tcx.thir_body(def)?; @@ -20,7 +21,6 @@ pub(crate) fn check_tail_calls(tcx: TyCtxt<'_>, def: LocalDefId) -> Result<(), E } let is_closure = matches!(tcx.def_kind(def), DefKind::Closure); - let caller_ty = tcx.type_of(def).skip_binder(); let mut visitor = TailCallCkVisitor { tcx, @@ -29,7 +29,7 @@ pub(crate) fn check_tail_calls(tcx: TyCtxt<'_>, def: LocalDefId) -> Result<(), E // FIXME(#132279): we're clearly in a body here. typing_env: ty::TypingEnv::non_body_analysis(tcx, def), is_closure, - caller_ty, + caller_def_id: def, }; visitor.visit_expr(&thir[expr]); @@ -46,8 +46,8 @@ struct TailCallCkVisitor<'a, 'tcx> { /// The result of the checks, `Err(_)` if there was a problem with some /// tail call, `Ok(())` if all of them were fine. found_errors: Result<(), ErrorGuaranteed>, - /// Type of the caller function. - caller_ty: Ty<'tcx>, + /// `LocalDefId` of the caller function. + caller_def_id: LocalDefId, } impl<'tcx> TailCallCkVisitor<'_, 'tcx> { @@ -167,7 +167,7 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { // coercing the function to an `fn()` pointer. (although in that case the tailcall is // basically useless -- the shim calls the actual function, so tailcalling the shim is // equivalent to calling the function) - let caller_needs_location = self.needs_location(self.caller_ty); + let caller_needs_location = self.caller_needs_location(); if caller_needs_location { self.report_track_caller_caller(expr.span); @@ -183,19 +183,13 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { } } - /// Returns true if function of type `ty` needs location argument - /// (i.e. if a function is marked as `#[track_caller]`). - /// - /// Panics if the function's instance can't be immediately resolved. - fn needs_location(&self, ty: Ty<'tcx>) -> bool { - if let &ty::FnDef(did, substs) = ty.kind() { - let instance = - ty::Instance::expect_resolve(self.tcx, self.typing_env, did, substs, DUMMY_SP); - - instance.def.requires_caller_location(self.tcx) - } else { - false - } + /// Returns true if the caller function needs location argument + /// (i.e. if a function is marked as `#[track_caller]`) + fn caller_needs_location(&self) -> bool { + self.tcx + .codegen_fn_attrs(self.caller_def_id) + .flags + .contains(CodegenFnAttrFlags::TRACK_CALLER) } fn report_in_closure(&mut self, expr: &Expr<'_>) { diff --git a/tests/ui/explicit-tail-calls/caller_is_track_caller.rs b/tests/ui/explicit-tail-calls/caller_is_track_caller.rs index 4e5f3f12f8399..a3a116cbd61b6 100644 --- a/tests/ui/explicit-tail-calls/caller_is_track_caller.rs +++ b/tests/ui/explicit-tail-calls/caller_is_track_caller.rs @@ -13,4 +13,13 @@ fn c() { become a(); //~ error: a function marked with `#[track_caller]` cannot perform a tail-call } +trait Trait { + fn d(&self); + + #[track_caller] + fn e(&self) { + become self.d(); //~ error: a function marked with `#[track_caller]` cannot perform a tail-call + } +} + fn main() {} diff --git a/tests/ui/explicit-tail-calls/caller_is_track_caller.stderr b/tests/ui/explicit-tail-calls/caller_is_track_caller.stderr index 79b9b45986c47..8c2ebf67bdb96 100644 --- a/tests/ui/explicit-tail-calls/caller_is_track_caller.stderr +++ b/tests/ui/explicit-tail-calls/caller_is_track_caller.stderr @@ -10,5 +10,11 @@ error: a function marked with `#[track_caller]` cannot perform a tail-call LL | become a(); | ^^^^^^^^^^ -error: aborting due to 2 previous errors +error: a function marked with `#[track_caller]` cannot perform a tail-call + --> $DIR/caller_is_track_caller.rs:21:9 + | +LL | become self.d(); + | ^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors diff --git a/tests/ui/explicit-tail-calls/default-trait-method.rs b/tests/ui/explicit-tail-calls/default-trait-method.rs new file mode 100644 index 0000000000000..f53424450eb33 --- /dev/null +++ b/tests/ui/explicit-tail-calls/default-trait-method.rs @@ -0,0 +1,36 @@ +// A regression test for . +// Previously, using `become` in a default trait method would lead to an ICE +// in a path determining whether the method in question is marked as `#[track_caller]`. +// +//@ run-pass + +#![feature(explicit_tail_calls)] +#![expect(incomplete_features)] + +trait Trait { + fn bar(&self) -> usize { + 123 + } + + fn foo(&self) -> usize { + become self.bar(); + } +} + +struct Struct; + +impl Trait for Struct {} + +struct OtherStruct; + +impl Trait for OtherStruct { + #[track_caller] + fn bar(&self) -> usize { + 456 + } +} + +fn main() { + assert_eq!(Struct.foo(), 123); + assert_eq!(OtherStruct.foo(), 456); +}