Skip to content

Commit 97da6da

Browse files
committed
Allow #[track_caller] in traits.
The codegen implementation already works for this, so we're: * propagating track_caller attr from trait def to impl * relaxing errors * adding tests Approved in a recent lang team meeting: https://github.com/rust-lang/lang-team/blob/master/minutes/2020-01-09.md
1 parent d1e81ef commit 97da6da

15 files changed

+215
-107
lines changed

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#![feature(extern_types)]
3939
#![feature(nll)]
4040
#![feature(option_expect_none)]
41+
#![feature(or_patterns)]
4142
#![feature(range_is_empty)]
4243
#![feature(specialization)]
4344
#![feature(trusted_len)]

src/librustc/ty/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2875,8 +2875,8 @@ impl<'tcx> TyCtxt<'tcx> {
28752875
_ => false,
28762876
}
28772877
} else {
2878-
match self.def_kind(def_id).expect("no def for `DefId`") {
2879-
DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy => true,
2878+
match self.def_kind(def_id) {
2879+
Some(DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy) => true,
28802880
_ => false,
28812881
}
28822882
};
+4-41
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,11 @@
1-
`#[track_caller]` cannot be used in traits yet. This is due to limitations in
2-
the compiler which are likely to be temporary. See [RFC 2091] for details on
3-
this and other restrictions.
1+
`#[track_caller]` cannot be used to annotate foreign functions.
42

5-
Erroneous example with a trait method implementation:
3+
Erroneous example:
64

75
```compile_fail,E0738
86
#![feature(track_caller)]
9-
10-
trait Foo {
11-
fn bar(&self);
12-
}
13-
14-
impl Foo for u64 {
15-
#[track_caller]
16-
fn bar(&self) {}
17-
}
18-
```
19-
20-
Erroneous example with a blanket trait method implementation:
21-
22-
```compile_fail,E0738
23-
#![feature(track_caller)]
24-
25-
trait Foo {
7+
extern "Rust" {
268
#[track_caller]
27-
fn bar(&self) {}
28-
fn baz(&self);
9+
fn bar();
2910
}
3011
```
31-
32-
Erroneous example with a trait method declaration:
33-
34-
```compile_fail,E0738
35-
#![feature(track_caller)]
36-
37-
trait Foo {
38-
fn bar(&self) {}
39-
40-
#[track_caller]
41-
fn baz(&self);
42-
}
43-
```
44-
45-
Note that while the compiler may be able to support the attribute in traits in
46-
the future, [RFC 2091] prohibits their implementation without a follow-up RFC.
47-
48-
[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md

src/librustc_passes/check_attr.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -151,17 +151,17 @@ impl CheckAttrVisitor<'tcx> {
151151
.emit();
152152
false
153153
}
154-
Target::Fn | Target::Method(MethodKind::Inherent) => true,
155-
Target::Method(_) => {
154+
Target::ForeignFn => {
156155
struct_span_err!(
157156
self.tcx.sess,
158157
*attr_span,
159158
E0738,
160-
"`#[track_caller]` may not be used on trait methods",
159+
"`#[track_caller]` is not supported on foreign functions",
161160
)
162161
.emit();
163162
false
164163
}
164+
Target::Fn | Target::Method(..) => true,
165165
_ => {
166166
struct_span_err!(
167167
self.tcx.sess,

src/librustc_typeck/collect.rs

+29
Original file line numberDiff line numberDiff line change
@@ -2339,6 +2339,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
23392339
let attrs = tcx.get_attrs(id);
23402340

23412341
let mut codegen_fn_attrs = CodegenFnAttrs::new();
2342+
if should_inherit_track_caller(tcx, id) {
2343+
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
2344+
}
23422345

23432346
let whitelist = tcx.target_features_whitelist(LOCAL_CRATE);
23442347

@@ -2583,6 +2586,32 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
25832586
codegen_fn_attrs
25842587
}
25852588

2589+
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
2590+
/// applied to the method prototype.
2591+
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
2592+
if let Some(impl_item) = tcx.opt_associated_item(def_id) {
2593+
if let ty::AssocItemContainer::ImplContainer(impl_def_id) = impl_item.container {
2594+
if let Some(trait_def_id) = tcx.trait_id_of_impl(impl_def_id) {
2595+
if let Some(trait_item) = tcx
2596+
.associated_items(trait_def_id)
2597+
.filter_by_name_unhygienic(impl_item.ident.name)
2598+
.find(move |trait_item| {
2599+
trait_item.kind == ty::AssocKind::Method
2600+
&& tcx.hygienic_eq(impl_item.ident, trait_item.ident, trait_def_id)
2601+
})
2602+
{
2603+
return tcx
2604+
.codegen_fn_attrs(trait_item.def_id)
2605+
.flags
2606+
.intersects(CodegenFnAttrFlags::TRACK_CALLER);
2607+
}
2608+
}
2609+
}
2610+
}
2611+
2612+
false
2613+
}
2614+
25862615
fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<usize> {
25872616
use rustc_ast::ast::{Lit, LitIntType, LitKind};
25882617
let meta_item_list = attr.meta_item_list();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![feature(track_caller)]
2+
#![allow(dead_code)]
3+
4+
extern "Rust" {
5+
#[track_caller] //~ ERROR: `#[track_caller]` is not supported on foreign functions
6+
fn bar();
7+
}
8+
9+
fn main() {}

src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr renamed to src/test/ui/rfc-2091-track-caller/error-extern-fn.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
error[E0738]: `#[track_caller]` may not be used on trait methods
2-
--> $DIR/error-with-trait-decl.rs:4:5
1+
error[E0738]: `#[track_caller]` is not supported on foreign functions
2+
--> $DIR/error-extern-fn.rs:5:5
33
|
44
LL | #[track_caller]
55
| ^^^^^^^^^^^^^^^

src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs

-12
This file was deleted.

src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs

-8
This file was deleted.

src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr

-9
This file was deleted.

src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs

-21
This file was deleted.

src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr

-9
This file was deleted.

src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs

+43
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,49 @@ fn tracked_unit(_: ()) {
1414
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
1515
}
1616

17+
trait Trait {
18+
fn trait_tracked_unit(_: ());
19+
}
20+
21+
impl Trait for () {
22+
#[track_caller]
23+
fn trait_tracked_unit(_: ()) {
24+
let expected_line = line!() - 1;
25+
let location = std::panic::Location::caller();
26+
assert_eq!(location.file(), file!());
27+
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
28+
}
29+
}
30+
31+
trait TrackedTrait {
32+
#[track_caller]
33+
fn trait_tracked_unit_default(_: ()) {
34+
let expected_line = line!() - 1;
35+
let location = std::panic::Location::caller();
36+
assert_eq!(location.file(), file!());
37+
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
38+
}
39+
}
40+
41+
impl TrackedTrait for () {}
42+
43+
trait BlanketTrackedTrait {
44+
#[track_caller]
45+
fn tracked_blanket(_: ());
46+
}
47+
48+
impl BlanketTrackedTrait for () {
49+
fn tracked_blanket(_: ()) {
50+
let expected_line = line!() - 1;
51+
let location = std::panic::Location::caller();
52+
assert_eq!(location.file(), file!());
53+
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
54+
}
55+
}
56+
1757
fn main() {
1858
pass_to_ptr_call(tracked_unit, ());
59+
pass_to_ptr_call(<() as Trait>::trait_tracked_unit, ());
60+
pass_to_ptr_call(<() as TrackedTrait>::trait_tracked_unit_default, ());
61+
pass_to_ptr_call(<() as BlanketTrackedTrait>::tracked_blanket, ());
1962
}

src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs

+43
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,49 @@ fn tracked() {
1414
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
1515
}
1616

17+
trait Trait {
18+
fn trait_tracked();
19+
}
20+
21+
impl Trait for () {
22+
#[track_caller]
23+
fn trait_tracked() {
24+
let expected_line = line!() - 1;
25+
let location = std::panic::Location::caller();
26+
assert_eq!(location.file(), file!());
27+
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
28+
}
29+
}
30+
31+
trait TrackedTrait {
32+
#[track_caller]
33+
fn trait_tracked_default() {
34+
let expected_line = line!() - 1;
35+
let location = std::panic::Location::caller();
36+
assert_eq!(location.file(), file!());
37+
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
38+
}
39+
}
40+
41+
impl TrackedTrait for () {}
42+
43+
trait TraitBlanketTracked {
44+
#[track_caller]
45+
fn tracked_blanket();
46+
}
47+
48+
impl TraitBlanketTracked for () {
49+
fn tracked_blanket() {
50+
let expected_line = line!() - 1;
51+
let location = std::panic::Location::caller();
52+
assert_eq!(location.file(), file!());
53+
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
54+
}
55+
}
56+
1757
fn main() {
1858
ptr_call(tracked);
59+
ptr_call(<() as Trait>::trait_tracked);
60+
ptr_call(<() as TrackedTrait>::trait_tracked_default);
61+
ptr_call(<() as TraitBlanketTracked>::tracked_blanket);
1962
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// run-pass
2+
3+
#![feature(track_caller)]
4+
5+
macro_rules! assert_expansion_site_is_tracked {
6+
() => {{
7+
let location = std::panic::Location::caller();
8+
assert_eq!(location.file(), file!());
9+
assert_ne!(location.line(), line!(), "line should be outside this fn");
10+
}}
11+
}
12+
13+
trait Tracked {
14+
fn local_tracked(&self);
15+
16+
#[track_caller]
17+
fn blanket_tracked(&self);
18+
19+
#[track_caller]
20+
fn default_tracked(&self) {
21+
assert_expansion_site_is_tracked!();
22+
}
23+
}
24+
25+
impl Tracked for () {
26+
#[track_caller]
27+
fn local_tracked(&self) {
28+
assert_expansion_site_is_tracked!();
29+
}
30+
31+
fn blanket_tracked(&self) {
32+
assert_expansion_site_is_tracked!();
33+
}
34+
}
35+
36+
impl Tracked for bool {
37+
#[track_caller]
38+
fn local_tracked(&self) {
39+
assert_expansion_site_is_tracked!();
40+
}
41+
42+
fn blanket_tracked(&self) {
43+
assert_expansion_site_is_tracked!();
44+
}
45+
46+
fn default_tracked(&self) {
47+
assert_expansion_site_is_tracked!();
48+
}
49+
}
50+
51+
impl Tracked for u8 {
52+
#[track_caller]
53+
fn local_tracked(&self) {
54+
assert_expansion_site_is_tracked!();
55+
}
56+
57+
fn blanket_tracked(&self) {
58+
assert_expansion_site_is_tracked!();
59+
}
60+
61+
#[track_caller]
62+
fn default_tracked(&self) {
63+
assert_expansion_site_is_tracked!();
64+
}
65+
}
66+
67+
fn main() {
68+
().local_tracked();
69+
().default_tracked();
70+
().blanket_tracked();
71+
72+
true.local_tracked();
73+
true.default_tracked();
74+
true.blanket_tracked();
75+
76+
0u8.local_tracked();
77+
0u8.default_tracked();
78+
0u8.blanket_tracked();
79+
}

0 commit comments

Comments
 (0)