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
This commit is contained in:
parent
d1e81ef234
commit
97da6dae41
@ -38,6 +38,7 @@
|
|||||||
#![feature(extern_types)]
|
#![feature(extern_types)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![feature(option_expect_none)]
|
#![feature(option_expect_none)]
|
||||||
|
#![feature(or_patterns)]
|
||||||
#![feature(range_is_empty)]
|
#![feature(range_is_empty)]
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
#![feature(trusted_len)]
|
#![feature(trusted_len)]
|
||||||
|
@ -2875,8 +2875,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match self.def_kind(def_id).expect("no def for `DefId`") {
|
match self.def_kind(def_id) {
|
||||||
DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy => true,
|
Some(DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,48 +1,11 @@
|
|||||||
`#[track_caller]` cannot be used in traits yet. This is due to limitations in
|
`#[track_caller]` cannot be used to annotate foreign functions.
|
||||||
the compiler which are likely to be temporary. See [RFC 2091] for details on
|
|
||||||
this and other restrictions.
|
|
||||||
|
|
||||||
Erroneous example with a trait method implementation:
|
Erroneous example:
|
||||||
|
|
||||||
```compile_fail,E0738
|
```compile_fail,E0738
|
||||||
#![feature(track_caller)]
|
#![feature(track_caller)]
|
||||||
|
extern "Rust" {
|
||||||
trait Foo {
|
|
||||||
fn bar(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Foo for u64 {
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn bar(&self) {}
|
fn bar();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Erroneous example with a blanket trait method implementation:
|
|
||||||
|
|
||||||
```compile_fail,E0738
|
|
||||||
#![feature(track_caller)]
|
|
||||||
|
|
||||||
trait Foo {
|
|
||||||
#[track_caller]
|
|
||||||
fn bar(&self) {}
|
|
||||||
fn baz(&self);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Erroneous example with a trait method declaration:
|
|
||||||
|
|
||||||
```compile_fail,E0738
|
|
||||||
#![feature(track_caller)]
|
|
||||||
|
|
||||||
trait Foo {
|
|
||||||
fn bar(&self) {}
|
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
fn baz(&self);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that while the compiler may be able to support the attribute in traits in
|
|
||||||
the future, [RFC 2091] prohibits their implementation without a follow-up RFC.
|
|
||||||
|
|
||||||
[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
|
|
||||||
|
@ -151,17 +151,17 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
.emit();
|
.emit();
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
Target::Fn | Target::Method(MethodKind::Inherent) => true,
|
Target::ForeignFn => {
|
||||||
Target::Method(_) => {
|
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
self.tcx.sess,
|
self.tcx.sess,
|
||||||
*attr_span,
|
*attr_span,
|
||||||
E0738,
|
E0738,
|
||||||
"`#[track_caller]` may not be used on trait methods",
|
"`#[track_caller]` is not supported on foreign functions",
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
Target::Fn | Target::Method(..) => true,
|
||||||
_ => {
|
_ => {
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
self.tcx.sess,
|
self.tcx.sess,
|
||||||
|
@ -2339,6 +2339,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
|||||||
let attrs = tcx.get_attrs(id);
|
let attrs = tcx.get_attrs(id);
|
||||||
|
|
||||||
let mut codegen_fn_attrs = CodegenFnAttrs::new();
|
let mut codegen_fn_attrs = CodegenFnAttrs::new();
|
||||||
|
if should_inherit_track_caller(tcx, id) {
|
||||||
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
|
||||||
|
}
|
||||||
|
|
||||||
let whitelist = tcx.target_features_whitelist(LOCAL_CRATE);
|
let whitelist = tcx.target_features_whitelist(LOCAL_CRATE);
|
||||||
|
|
||||||
@ -2583,6 +2586,32 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
|||||||
codegen_fn_attrs
|
codegen_fn_attrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
|
||||||
|
/// applied to the method prototype.
|
||||||
|
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||||
|
if let Some(impl_item) = tcx.opt_associated_item(def_id) {
|
||||||
|
if let ty::AssocItemContainer::ImplContainer(impl_def_id) = impl_item.container {
|
||||||
|
if let Some(trait_def_id) = tcx.trait_id_of_impl(impl_def_id) {
|
||||||
|
if let Some(trait_item) = tcx
|
||||||
|
.associated_items(trait_def_id)
|
||||||
|
.filter_by_name_unhygienic(impl_item.ident.name)
|
||||||
|
.find(move |trait_item| {
|
||||||
|
trait_item.kind == ty::AssocKind::Method
|
||||||
|
&& tcx.hygienic_eq(impl_item.ident, trait_item.ident, trait_def_id)
|
||||||
|
})
|
||||||
|
{
|
||||||
|
return tcx
|
||||||
|
.codegen_fn_attrs(trait_item.def_id)
|
||||||
|
.flags
|
||||||
|
.intersects(CodegenFnAttrFlags::TRACK_CALLER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<usize> {
|
fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<usize> {
|
||||||
use rustc_ast::ast::{Lit, LitIntType, LitKind};
|
use rustc_ast::ast::{Lit, LitIntType, LitKind};
|
||||||
let meta_item_list = attr.meta_item_list();
|
let meta_item_list = attr.meta_item_list();
|
||||||
|
9
src/test/ui/rfc-2091-track-caller/error-extern-fn.rs
Normal file
9
src/test/ui/rfc-2091-track-caller/error-extern-fn.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#![feature(track_caller)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
extern "Rust" {
|
||||||
|
#[track_caller] //~ ERROR: `#[track_caller]` is not supported on foreign functions
|
||||||
|
fn bar();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -1,5 +1,5 @@
|
|||||||
error[E0738]: `#[track_caller]` may not be used on trait methods
|
error[E0738]: `#[track_caller]` is not supported on foreign functions
|
||||||
--> $DIR/error-with-trait-decl.rs:4:5
|
--> $DIR/error-extern-fn.rs:5:5
|
||||||
|
|
|
|
||||||
LL | #[track_caller]
|
LL | #[track_caller]
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
@ -1,12 +0,0 @@
|
|||||||
#![feature(track_caller)]
|
|
||||||
|
|
||||||
trait Trait {
|
|
||||||
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods
|
|
||||||
fn unwrap(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Trait for u64 {
|
|
||||||
fn unwrap(&self) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
@ -1,8 +0,0 @@
|
|||||||
#![feature(track_caller)]
|
|
||||||
|
|
||||||
trait Trait {
|
|
||||||
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods
|
|
||||||
fn unwrap(&self) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
@ -1,9 +0,0 @@
|
|||||||
error[E0738]: `#[track_caller]` may not be used on trait methods
|
|
||||||
--> $DIR/error-with-trait-default-impl.rs:4:5
|
|
||||||
|
|
|
||||||
LL | #[track_caller]
|
|
||||||
| ^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0738`.
|
|
@ -1,21 +0,0 @@
|
|||||||
// check-fail
|
|
||||||
|
|
||||||
#![feature(track_caller)]
|
|
||||||
|
|
||||||
trait Trait {
|
|
||||||
fn unwrap(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Trait for u64 {
|
|
||||||
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods
|
|
||||||
fn unwrap(&self) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct S;
|
|
||||||
|
|
||||||
impl S {
|
|
||||||
#[track_caller] // ok
|
|
||||||
fn foo() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
@ -1,9 +0,0 @@
|
|||||||
error[E0738]: `#[track_caller]` may not be used on trait methods
|
|
||||||
--> $DIR/error-with-trait-fn-impl.rs:10:5
|
|
||||||
|
|
|
||||||
LL | #[track_caller]
|
|
||||||
| ^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0738`.
|
|
@ -14,6 +14,49 @@ fn tracked_unit(_: ()) {
|
|||||||
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
|
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
fn trait_tracked_unit(_: ());
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for () {
|
||||||
|
#[track_caller]
|
||||||
|
fn trait_tracked_unit(_: ()) {
|
||||||
|
let expected_line = line!() - 1;
|
||||||
|
let location = std::panic::Location::caller();
|
||||||
|
assert_eq!(location.file(), file!());
|
||||||
|
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait TrackedTrait {
|
||||||
|
#[track_caller]
|
||||||
|
fn trait_tracked_unit_default(_: ()) {
|
||||||
|
let expected_line = line!() - 1;
|
||||||
|
let location = std::panic::Location::caller();
|
||||||
|
assert_eq!(location.file(), file!());
|
||||||
|
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrackedTrait for () {}
|
||||||
|
|
||||||
|
trait BlanketTrackedTrait {
|
||||||
|
#[track_caller]
|
||||||
|
fn tracked_blanket(_: ());
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlanketTrackedTrait for () {
|
||||||
|
fn tracked_blanket(_: ()) {
|
||||||
|
let expected_line = line!() - 1;
|
||||||
|
let location = std::panic::Location::caller();
|
||||||
|
assert_eq!(location.file(), file!());
|
||||||
|
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
pass_to_ptr_call(tracked_unit, ());
|
pass_to_ptr_call(tracked_unit, ());
|
||||||
|
pass_to_ptr_call(<() as Trait>::trait_tracked_unit, ());
|
||||||
|
pass_to_ptr_call(<() as TrackedTrait>::trait_tracked_unit_default, ());
|
||||||
|
pass_to_ptr_call(<() as BlanketTrackedTrait>::tracked_blanket, ());
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,49 @@ fn tracked() {
|
|||||||
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
|
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
fn trait_tracked();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for () {
|
||||||
|
#[track_caller]
|
||||||
|
fn trait_tracked() {
|
||||||
|
let expected_line = line!() - 1;
|
||||||
|
let location = std::panic::Location::caller();
|
||||||
|
assert_eq!(location.file(), file!());
|
||||||
|
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait TrackedTrait {
|
||||||
|
#[track_caller]
|
||||||
|
fn trait_tracked_default() {
|
||||||
|
let expected_line = line!() - 1;
|
||||||
|
let location = std::panic::Location::caller();
|
||||||
|
assert_eq!(location.file(), file!());
|
||||||
|
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrackedTrait for () {}
|
||||||
|
|
||||||
|
trait TraitBlanketTracked {
|
||||||
|
#[track_caller]
|
||||||
|
fn tracked_blanket();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TraitBlanketTracked for () {
|
||||||
|
fn tracked_blanket() {
|
||||||
|
let expected_line = line!() - 1;
|
||||||
|
let location = std::panic::Location::caller();
|
||||||
|
assert_eq!(location.file(), file!());
|
||||||
|
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
ptr_call(tracked);
|
ptr_call(tracked);
|
||||||
|
ptr_call(<() as Trait>::trait_tracked);
|
||||||
|
ptr_call(<() as TrackedTrait>::trait_tracked_default);
|
||||||
|
ptr_call(<() as TraitBlanketTracked>::tracked_blanket);
|
||||||
}
|
}
|
||||||
|
79
src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs
Normal file
79
src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![feature(track_caller)]
|
||||||
|
|
||||||
|
macro_rules! assert_expansion_site_is_tracked {
|
||||||
|
() => {{
|
||||||
|
let location = std::panic::Location::caller();
|
||||||
|
assert_eq!(location.file(), file!());
|
||||||
|
assert_ne!(location.line(), line!(), "line should be outside this fn");
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Tracked {
|
||||||
|
fn local_tracked(&self);
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn blanket_tracked(&self);
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn default_tracked(&self) {
|
||||||
|
assert_expansion_site_is_tracked!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tracked for () {
|
||||||
|
#[track_caller]
|
||||||
|
fn local_tracked(&self) {
|
||||||
|
assert_expansion_site_is_tracked!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blanket_tracked(&self) {
|
||||||
|
assert_expansion_site_is_tracked!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tracked for bool {
|
||||||
|
#[track_caller]
|
||||||
|
fn local_tracked(&self) {
|
||||||
|
assert_expansion_site_is_tracked!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blanket_tracked(&self) {
|
||||||
|
assert_expansion_site_is_tracked!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_tracked(&self) {
|
||||||
|
assert_expansion_site_is_tracked!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tracked for u8 {
|
||||||
|
#[track_caller]
|
||||||
|
fn local_tracked(&self) {
|
||||||
|
assert_expansion_site_is_tracked!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blanket_tracked(&self) {
|
||||||
|
assert_expansion_site_is_tracked!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn default_tracked(&self) {
|
||||||
|
assert_expansion_site_is_tracked!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
().local_tracked();
|
||||||
|
().default_tracked();
|
||||||
|
().blanket_tracked();
|
||||||
|
|
||||||
|
true.local_tracked();
|
||||||
|
true.default_tracked();
|
||||||
|
true.blanket_tracked();
|
||||||
|
|
||||||
|
0u8.local_tracked();
|
||||||
|
0u8.default_tracked();
|
||||||
|
0u8.blanket_tracked();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user