From 97da6dae41dc7fe5597c2cd858b1ac86548cec16 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Mon, 17 Feb 2020 15:36:36 -0800 Subject: [PATCH 1/2] 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 --- src/librustc/lib.rs | 1 + src/librustc/ty/mod.rs | 4 +- src/librustc_error_codes/error_codes/E0738.md | 45 +---------- src/librustc_passes/check_attr.rs | 6 +- src/librustc_typeck/collect.rs | 29 +++++++ .../rfc-2091-track-caller/error-extern-fn.rs | 9 +++ ...ait-decl.stderr => error-extern-fn.stderr} | 4 +- .../error-with-trait-decl.rs | 12 --- .../error-with-trait-default-impl.rs | 8 -- .../error-with-trait-default-impl.stderr | 9 --- .../error-with-trait-fn-impl.rs | 21 ----- .../error-with-trait-fn-impl.stderr | 9 --- .../tracked-fn-ptr-with-arg.rs | 43 ++++++++++ .../rfc-2091-track-caller/tracked-fn-ptr.rs | 43 ++++++++++ .../tracked-trait-impls.rs | 79 +++++++++++++++++++ 15 files changed, 215 insertions(+), 107 deletions(-) create mode 100644 src/test/ui/rfc-2091-track-caller/error-extern-fn.rs rename src/test/ui/rfc-2091-track-caller/{error-with-trait-decl.stderr => error-extern-fn.stderr} (60%) delete mode 100644 src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs delete mode 100644 src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs delete mode 100644 src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr delete mode 100644 src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs delete mode 100644 src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr create mode 100644 src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 8d0f604de6d76..6f18560a02d7f 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -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)] diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index eeacd6a6d83f6..e0afe7648b1dd 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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, } }; diff --git a/src/librustc_error_codes/error_codes/E0738.md b/src/librustc_error_codes/error_codes/E0738.md index 4c9588ef7b63b..8f31b701e495e 100644 --- a/src/librustc_error_codes/error_codes/E0738.md +++ b/src/librustc_error_codes/error_codes/E0738.md @@ -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 diff --git a/src/librustc_passes/check_attr.rs b/src/librustc_passes/check_attr.rs index 373b7c56d3802..583e1fdc1f05f 100644 --- a/src/librustc_passes/check_attr.rs +++ b/src/librustc_passes/check_attr.rs @@ -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, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a79c065307796..bb9354b8ab339 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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); @@ -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 { use rustc_ast::ast::{Lit, LitIntType, LitKind}; let meta_item_list = attr.meta_item_list(); diff --git a/src/test/ui/rfc-2091-track-caller/error-extern-fn.rs b/src/test/ui/rfc-2091-track-caller/error-extern-fn.rs new file mode 100644 index 0000000000000..9f6a69a51c0ce --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/error-extern-fn.rs @@ -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() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr b/src/test/ui/rfc-2091-track-caller/error-extern-fn.stderr similarity index 60% rename from src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr rename to src/test/ui/rfc-2091-track-caller/error-extern-fn.stderr index ded721d278253..b03f5fbbdb20e 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-extern-fn.stderr @@ -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] | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs deleted file mode 100644 index ef037ab62aa3e..0000000000000 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs +++ /dev/null @@ -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() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs deleted file mode 100644 index 17e4bf41ddb53..0000000000000 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs +++ /dev/null @@ -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() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr deleted file mode 100644 index 867eb918b6e08..0000000000000 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr +++ /dev/null @@ -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`. diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs deleted file mode 100644 index 75f20f76e660d..0000000000000 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs +++ /dev/null @@ -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() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr deleted file mode 100644 index fafceefbfd839..0000000000000 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr +++ /dev/null @@ -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`. diff --git a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs index 0407eafbfd41c..b17c1efb3d38c 100644 --- a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs +++ b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs @@ -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, ()); } diff --git a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs index a4baaa26ced1e..8ee4d4fa16871 100644 --- a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs +++ b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs @@ -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); } diff --git a/src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs b/src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs new file mode 100644 index 0000000000000..0a5f92bb635e5 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs @@ -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(); +} From 69bd46a6a18a5b44972ccebb96de1294f4b760b1 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sun, 22 Mar 2020 16:59:02 -0700 Subject: [PATCH 2/2] Remove special-casing from TyCtxt::impl_of_method. We can do this now that opt_associated_item doesn't have any panicking paths. --- src/librustc/ty/mod.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e0afe7648b1dd..e7316ea763e8a 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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; @@ -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 { - 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), })