提交 f8db8ffc 编写于 作者: V varkor

Permit #[track_caller] on inherent methods

上级 6446f192
...@@ -16,6 +16,12 @@ ...@@ -16,6 +16,12 @@
use syntax::{attr, symbol::sym}; use syntax::{attr, symbol::sym};
use syntax_pos::Span; use syntax_pos::Span;
#[derive(Copy, Clone, PartialEq)]
pub(crate) enum MethodKind {
Trait { body: bool },
Inherent,
}
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
pub(crate) enum Target { pub(crate) enum Target {
ExternCrate, ExternCrate,
...@@ -38,7 +44,7 @@ pub(crate) enum Target { ...@@ -38,7 +44,7 @@ pub(crate) enum Target {
Expression, Expression,
Statement, Statement,
AssocConst, AssocConst,
Method { body: bool }, Method(MethodKind),
AssocTy, AssocTy,
ForeignFn, ForeignFn,
ForeignStatic, ForeignStatic,
...@@ -68,7 +74,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ...@@ -68,7 +74,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Target::Expression => "expression", Target::Expression => "expression",
Target::Statement => "statement", Target::Statement => "statement",
Target::AssocConst => "associated const", Target::AssocConst => "associated const",
Target::Method { .. } => "method", Target::Method(_) => "method",
Target::AssocTy => "associated type", Target::AssocTy => "associated type",
Target::ForeignFn => "foreign function", Target::ForeignFn => "foreign function",
Target::ForeignStatic => "foreign static item", Target::ForeignStatic => "foreign static item",
...@@ -103,10 +109,10 @@ fn from_trait_item(trait_item: &TraitItem) -> Target { ...@@ -103,10 +109,10 @@ fn from_trait_item(trait_item: &TraitItem) -> Target {
match trait_item.kind { match trait_item.kind {
TraitItemKind::Const(..) => Target::AssocConst, TraitItemKind::Const(..) => Target::AssocConst,
TraitItemKind::Method(_, hir::TraitMethod::Required(_)) => { TraitItemKind::Method(_, hir::TraitMethod::Required(_)) => {
Target::Method { body: false } Target::Method(MethodKind::Trait { body: false })
} }
TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => { TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
Target::Method { body: true } Target::Method(MethodKind::Trait { body: true })
} }
TraitItemKind::Type(..) => Target::AssocTy, TraitItemKind::Type(..) => Target::AssocTy,
} }
...@@ -120,10 +126,22 @@ fn from_foreign_item(foreign_item: &hir::ForeignItem) -> Target { ...@@ -120,10 +126,22 @@ fn from_foreign_item(foreign_item: &hir::ForeignItem) -> 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 { match impl_item.kind {
hir::ImplItemKind::Const(..) => Target::Const, 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::TyAlias(..) => Target::TyAlias,
hir::ImplItemKind::OpaqueTy(..) => Target::OpaqueTy, hir::ImplItemKind::OpaqueTy(..) => Target::OpaqueTy,
} }
...@@ -176,8 +194,9 @@ fn check_attributes( ...@@ -176,8 +194,9 @@ fn check_attributes(
/// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid. /// 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 { fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
match target { match target {
Target::Fn | Target::Closure | Target::Method { body: true } => true, Target::Fn | Target::Closure | Target::Method(MethodKind::Trait { body: true })
Target::Method { body: false } | Target::ForeignFn => { | Target::Method(MethodKind::Inherent) => true,
Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
self.tcx.struct_span_lint_hir( self.tcx.struct_span_lint_hir(
UNUSED_ATTRIBUTES, UNUSED_ATTRIBUTES,
hir_id, hir_id,
...@@ -216,8 +235,8 @@ fn check_track_caller( ...@@ -216,8 +235,8 @@ fn check_track_caller(
).emit(); ).emit();
false false
} }
Target::Fn => true, Target::Fn | Target::Method(MethodKind::Inherent) => true,
Target::Method { .. } => { Target::Method(_) => {
struct_span_err!( struct_span_err!(
self.tcx.sess, self.tcx.sess,
*attr_span, *attr_span,
...@@ -278,7 +297,8 @@ fn check_marker(&self, attr: &Attribute, span: &Span, target: Target) -> bool { ...@@ -278,7 +297,8 @@ fn check_marker(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
/// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid. /// 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 { fn check_target_feature(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
match target { 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 self.tcx.sess
.struct_span_err(attr.span, "attribute should be applied to a function") .struct_span_err(attr.span, "attribute should be applied to a function")
...@@ -471,7 +491,7 @@ fn visit_foreign_item(&mut self, f_item: &'tcx hir::ForeignItem) { ...@@ -471,7 +491,7 @@ fn visit_foreign_item(&mut self, f_item: &'tcx hir::ForeignItem) {
} }
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { 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); self.check_attributes(impl_item.hir_id, &impl_item.attrs, &impl_item.span, target, None);
intravisit::walk_impl_item(self, impl_item) intravisit::walk_impl_item(self, impl_item)
} }
......
// check-fail
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete #![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
trait Trait { trait Trait {
...@@ -9,4 +11,11 @@ impl Trait for u64 { ...@@ -9,4 +11,11 @@ impl Trait for u64 {
fn unwrap(&self) {} fn unwrap(&self) {}
} }
struct S;
impl S {
#[track_caller] // ok
fn foo() {}
}
fn main() {} fn main() {}
warning: the feature `track_caller` is incomplete and may cause the compiler to crash 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)] LL | #![feature(track_caller)]
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
...@@ -7,7 +7,7 @@ LL | #![feature(track_caller)] ...@@ -7,7 +7,7 @@ LL | #![feature(track_caller)]
= note: `#[warn(incomplete_features)]` on by default = note: `#[warn(incomplete_features)]` on by default
error[E0738]: `#[track_caller]` may not be used on trait methods 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] LL | #[track_caller]
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册