diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2020-03-23 04:26:04 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-03-23 04:26:04 +0100 |
| commit | 5ed9d7ebb662ad993e9f2e8c70575fb27cd45041 (patch) | |
| tree | 02634cf6a1d092d5781e3ca0f755abe1cff0a8c7 /src | |
| parent | e4b01c7791446b2f79a1b1d517223378df2bf5f2 (diff) | |
| parent | 69bd46a6a18a5b44972ccebb96de1294f4b760b1 (diff) | |
| download | rust-5ed9d7ebb662ad993e9f2e8c70575fb27cd45041.tar.gz rust-5ed9d7ebb662ad993e9f2e8c70575fb27cd45041.zip | |
Rollup merge of #69251 - anp:track-caller-in-traits, r=eddyb
#[track_caller] in traits Per https://github.com/rust-lang/rust/issues/47809#issuecomment-572791760, 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
Diffstat (limited to 'src')
15 files changed, 217 insertions, 119 deletions
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 8d0f604de6d..6f18560a02d 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 eeacd6a6d83..e7316ea763e 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; @@ -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, } }; @@ -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), }) diff --git a/src/librustc_error_codes/error_codes/E0738.md b/src/librustc_error_codes/error_codes/E0738.md index 4c9588ef7b6..8f31b701e49 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 373b7c56d38..583e1fdc1f0 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 a79c0653077..bb9354b8ab3 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<usize> { 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 00000000000..9f6a69a51c0 --- /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 index ded721d2782..b03f5fbbdb2 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 ef037ab62aa..00000000000 --- 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 17e4bf41ddb..00000000000 --- 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 867eb918b6e..00000000000 --- 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 75f20f76e66..00000000000 --- 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 fafceefbfd8..00000000000 --- 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 0407eafbfd4..b17c1efb3d3 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 a4baaa26ced..8ee4d4fa168 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 00000000000..0a5f92bb635 --- /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(); +} |
