From f8db8ffcf32199dd534768ed30233724dab1fc08 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 24 Oct 2019 22:21:30 +0100 Subject: [PATCH] Permit #[track_caller] on inherent methods --- src/librustc/hir/check_attr.rs | 44 ++++++++++++++----- .../error-with-trait-fn-impl.rs | 9 ++++ .../error-with-trait-fn-impl.stderr | 4 +- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index a67a4566615..7ee1d3448c4 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -16,6 +16,12 @@ use std::fmt::{self, Display}; use syntax::{attr, symbol::sym}; use syntax_pos::Span; +#[derive(Copy, Clone, PartialEq)] +pub(crate) enum MethodKind { + Trait { body: bool }, + Inherent, +} + #[derive(Copy, Clone, PartialEq)] pub(crate) enum Target { ExternCrate, @@ -38,7 +44,7 @@ pub(crate) enum Target { Expression, Statement, AssocConst, - Method { body: bool }, + Method(MethodKind), AssocTy, ForeignFn, ForeignStatic, @@ -68,7 +74,7 @@ impl Display for Target { Target::Expression => "expression", Target::Statement => "statement", Target::AssocConst => "associated const", - Target::Method { .. } => "method", + Target::Method(_) => "method", Target::AssocTy => "associated type", Target::ForeignFn => "foreign function", Target::ForeignStatic => "foreign static item", @@ -103,10 +109,10 @@ impl Target { match trait_item.kind { TraitItemKind::Const(..) => Target::AssocConst, TraitItemKind::Method(_, hir::TraitMethod::Required(_)) => { - Target::Method { body: false } + Target::Method(MethodKind::Trait { body: false }) } TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => { - Target::Method { body: true } + Target::Method(MethodKind::Trait { body: true }) } TraitItemKind::Type(..) => Target::AssocTy, } @@ -120,10 +126,22 @@ impl Target { } } - fn from_impl_item(impl_item: &hir::ImplItem) -> Target { + fn from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem) -> Target { match impl_item.kind { hir::ImplItemKind::Const(..) => Target::Const, - hir::ImplItemKind::Method(..) => Target::Method { body: true }, + hir::ImplItemKind::Method(..) => { + let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id); + let containing_item = tcx.hir().expect_item(parent_hir_id); + let containing_impl_is_for_trait = match &containing_item.kind { + hir::ItemKind::Impl(_, _, _, _, tr, _, _) => tr.is_some(), + _ => bug!("parent of an ImplItem must be an Impl"), + }; + if containing_impl_is_for_trait { + Target::Method(MethodKind::Trait { body: true }) + } else { + Target::Method(MethodKind::Inherent) + } + } hir::ImplItemKind::TyAlias(..) => Target::TyAlias, hir::ImplItemKind::OpaqueTy(..) => Target::OpaqueTy, } @@ -176,8 +194,9 @@ impl CheckAttrVisitor<'tcx> { /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid. fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool { match target { - Target::Fn | Target::Closure | Target::Method { body: true } => true, - Target::Method { body: false } | Target::ForeignFn => { + Target::Fn | Target::Closure | Target::Method(MethodKind::Trait { body: true }) + | Target::Method(MethodKind::Inherent) => true, + Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => { self.tcx.struct_span_lint_hir( UNUSED_ATTRIBUTES, hir_id, @@ -216,8 +235,8 @@ impl CheckAttrVisitor<'tcx> { ).emit(); false } - Target::Fn => true, - Target::Method { .. } => { + Target::Fn | Target::Method(MethodKind::Inherent) => true, + Target::Method(_) => { struct_span_err!( self.tcx.sess, *attr_span, @@ -278,7 +297,8 @@ impl CheckAttrVisitor<'tcx> { /// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid. fn check_target_feature(&self, attr: &Attribute, span: &Span, target: Target) -> bool { match target { - Target::Fn | Target::Method { body: true } => true, + Target::Fn | Target::Method(MethodKind::Trait { body: true }) + | Target::Method(MethodKind::Inherent) => true, _ => { self.tcx.sess .struct_span_err(attr.span, "attribute should be applied to a function") @@ -471,7 +491,7 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { } fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { - let target = Target::from_impl_item(impl_item); + let target = Target::from_impl_item(self.tcx, impl_item); self.check_attributes(impl_item.hir_id, &impl_item.attrs, &impl_item.span, target, None); intravisit::walk_impl_item(self, impl_item) } 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 index 9b97df2e4eb..b565e11f55b 100644 --- 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 @@ -1,3 +1,5 @@ +// check-fail + #![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete trait Trait { @@ -9,4 +11,11 @@ impl Trait for u64 { 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 index 9646cb1ac0b..707b367484c 100644 --- 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 @@ -1,5 +1,5 @@ warning: the feature `track_caller` is incomplete and may cause the compiler to crash - --> $DIR/error-with-trait-fn-impl.rs:1:12 + --> $DIR/error-with-trait-fn-impl.rs:3:12 | LL | #![feature(track_caller)] | ^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #![feature(track_caller)] = note: `#[warn(incomplete_features)]` on by default error[E0738]: `#[track_caller]` may not be used on trait methods - --> $DIR/error-with-trait-fn-impl.rs:8:5 + --> $DIR/error-with-trait-fn-impl.rs:10:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^