Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#[track_caller] in traits #69251

Merged
merged 2 commits into from
Mar 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
anp marked this conversation as resolved.
Show resolved Hide resolved
_ => 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);
anp marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}

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