about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-03-23 04:26:04 +0100
committerGitHub <noreply@github.com>2020-03-23 04:26:04 +0100
commit5ed9d7ebb662ad993e9f2e8c70575fb27cd45041 (patch)
tree02634cf6a1d092d5781e3ca0f755abe1cff0a8c7 /src
parente4b01c7791446b2f79a1b1d517223378df2bf5f2 (diff)
parent69bd46a6a18a5b44972ccebb96de1294f4b760b1 (diff)
downloadrust-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')
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/ty/mod.rs18
-rw-r--r--src/librustc_error_codes/error_codes/E0738.md45
-rw-r--r--src/librustc_passes/check_attr.rs6
-rw-r--r--src/librustc_typeck/collect.rs29
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-extern-fn.rs9
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-extern-fn.stderr (renamed from src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr)4
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs12
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs8
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr9
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs21
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr9
-rw-r--r--src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs43
-rw-r--r--src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs43
-rw-r--r--src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs79
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();
+}