[RFC 2091] Add #[track_caller] attribute.

- The attribute is behind a feature gate.
- Error if both #[naked] and #[track_caller] are applied to the same function.
- Error if #[track_caller] is applied to a non-function item.
- Error if ABI is not "rust"
- Error if #[track_caller] is applied to a trait function.

Error codes and descriptions are pending.
This commit is contained in:
Ayose 2019-07-20 00:55:58 +00:00 committed by Adam Perry
parent e3cb9ea15a
commit 543449d4fd
22 changed files with 199 additions and 1 deletions

View file

@ -1640,6 +1640,16 @@ each method; it is not possible to annotate the entire impl with an `#[inline]`
attribute.
"##,
E0900: r##"
TODO: change error number
TODO: track_caller: invalid syntax
"##,
E0901: r##"
TODO: change error number
TODO: track_caller: no naked functions
"##,
E0522: r##"
The lang attribute is intended for marking special items that are built-in to
Rust itself. This includes special traits (like `Copy` and `Sized`) that affect

View file

@ -94,6 +94,7 @@ impl CheckAttrVisitor<'tcx> {
/// Checks any attribute.
fn check_attributes(&self, item: &hir::Item, target: Target) {
let mut is_valid = true;
let mut track_caller_span = None;
for attr in &item.attrs {
is_valid &= if attr.check_name(sym::inline) {
self.check_inline(attr, &item.span, target)
@ -103,6 +104,9 @@ impl CheckAttrVisitor<'tcx> {
self.check_marker(attr, item, target)
} else if attr.check_name(sym::target_feature) {
self.check_target_feature(attr, item, target)
} else if attr.check_name(sym::track_caller) {
track_caller_span = Some(attr.span);
self.check_track_caller(attr, &item, target)
} else {
true
};
@ -118,6 +122,19 @@ impl CheckAttrVisitor<'tcx> {
self.check_repr(item, target);
self.check_used(item, target);
// Checks if `#[track_caller]` and `#[naked]` are both used.
if let Some(span) = track_caller_span {
if item.attrs.iter().any(|attr| attr.check_name(sym::naked)) {
struct_span_err!(
self.tcx.sess,
span,
E0901,
"cannot use `#[track_caller]` with `#[naked]`",
)
.emit();
}
}
}
/// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
@ -135,6 +152,23 @@ impl CheckAttrVisitor<'tcx> {
}
}
/// Checks if a `#[target_feature]` can be applied.
fn check_track_caller(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) -> bool {
if target != Target::Fn {
struct_span_err!(
self.tcx.sess,
attr.span,
E0900,
"attribute should be applied to function"
)
.span_label(item.span, "not a function")
.emit();
false
} else {
true
}
}
/// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
fn check_non_exhaustive(
&self,

View file

@ -2721,7 +2721,9 @@ bitflags! {
const USED = 1 << 9;
/// #[ffi_returns_twice], indicates that an extern function can return
/// multiple times
const FFI_RETURNS_TWICE = 1 << 10;
const FFI_RETURNS_TWICE = 1 << 10;
/// #[track_caller]: allow access to the caller location
const TRACK_CALLER = 1 << 11;
}
}