Skip to content

Commit

Permalink
Rollup merge of rust-lang#69251 - anp:track-caller-in-traits, r=eddyb
Browse files Browse the repository at this point in the history
#[track_caller] in traits

Per rust-lang#47809 (comment), this allows the `#[track_caller]` attribute on trait methods.

Includes tests for `#[track_caller]` with:

* "regular" trait impls
* default trait impls
* "blanket-tracked" trait impls, where the annotation is in the trait definition and is inherited by "regular" impls of the trait
  • Loading branch information
Centril authored Mar 23, 2020
2 parents 2cb50eb + 69bd46a commit 1229c0a
Show file tree
Hide file tree
Showing 15 changed files with 217 additions and 119 deletions.
1 change: 1 addition & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#![feature(extern_types)]
#![feature(nll)]
#![feature(option_expect_none)]
#![feature(or_patterns)]
#![feature(range_is_empty)]
#![feature(specialization)]
#![feature(trusted_len)]
Expand Down
18 changes: 4 additions & 14 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{self, par_iter, Lrc, ParallelIterator};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::{Constness, GlobMap, Node, TraitMap};
use rustc_index::vec::{Idx, IndexVec};
use rustc_macros::HashStable;
Expand Down Expand Up @@ -2875,8 +2875,8 @@ impl<'tcx> TyCtxt<'tcx> {
_ => false,
}
} else {
match self.def_kind(def_id).expect("no def for `DefId`") {
DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy => true,
match self.def_kind(def_id) {
Some(DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy) => true,
_ => false,
}
};
Expand Down Expand Up @@ -3054,17 +3054,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// If the given defid describes a method belonging to an impl, returns the
/// `DefId` of the impl that the method belongs to; otherwise, returns `None`.
pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> {
let item = if def_id.krate != LOCAL_CRATE {
if let Some(DefKind::AssocFn) = self.def_kind(def_id) {
Some(self.associated_item(def_id))
} else {
None
}
} else {
self.opt_associated_item(def_id)
};

item.and_then(|trait_item| match trait_item.container {
self.opt_associated_item(def_id).and_then(|trait_item| match trait_item.container {
TraitContainer(_) => None,
ImplContainer(def_id) => Some(def_id),
})
Expand Down
45 changes: 4 additions & 41 deletions src/librustc_error_codes/error_codes/E0738.md
Original file line number Diff line number Diff line change
@@ -1,48 +1,11 @@
`#[track_caller]` cannot be used in traits yet. This is due to limitations in
the compiler which are likely to be temporary. See [RFC 2091] for details on
this and other restrictions.
`#[track_caller]` cannot be used to annotate foreign functions.

Erroneous example with a trait method implementation:
Erroneous example:

```compile_fail,E0738
#![feature(track_caller)]
trait Foo {
fn bar(&self);
}
impl Foo for u64 {
#[track_caller]
fn bar(&self) {}
}
```

Erroneous example with a blanket trait method implementation:

```compile_fail,E0738
#![feature(track_caller)]
trait Foo {
extern "Rust" {
#[track_caller]
fn bar(&self) {}
fn baz(&self);
fn bar();
}
```

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
6 changes: 3 additions & 3 deletions src/librustc_passes/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,17 +151,17 @@ impl CheckAttrVisitor<'tcx> {
.emit();
false
}
Target::Fn | Target::Method(MethodKind::Inherent) => true,
Target::Method(_) => {
Target::ForeignFn => {
struct_span_err!(
self.tcx.sess,
*attr_span,
E0738,
"`#[track_caller]` may not be used on trait methods",
"`#[track_caller]` is not supported on foreign functions",
)
.emit();
false
}
Target::Fn | Target::Method(..) => true,
_ => {
struct_span_err!(
self.tcx.sess,
Expand Down
29 changes: 29 additions & 0 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2339,6 +2339,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
let attrs = tcx.get_attrs(id);

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);

Expand Down Expand Up @@ -2583,6 +2586,32 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
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> {
use rustc_ast::ast::{Lit, LitIntType, LitKind};
let meta_item_list = attr.meta_item_list();
Expand Down
9 changes: 9 additions & 0 deletions src/test/ui/rfc-2091-track-caller/error-extern-fn.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0738]: `#[track_caller]` may not be used on trait methods
--> $DIR/error-with-trait-decl.rs:4:5
error[E0738]: `#[track_caller]` is not supported on foreign functions
--> $DIR/error-extern-fn.rs:5:5
|
LL | #[track_caller]
| ^^^^^^^^^^^^^^^
Expand Down
12 changes: 0 additions & 12 deletions src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs

This file was deleted.

This file was deleted.

This file was deleted.

21 changes: 0 additions & 21 deletions src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs

This file was deleted.

This file was deleted.

43 changes: 43 additions & 0 deletions src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,49 @@ fn tracked_unit(_: ()) {
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() {
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, ());
}
43 changes: 43 additions & 0 deletions src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,49 @@ fn tracked() {
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() {
ptr_call(tracked);
ptr_call(<() as Trait>::trait_tracked);
ptr_call(<() as TrackedTrait>::trait_tracked_default);
ptr_call(<() as TraitBlanketTracked>::tracked_blanket);
}
Loading

0 comments on commit 1229c0a

Please sign in to comment.