Skip to content

Commit ae5bb7e

Browse files
authored
Rollup merge of #65037 - anp:track-caller, r=oli-obk
`#[track_caller]` feature gate (RFC 2091 1/N) RFC text: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md Tracking issue: #47809 I started with @ayosec's commit to add the feature gate with tests and rebased it onto current master. I fixed up some tidy lints and added a test.
2 parents 27240fe + cca58d1 commit ae5bb7e

28 files changed

+395
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# `track_caller`
2+
3+
The tracking issue for this feature is: [#47809](https://github.com/rust-lang/rust/issues/47809).
4+
5+
------------------------

src/librustc/error_codes.rs

+20
Original file line numberDiff line numberDiff line change
@@ -2120,6 +2120,25 @@ These attributes are meant to only be used by the standard library and are
21202120
rejected in your own crates.
21212121
"##,
21222122

2123+
E0736: r##"
2124+
#[track_caller] and #[naked] cannot be applied to the same function.
2125+
2126+
Erroneous code example:
2127+
2128+
```compile_fail,E0736
2129+
#![feature(track_caller)]
2130+
2131+
#[naked]
2132+
#[track_caller]
2133+
fn foo() {}
2134+
```
2135+
2136+
This is primarily due to ABI incompatibilities between the two attributes.
2137+
See [RFC 2091] for details on this and other limitations.
2138+
2139+
[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
2140+
"##,
2141+
21232142
;
21242143
// E0006, // merged with E0005
21252144
// E0101, // replaced with E0282
@@ -2179,4 +2198,5 @@ rejected in your own crates.
21792198
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
21802199
E0727, // `async` generators are not yet supported
21812200
E0728, // `await` must be in an `async` function or block
2201+
E0739, // invalid track_caller application/syntax
21822202
}

src/librustc/hir/check_attr.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::ty::TyCtxt;
1111
use crate::ty::query::Providers;
1212

1313
use std::fmt::{self, Display};
14-
use syntax::symbol::sym;
14+
use syntax::{attr, symbol::sym};
1515
use syntax_pos::Span;
1616

1717
#[derive(Copy, Clone, PartialEq)]
@@ -103,6 +103,8 @@ impl CheckAttrVisitor<'tcx> {
103103
self.check_marker(attr, item, target)
104104
} else if attr.check_name(sym::target_feature) {
105105
self.check_target_feature(attr, item, target)
106+
} else if attr.check_name(sym::track_caller) {
107+
self.check_track_caller(attr, &item, target)
106108
} else {
107109
true
108110
};
@@ -135,6 +137,32 @@ impl CheckAttrVisitor<'tcx> {
135137
}
136138
}
137139

140+
/// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
141+
fn check_track_caller(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) -> bool {
142+
if target != Target::Fn {
143+
struct_span_err!(
144+
self.tcx.sess,
145+
attr.span,
146+
E0739,
147+
"attribute should be applied to function"
148+
)
149+
.span_label(item.span, "not a function")
150+
.emit();
151+
false
152+
} else if attr::contains_name(&item.attrs, sym::naked) {
153+
struct_span_err!(
154+
self.tcx.sess,
155+
attr.span,
156+
E0736,
157+
"cannot use `#[track_caller]` with `#[naked]`",
158+
)
159+
.emit();
160+
false
161+
} else {
162+
true
163+
}
164+
}
165+
138166
/// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
139167
fn check_non_exhaustive(
140168
&self,

src/librustc/hir/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2734,7 +2734,9 @@ bitflags! {
27342734
const USED = 1 << 9;
27352735
/// #[ffi_returns_twice], indicates that an extern function can return
27362736
/// multiple times
2737-
const FFI_RETURNS_TWICE = 1 << 10;
2737+
const FFI_RETURNS_TWICE = 1 << 10;
2738+
/// #[track_caller]: allow access to the caller location
2739+
const TRACK_CALLER = 1 << 11;
27382740
}
27392741
}
27402742

src/librustc_typeck/check/wfcheck.rs

+36
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,18 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: DefId) {
172172
_ => None
173173
};
174174
check_associated_item(tcx, trait_item.hir_id, trait_item.span, method_sig);
175+
176+
// Prohibits applying `#[track_caller]` to trait decls
177+
for attr in &trait_item.attrs {
178+
if attr.check_name(sym::track_caller) {
179+
struct_span_err!(
180+
tcx.sess,
181+
attr.span,
182+
E0738,
183+
"`#[track_caller]` is not supported in trait declarations."
184+
).emit();
185+
}
186+
}
175187
}
176188

177189
pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: DefId) {
@@ -182,6 +194,30 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: DefId) {
182194
hir::ImplItemKind::Method(ref sig, _) => Some(sig),
183195
_ => None
184196
};
197+
198+
// Prohibits applying `#[track_caller]` to trait impls
199+
if method_sig.is_some() {
200+
let track_caller_attr = impl_item.attrs.iter()
201+
.find(|a| a.check_name(sym::track_caller));
202+
if let Some(tc_attr) = track_caller_attr {
203+
let parent_hir_id = tcx.hir().get_parent_item(hir_id);
204+
let containing_item = tcx.hir().expect_item(parent_hir_id);
205+
let containing_impl_is_for_trait = match &containing_item.kind {
206+
hir::ItemKind::Impl(_, _, _, _, tr, _, _) => tr.is_some(),
207+
_ => bug!("parent of an ImplItem must be an Impl"),
208+
};
209+
210+
if containing_impl_is_for_trait {
211+
struct_span_err!(
212+
tcx.sess,
213+
tc_attr.span,
214+
E0738,
215+
"`#[track_caller]` is not supported in traits yet."
216+
).emit();
217+
}
218+
}
219+
}
220+
185221
check_associated_item(tcx, impl_item.hir_id, impl_item.span, method_sig);
186222
}
187223

src/librustc_typeck/collect.rs

+10
Original file line numberDiff line numberDiff line change
@@ -2594,6 +2594,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
25942594
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
25952595
} else if attr.check_name(sym::thread_local) {
25962596
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
2597+
} else if attr.check_name(sym::track_caller) {
2598+
if tcx.fn_sig(id).abi() != abi::Abi::Rust {
2599+
struct_span_err!(
2600+
tcx.sess,
2601+
attr.span,
2602+
E0737,
2603+
"rust ABI is required to use `#[track_caller]`"
2604+
).emit();
2605+
}
2606+
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
25972607
} else if attr.check_name(sym::export_name) {
25982608
if let Some(s) = attr.value_str() {
25992609
if s.as_str().contains("\0") {

src/librustc_typeck/error_codes.rs

+69
Original file line numberDiff line numberDiff line change
@@ -4905,6 +4905,75 @@ fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
49054905
The `Box<...>` ensures that the result is of known size,
49064906
and the pin is required to keep it in the same place in memory.
49074907
"##,
4908+
4909+
E0737: r##"
4910+
#[track_caller] requires functions to have the "Rust" ABI for implicitly
4911+
receiving caller location. See [RFC 2091] for details on this and other
4912+
restrictions.
4913+
4914+
Erroneous code example:
4915+
4916+
```compile_fail,E0737
4917+
#![feature(track_caller)]
4918+
4919+
#[track_caller]
4920+
extern "C" fn foo() {}
4921+
```
4922+
4923+
[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
4924+
"##,
4925+
4926+
E0738: r##"
4927+
#[track_caller] cannot be used in traits yet. This is due to limitations in the
4928+
compiler which are likely to be temporary. See [RFC 2091] for details on this
4929+
and other restrictions.
4930+
4931+
Erroneous example with a trait method implementation:
4932+
4933+
```compile_fail,E0738
4934+
#![feature(track_caller)]
4935+
4936+
trait Foo {
4937+
fn bar(&self);
4938+
}
4939+
4940+
impl Foo for u64 {
4941+
#[track_caller]
4942+
fn bar(&self) {}
4943+
}
4944+
```
4945+
4946+
Erroneous example with a blanket trait method implementation:
4947+
4948+
```compile_fail,E0738
4949+
#![feature(track_caller)]
4950+
4951+
trait Foo {
4952+
#[track_caller]
4953+
fn bar(&self) {}
4954+
fn baz(&self);
4955+
}
4956+
```
4957+
4958+
Erroneous example with a trait method declaration:
4959+
4960+
```compile_fail,E0738
4961+
#![feature(track_caller)]
4962+
4963+
trait Foo {
4964+
fn bar(&self) {}
4965+
4966+
#[track_caller]
4967+
fn baz(&self);
4968+
}
4969+
```
4970+
4971+
Note that while the compiler may be able to support the attribute in traits in
4972+
the future, [RFC 2091] prohibits their implementation without a follow-up RFC.
4973+
4974+
[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
4975+
"##,
4976+
49084977
;
49094978
// E0035, merged into E0087/E0089
49104979
// E0036, merged into E0087/E0089

src/libsyntax/feature_gate/active.rs

+4
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,9 @@ declare_features! (
525525
// Allows the use of raw-dylibs (RFC 2627).
526526
(active, raw_dylib, "1.40.0", Some(58713), None),
527527

528+
/// Enable accurate caller location reporting during panic (RFC 2091).
529+
(active, track_caller, "1.40.0", Some(47809), None),
530+
528531
// -------------------------------------------------------------------------
529532
// feature-group-end: actual feature gates
530533
// -------------------------------------------------------------------------
@@ -540,4 +543,5 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
540543
sym::or_patterns,
541544
sym::let_chains,
542545
sym::raw_dylib,
546+
sym::track_caller,
543547
];

src/libsyntax/feature_gate/builtin_attrs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
324324
),
325325

326326
gated!(ffi_returns_twice, Whitelisted, template!(Word), experimental!(ffi_returns_twice)),
327+
gated!(track_caller, Whitelisted, template!(Word), experimental!(track_caller)),
327328

328329
// ==========================================================================
329330
// Internal attributes: Stability, deprecation, and unsafe:

src/libsyntax_pos/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,7 @@ symbols! {
674674
tool_attributes,
675675
tool_lints,
676676
trace_macros,
677+
track_caller,
677678
trait_alias,
678679
transmute,
679680
transparent,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#[track_caller]
2+
fn f() {}
3+
//~^^ ERROR the `#[track_caller]` attribute is an experimental feature
4+
5+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0658]: the `#[track_caller]` attribute is an experimental feature
2+
--> $DIR/feature-gate-track_caller.rs:1:1
3+
|
4+
LL | #[track_caller]
5+
| ^^^^^^^^^^^^^^^
6+
|
7+
= note: for more information, see https://github.com/rust-lang/rust/issues/47809
8+
= help: add `#![feature(track_caller)]` to the crate attributes to enable
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0658`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
2+
3+
#[track_caller(1)]
4+
fn f() {}
5+
//~^^ ERROR malformed `track_caller` attribute input
6+
7+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: malformed `track_caller` attribute input
2+
--> $DIR/error-odd-syntax.rs:3:1
3+
|
4+
LL | #[track_caller(1)]
5+
| ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[track_caller]`
6+
7+
warning: the feature `track_caller` is incomplete and may cause the compiler to crash
8+
--> $DIR/error-odd-syntax.rs:1:12
9+
|
10+
LL | #![feature(track_caller)]
11+
| ^^^^^^^^^^^^
12+
|
13+
= note: `#[warn(incomplete_features)]` on by default
14+
15+
error: aborting due to previous error
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
2+
3+
#[track_caller]
4+
extern "C" fn f() {}
5+
//~^^ ERROR rust ABI is required to use `#[track_caller]`
6+
7+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
warning: the feature `track_caller` is incomplete and may cause the compiler to crash
2+
--> $DIR/error-with-invalid-abi.rs:1:12
3+
|
4+
LL | #![feature(track_caller)]
5+
| ^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+
9+
error[E0737]: rust ABI is required to use `#[track_caller]`
10+
--> $DIR/error-with-invalid-abi.rs:3:1
11+
|
12+
LL | #[track_caller]
13+
| ^^^^^^^^^^^^^^^
14+
15+
error: aborting due to previous error
16+
17+
For more information about this error, try `rustc --explain E0737`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![feature(naked_functions, track_caller)] //~ WARN the feature `track_caller` is incomplete
2+
3+
#[track_caller]
4+
#[naked]
5+
fn f() {}
6+
//~^^^ ERROR cannot use `#[track_caller]` with `#[naked]`
7+
8+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
warning: the feature `track_caller` is incomplete and may cause the compiler to crash
2+
--> $DIR/error-with-naked.rs:1:29
3+
|
4+
LL | #![feature(naked_functions, track_caller)]
5+
| ^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+
9+
error[E0736]: cannot use `#[track_caller]` with `#[naked]`
10+
--> $DIR/error-with-naked.rs:3:1
11+
|
12+
LL | #[track_caller]
13+
| ^^^^^^^^^^^^^^^
14+
15+
error: aborting due to previous error
16+
17+
For more information about this error, try `rustc --explain E0736`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
2+
3+
trait Trait {
4+
#[track_caller]
5+
fn unwrap(&self);
6+
//~^^ ERROR: `#[track_caller]` is not supported in trait declarations.
7+
}
8+
9+
impl Trait for u64 {
10+
fn unwrap(&self) {}
11+
}
12+
13+
fn main() {}

0 commit comments

Comments
 (0)