Auto merge of #81360 - Aaron1011:trait-caller-loc, r=nagisa
Support forwarding caller location through trait object method call Since PR #69251, the `#[track_caller]` attribute has been supported on traits. However, it only has an effect on direct (monomorphized) method calls. Calling a `#[track_caller]` method on a trait object will *not* propagate caller location information - instead, `Location::caller()` will return the location of the method definition. This PR forwards caller location information when `#[track_caller]` is present on the method definition in the trait. This is possible because `#[track_caller]` in this position is 'inherited' by any impls of that trait, so all implementations will have the same ABI. This PR does *not* change the behavior in the case where `#[track_caller]` is present only on the impl of a trait. While all implementations of the method might have an explicit `#[track_caller]`, we cannot know this at codegen time, since other crates may have impls of the trait. Therefore, we keep the current behavior of not forwarding the caller location, ensuring that all implementations of the trait will have the correct ABI. See the modified test for examples of how this works
This commit is contained in:
commit
3982eb35ca
5 changed files with 102 additions and 15 deletions
|
|
@ -2,22 +2,60 @@
|
|||
|
||||
trait Tracked {
|
||||
#[track_caller]
|
||||
fn handle(&self) {
|
||||
fn track_caller_trait_method(&self, line: u32, col: u32) {
|
||||
let location = std::panic::Location::caller();
|
||||
assert_eq!(location.file(), file!());
|
||||
// we only call this via trait object, so the def site should *always* be returned
|
||||
assert_eq!(location.line(), line!() - 4);
|
||||
// The trait method definition is annotated with `#[track_caller]`,
|
||||
// so caller location information will work through a method
|
||||
// call on a trait object
|
||||
assert_eq!(location.line(), line, "Bad line");
|
||||
assert_eq!(location.column(), col, "Bad col");
|
||||
}
|
||||
|
||||
fn track_caller_not_on_trait_method(&self);
|
||||
|
||||
#[track_caller]
|
||||
fn track_caller_through_self(self: Box<Self>, line: u32, col: u32);
|
||||
}
|
||||
|
||||
impl Tracked for () {
|
||||
// We have `#[track_caller]` on the implementation of the method,
|
||||
// but not on the definition of the method in the trait. Therefore,
|
||||
// caller location information will *not* work through a method call
|
||||
// on a trait object. Instead, we will get the location of this method
|
||||
#[track_caller]
|
||||
fn track_caller_not_on_trait_method(&self) {
|
||||
let location = std::panic::Location::caller();
|
||||
assert_eq!(location.file(), file!());
|
||||
assert_eq!(location.line(), line!() - 3);
|
||||
assert_eq!(location.column(), 5);
|
||||
}
|
||||
|
||||
// We don't have a `#[track_caller]` attribute, but
|
||||
// `#[track_caller]` is present on the trait definition,
|
||||
// so we'll still get location information
|
||||
fn track_caller_through_self(self: Box<Self>, line: u32, col: u32) {
|
||||
let location = std::panic::Location::caller();
|
||||
assert_eq!(location.file(), file!());
|
||||
// The trait method definition is annotated with `#[track_caller]`,
|
||||
// so caller location information will work through a method
|
||||
// call on a trait object
|
||||
assert_eq!(location.line(), line, "Bad line");
|
||||
assert_eq!(location.column(), col, "Bad col");
|
||||
}
|
||||
}
|
||||
|
||||
impl Tracked for () {}
|
||||
impl Tracked for u8 {}
|
||||
|
||||
fn main() {
|
||||
let tracked: &dyn Tracked = &5u8;
|
||||
tracked.handle();
|
||||
let tracked: &dyn Tracked = &();
|
||||
// The column is the start of 'track_caller_trait_method'
|
||||
tracked.track_caller_trait_method(line!(), 13);
|
||||
|
||||
const TRACKED: &dyn Tracked = &();
|
||||
TRACKED.handle();
|
||||
// The column is the start of 'track_caller_trait_method'
|
||||
TRACKED.track_caller_trait_method(line!(), 13);
|
||||
TRACKED.track_caller_not_on_trait_method();
|
||||
|
||||
// The column is the start of `track_caller_through_self`
|
||||
let boxed: Box<dyn Tracked> = Box::new(());
|
||||
boxed.track_caller_through_self(line!(), 11);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue