mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-04 02:54:00 +00:00
Rollup merge of #65294 - varkor:lint-inline-prototype, r=matthewjasper
Lint ignored `#[inline]` on function prototypes Fixes https://github.com/rust-lang/rust/issues/51280. - Adds a `unused_attribute` lint for `#[inline]` on function prototypes. - As a consequence, foreign items, impl items and trait items now have their attributes checked, which could cause some code to no longer compile (it was previously erroneously ignored).
This commit is contained in:
commit
42d4e261a1
@ -150,9 +150,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.1.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "blake2-rfc"
|
||||
|
@ -11,7 +11,7 @@ doctest = false
|
||||
|
||||
[dependencies]
|
||||
arena = { path = "../libarena" }
|
||||
bitflags = "1.0"
|
||||
bitflags = "1.2.1"
|
||||
fmt_macros = { path = "../libfmt_macros" }
|
||||
graphviz = { path = "../libgraphviz" }
|
||||
jobserver = "0.1"
|
||||
|
@ -2219,7 +2219,7 @@ rejected in your own crates.
|
||||
"##,
|
||||
|
||||
E0736: r##"
|
||||
#[track_caller] and #[naked] cannot be applied to the same function.
|
||||
`#[track_caller]` and `#[naked]` cannot both be applied to the same function.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
@ -2237,6 +2237,57 @@ See [RFC 2091] for details on this and other limitations.
|
||||
[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
|
||||
"##,
|
||||
|
||||
E0738: r##"
|
||||
`#[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.
|
||||
|
||||
Erroneous example with a trait method implementation:
|
||||
|
||||
```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 {
|
||||
#[track_caller]
|
||||
fn bar(&self) {}
|
||||
fn baz(&self);
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
"##,
|
||||
|
||||
;
|
||||
// E0006, // merged with E0005
|
||||
// E0101, // replaced with E0282
|
||||
|
@ -4,9 +4,11 @@
|
||||
//! conflicts between multiple such attributes attached to the same
|
||||
//! item.
|
||||
|
||||
use crate::hir;
|
||||
use crate::hir::{self, HirId, HirVec, Attribute, Item, ItemKind, TraitItem, TraitItemKind};
|
||||
use crate::hir::DUMMY_HIR_ID;
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use crate::lint::builtin::UNUSED_ATTRIBUTES;
|
||||
use crate::ty::TyCtxt;
|
||||
use crate::ty::query::Providers;
|
||||
|
||||
@ -14,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,
|
||||
@ -35,6 +43,12 @@ pub(crate) enum Target {
|
||||
Impl,
|
||||
Expression,
|
||||
Statement,
|
||||
AssocConst,
|
||||
Method(MethodKind),
|
||||
AssocTy,
|
||||
ForeignFn,
|
||||
ForeignStatic,
|
||||
ForeignTy,
|
||||
}
|
||||
|
||||
impl Display for Target {
|
||||
@ -59,29 +73,76 @@ impl Display for Target {
|
||||
Target::Impl => "item",
|
||||
Target::Expression => "expression",
|
||||
Target::Statement => "statement",
|
||||
Target::AssocConst => "associated const",
|
||||
Target::Method(_) => "method",
|
||||
Target::AssocTy => "associated type",
|
||||
Target::ForeignFn => "foreign function",
|
||||
Target::ForeignStatic => "foreign static item",
|
||||
Target::ForeignTy => "foreign type",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Target {
|
||||
pub(crate) fn from_item(item: &hir::Item) -> Target {
|
||||
pub(crate) fn from_item(item: &Item) -> Target {
|
||||
match item.kind {
|
||||
hir::ItemKind::ExternCrate(..) => Target::ExternCrate,
|
||||
hir::ItemKind::Use(..) => Target::Use,
|
||||
hir::ItemKind::Static(..) => Target::Static,
|
||||
hir::ItemKind::Const(..) => Target::Const,
|
||||
hir::ItemKind::Fn(..) => Target::Fn,
|
||||
hir::ItemKind::Mod(..) => Target::Mod,
|
||||
hir::ItemKind::ForeignMod(..) => Target::ForeignMod,
|
||||
hir::ItemKind::GlobalAsm(..) => Target::GlobalAsm,
|
||||
hir::ItemKind::TyAlias(..) => Target::TyAlias,
|
||||
hir::ItemKind::OpaqueTy(..) => Target::OpaqueTy,
|
||||
hir::ItemKind::Enum(..) => Target::Enum,
|
||||
hir::ItemKind::Struct(..) => Target::Struct,
|
||||
hir::ItemKind::Union(..) => Target::Union,
|
||||
hir::ItemKind::Trait(..) => Target::Trait,
|
||||
hir::ItemKind::TraitAlias(..) => Target::TraitAlias,
|
||||
hir::ItemKind::Impl(..) => Target::Impl,
|
||||
ItemKind::ExternCrate(..) => Target::ExternCrate,
|
||||
ItemKind::Use(..) => Target::Use,
|
||||
ItemKind::Static(..) => Target::Static,
|
||||
ItemKind::Const(..) => Target::Const,
|
||||
ItemKind::Fn(..) => Target::Fn,
|
||||
ItemKind::Mod(..) => Target::Mod,
|
||||
ItemKind::ForeignMod(..) => Target::ForeignMod,
|
||||
ItemKind::GlobalAsm(..) => Target::GlobalAsm,
|
||||
ItemKind::TyAlias(..) => Target::TyAlias,
|
||||
ItemKind::OpaqueTy(..) => Target::OpaqueTy,
|
||||
ItemKind::Enum(..) => Target::Enum,
|
||||
ItemKind::Struct(..) => Target::Struct,
|
||||
ItemKind::Union(..) => Target::Union,
|
||||
ItemKind::Trait(..) => Target::Trait,
|
||||
ItemKind::TraitAlias(..) => Target::TraitAlias,
|
||||
ItemKind::Impl(..) => Target::Impl,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_trait_item(trait_item: &TraitItem) -> Target {
|
||||
match trait_item.kind {
|
||||
TraitItemKind::Const(..) => Target::AssocConst,
|
||||
TraitItemKind::Method(_, hir::TraitMethod::Required(_)) => {
|
||||
Target::Method(MethodKind::Trait { body: false })
|
||||
}
|
||||
TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
|
||||
Target::Method(MethodKind::Trait { body: true })
|
||||
}
|
||||
TraitItemKind::Type(..) => Target::AssocTy,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_foreign_item(foreign_item: &hir::ForeignItem) -> Target {
|
||||
match foreign_item.kind {
|
||||
hir::ForeignItemKind::Fn(..) => Target::ForeignFn,
|
||||
hir::ForeignItemKind::Static(..) => Target::ForeignStatic,
|
||||
hir::ForeignItemKind::Type => Target::ForeignTy,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem) -> Target {
|
||||
match impl_item.kind {
|
||||
hir::ImplItemKind::Const(..) => Target::AssocConst,
|
||||
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(..) | hir::ImplItemKind::OpaqueTy(..) => Target::AssocTy,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,19 +153,26 @@ struct CheckAttrVisitor<'tcx> {
|
||||
|
||||
impl CheckAttrVisitor<'tcx> {
|
||||
/// Checks any attribute.
|
||||
fn check_attributes(&self, item: &hir::Item, target: Target) {
|
||||
fn check_attributes(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
attrs: &HirVec<Attribute>,
|
||||
span: &Span,
|
||||
target: Target,
|
||||
item: Option<&Item>,
|
||||
) {
|
||||
let mut is_valid = true;
|
||||
for attr in &item.attrs {
|
||||
for attr in attrs {
|
||||
is_valid &= if attr.check_name(sym::inline) {
|
||||
self.check_inline(attr, &item.span, target)
|
||||
self.check_inline(hir_id, attr, span, target)
|
||||
} else if attr.check_name(sym::non_exhaustive) {
|
||||
self.check_non_exhaustive(attr, item, target)
|
||||
self.check_non_exhaustive(attr, span, target)
|
||||
} else if attr.check_name(sym::marker) {
|
||||
self.check_marker(attr, item, target)
|
||||
self.check_marker(attr, span, target)
|
||||
} else if attr.check_name(sym::target_feature) {
|
||||
self.check_target_feature(attr, item, target)
|
||||
self.check_target_feature(attr, span, target)
|
||||
} else if attr.check_name(sym::track_caller) {
|
||||
self.check_track_caller(attr, &item, target)
|
||||
self.check_track_caller(&attr.span, attrs, span, target)
|
||||
} else {
|
||||
true
|
||||
};
|
||||
@ -115,59 +183,105 @@ impl CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
|
||||
if target == Target::Fn {
|
||||
self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(item.hir_id));
|
||||
self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(hir_id));
|
||||
}
|
||||
|
||||
self.check_repr(item, target);
|
||||
self.check_used(item, target);
|
||||
self.check_repr(attrs, span, target, item);
|
||||
self.check_used(attrs, target);
|
||||
}
|
||||
|
||||
/// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
|
||||
fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) -> bool {
|
||||
if target != Target::Fn && target != Target::Closure {
|
||||
struct_span_err!(self.tcx.sess,
|
||||
attr.span,
|
||||
E0518,
|
||||
"attribute should be applied to function or closure")
|
||||
.span_label(*span, "not a function or closure")
|
||||
fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
|
||||
match target {
|
||||
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,
|
||||
attr.span,
|
||||
"`#[inline]` is ignored on function prototypes",
|
||||
).emit();
|
||||
true
|
||||
}
|
||||
// FIXME(#65833): We permit associated consts to have an `#[inline]` attribute with
|
||||
// just a lint, because we previously erroneously allowed it and some crates used it
|
||||
// accidentally, to to be compatible with crates depending on them, we can't throw an
|
||||
// error here.
|
||||
Target::AssocConst => {
|
||||
self.tcx.struct_span_lint_hir(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
"`#[inline]` is ignored on constants",
|
||||
).warn("this was previously accepted by the compiler but is \
|
||||
being phased out; it will become a hard error in \
|
||||
a future release!")
|
||||
.note("for more information, see issue #65833 \
|
||||
<https://github.com/rust-lang/rust/issues/65833>")
|
||||
.emit();
|
||||
false
|
||||
} else {
|
||||
true
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
attr.span,
|
||||
E0518,
|
||||
"attribute should be applied to function or closure",
|
||||
).span_label(*span, "not a function or closure")
|
||||
.emit();
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
|
||||
fn check_track_caller(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) -> bool {
|
||||
if target != Target::Fn {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
attr.span,
|
||||
E0739,
|
||||
"attribute should be applied to function"
|
||||
)
|
||||
.span_label(item.span, "not a function")
|
||||
.emit();
|
||||
false
|
||||
} else if attr::contains_name(&item.attrs, sym::naked) {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
attr.span,
|
||||
E0736,
|
||||
"cannot use `#[track_caller]` with `#[naked]`",
|
||||
)
|
||||
.emit();
|
||||
false
|
||||
} else {
|
||||
true
|
||||
fn check_track_caller(
|
||||
&self,
|
||||
attr_span: &Span,
|
||||
attrs: &HirVec<Attribute>,
|
||||
span: &Span,
|
||||
target: Target,
|
||||
) -> bool {
|
||||
match target {
|
||||
Target::Fn if attr::contains_name(attrs, sym::naked) => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
*attr_span,
|
||||
E0736,
|
||||
"cannot use `#[track_caller]` with `#[naked]`",
|
||||
).emit();
|
||||
false
|
||||
}
|
||||
Target::Fn | Target::Method(MethodKind::Inherent) => true,
|
||||
Target::Method(_) => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
*attr_span,
|
||||
E0738,
|
||||
"`#[track_caller]` may not be used on trait methods",
|
||||
).emit();
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
*attr_span,
|
||||
E0739,
|
||||
"attribute should be applied to function"
|
||||
)
|
||||
.span_label(*span, "not a function")
|
||||
.emit();
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
|
||||
fn check_non_exhaustive(
|
||||
&self,
|
||||
attr: &hir::Attribute,
|
||||
item: &hir::Item,
|
||||
attr: &Attribute,
|
||||
span: &Span,
|
||||
target: Target,
|
||||
) -> bool {
|
||||
match target {
|
||||
@ -177,7 +291,7 @@ impl CheckAttrVisitor<'tcx> {
|
||||
attr.span,
|
||||
E0701,
|
||||
"attribute can only be applied to a struct or enum")
|
||||
.span_label(item.span, "not a struct or enum")
|
||||
.span_label(*span, "not a struct or enum")
|
||||
.emit();
|
||||
false
|
||||
}
|
||||
@ -185,13 +299,13 @@ impl CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
|
||||
/// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid.
|
||||
fn check_marker(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) -> bool {
|
||||
fn check_marker(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
|
||||
match target {
|
||||
Target::Trait => true,
|
||||
_ => {
|
||||
self.tcx.sess
|
||||
.struct_span_err(attr.span, "attribute can only be applied to a trait")
|
||||
.span_label(item.span, "not a trait")
|
||||
.span_label(*span, "not a trait")
|
||||
.emit();
|
||||
false
|
||||
}
|
||||
@ -199,18 +313,14 @@ impl CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
|
||||
/// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid.
|
||||
fn check_target_feature(
|
||||
&self,
|
||||
attr: &hir::Attribute,
|
||||
item: &hir::Item,
|
||||
target: Target,
|
||||
) -> bool {
|
||||
fn check_target_feature(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
|
||||
match target {
|
||||
Target::Fn => 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")
|
||||
.span_label(item.span, "not a function")
|
||||
.span_label(*span, "not a function")
|
||||
.emit();
|
||||
false
|
||||
},
|
||||
@ -218,13 +328,19 @@ impl CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
|
||||
/// Checks if the `#[repr]` attributes on `item` are valid.
|
||||
fn check_repr(&self, item: &hir::Item, target: Target) {
|
||||
fn check_repr(
|
||||
&self,
|
||||
attrs: &HirVec<Attribute>,
|
||||
span: &Span,
|
||||
target: Target,
|
||||
item: Option<&Item>,
|
||||
) {
|
||||
// Extract the names of all repr hints, e.g., [foo, bar, align] for:
|
||||
// ```
|
||||
// #[repr(foo)]
|
||||
// #[repr(bar, align(8))]
|
||||
// ```
|
||||
let hints: Vec<_> = item.attrs
|
||||
let hints: Vec<_> = attrs
|
||||
.iter()
|
||||
.filter(|attr| attr.check_name(sym::repr))
|
||||
.filter_map(|attr| attr.meta_item_list())
|
||||
@ -282,7 +398,7 @@ impl CheckAttrVisitor<'tcx> {
|
||||
};
|
||||
self.emit_repr_error(
|
||||
hint.span(),
|
||||
item.span,
|
||||
*span,
|
||||
&format!("attribute should be applied to {}", allowed_targets),
|
||||
&format!("not {} {}", article, allowed_targets),
|
||||
)
|
||||
@ -301,7 +417,7 @@ impl CheckAttrVisitor<'tcx> {
|
||||
// Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
|
||||
if (int_reprs > 1)
|
||||
|| (is_simd && is_c)
|
||||
|| (int_reprs == 1 && is_c && is_c_like_enum(item)) {
|
||||
|| (int_reprs == 1 && is_c && item.map_or(false, |item| is_c_like_enum(item))) {
|
||||
let hint_spans: Vec<_> = hint_spans.collect();
|
||||
span_warn!(self.tcx.sess, hint_spans, E0566,
|
||||
"conflicting representation hints");
|
||||
@ -325,7 +441,7 @@ impl CheckAttrVisitor<'tcx> {
|
||||
if let hir::StmtKind::Local(ref l) = stmt.kind {
|
||||
for attr in l.attrs.iter() {
|
||||
if attr.check_name(sym::inline) {
|
||||
self.check_inline(attr, &stmt.span, Target::Statement);
|
||||
self.check_inline(DUMMY_HIR_ID, attr, &stmt.span, Target::Statement);
|
||||
}
|
||||
if attr.check_name(sym::repr) {
|
||||
self.emit_repr_error(
|
||||
@ -346,7 +462,7 @@ impl CheckAttrVisitor<'tcx> {
|
||||
};
|
||||
for attr in expr.attrs.iter() {
|
||||
if attr.check_name(sym::inline) {
|
||||
self.check_inline(attr, &expr.span, target);
|
||||
self.check_inline(DUMMY_HIR_ID, attr, &expr.span, target);
|
||||
}
|
||||
if attr.check_name(sym::repr) {
|
||||
self.emit_repr_error(
|
||||
@ -359,8 +475,8 @@ impl CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_used(&self, item: &hir::Item, target: Target) {
|
||||
for attr in &item.attrs {
|
||||
fn check_used(&self, attrs: &HirVec<Attribute>, target: Target) {
|
||||
for attr in attrs {
|
||||
if attr.check_name(sym::used) && target != Target::Static {
|
||||
self.tcx.sess
|
||||
.span_err(attr.span, "attribute must be applied to a `static` variable");
|
||||
@ -374,12 +490,29 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
||||
NestedVisitorMap::OnlyBodies(&self.tcx.hir())
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item) {
|
||||
fn visit_item(&mut self, item: &'tcx Item) {
|
||||
let target = Target::from_item(item);
|
||||
self.check_attributes(item, target);
|
||||
self.check_attributes(item.hir_id, &item.attrs, &item.span, target, Some(item));
|
||||
intravisit::walk_item(self, item)
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem) {
|
||||
let target = Target::from_trait_item(trait_item);
|
||||
self.check_attributes(trait_item.hir_id, &trait_item.attrs, &trait_item.span, target, None);
|
||||
intravisit::walk_trait_item(self, trait_item)
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, f_item: &'tcx hir::ForeignItem) {
|
||||
let target = Target::from_foreign_item(f_item);
|
||||
self.check_attributes(f_item.hir_id, &f_item.attrs, &f_item.span, target, None);
|
||||
intravisit::walk_foreign_item(self, f_item)
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
|
||||
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)
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) {
|
||||
self.check_stmt_attributes(stmt);
|
||||
@ -392,12 +525,12 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_c_like_enum(item: &hir::Item) -> bool {
|
||||
if let hir::ItemKind::Enum(ref def, _) = item.kind {
|
||||
fn is_c_like_enum(item: &Item) -> bool {
|
||||
if let ItemKind::Enum(ref def, _) = item.kind {
|
||||
for variant in &def.variants {
|
||||
match variant.data {
|
||||
hir::VariantData::Unit(..) => { /* continue */ }
|
||||
_ => { return false; }
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
true
|
||||
|
@ -203,7 +203,7 @@ pub trait Visitor<'v>: Sized {
|
||||
|
||||
/// Invoked to visit the body of a function, method or closure. Like
|
||||
/// visit_nested_item, does nothing by default unless you override
|
||||
/// `nested_visit_map` to return other htan `None`, in which case it will walk
|
||||
/// `nested_visit_map` to return other than `None`, in which case it will walk
|
||||
/// the body.
|
||||
fn visit_nested_body(&mut self, id: BodyId) {
|
||||
let opt_body = self.nested_visit_map().intra().map(|map| map.body(id));
|
||||
|
@ -2512,7 +2512,7 @@ pub enum ItemKind {
|
||||
Fn(P<FnDecl>, FnHeader, Generics, BodyId),
|
||||
/// A module.
|
||||
Mod(Mod),
|
||||
/// An external module.
|
||||
/// An external module, e.g. `extern { .. }`.
|
||||
ForeignMod(ForeignMod),
|
||||
/// Module-level inline assembly (from `global_asm!`).
|
||||
GlobalAsm(P<GlobalAsm>),
|
||||
@ -2756,10 +2756,10 @@ bitflags! {
|
||||
/// `#[used]`: indicates that LLVM can't eliminate this function (but the
|
||||
/// linker can!).
|
||||
const USED = 1 << 9;
|
||||
/// #[ffi_returns_twice], indicates that an extern function can return
|
||||
/// `#[ffi_returns_twice]`, indicates that an extern function can return
|
||||
/// multiple times
|
||||
const FFI_RETURNS_TWICE = 1 << 10;
|
||||
/// #[track_caller]: allow access to the caller location
|
||||
/// `#[track_caller]`: allow access to the caller location
|
||||
const TRACK_CALLER = 1 << 11;
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,12 @@ declare_lint! {
|
||||
"detect unused, unexported items"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub UNUSED_ATTRIBUTES,
|
||||
Warn,
|
||||
"detects attributes that were not used by the compiler"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub UNREACHABLE_CODE,
|
||||
Warn,
|
||||
|
@ -9,5 +9,5 @@ name = "rustc_apfloat"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
bitflags = "1.2.1"
|
||||
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
|
||||
|
@ -10,7 +10,7 @@ path = "lib.rs"
|
||||
test = false
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0.4"
|
||||
bitflags = "1.2.1"
|
||||
cc = "1.0.1"
|
||||
num_cpus = "1.0"
|
||||
memmap = "0.6"
|
||||
|
@ -1,6 +1,7 @@
|
||||
use rustc::hir::def::{Res, DefKind};
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::lint;
|
||||
use rustc::lint::builtin::UNUSED_ATTRIBUTES;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::adjustment;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
@ -277,12 +278,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements {
|
||||
}
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub UNUSED_ATTRIBUTES,
|
||||
Warn,
|
||||
"detects attributes that were not used by the compiler"
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct UnusedAttributes {
|
||||
builtin_attributes: &'static FxHashMap<Symbol, &'static BuiltinAttribute>,
|
||||
|
@ -11,7 +11,7 @@ test = false
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
bitflags = "1.2.1"
|
||||
log = "0.4"
|
||||
syntax = { path = "../libsyntax" }
|
||||
syntax_expand = { path = "../libsyntax_expand" }
|
||||
|
@ -9,7 +9,7 @@ name = "rustc_target"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
bitflags = "1.2.1"
|
||||
log = "0.4"
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_serialize = { path = "../libserialize", package = "serialize" }
|
||||
|
@ -172,18 +172,6 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: DefId) {
|
||||
_ => None
|
||||
};
|
||||
check_associated_item(tcx, trait_item.hir_id, trait_item.span, method_sig);
|
||||
|
||||
// Prohibits applying `#[track_caller]` to trait decls
|
||||
for attr in &trait_item.attrs {
|
||||
if attr.check_name(sym::track_caller) {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
attr.span,
|
||||
E0738,
|
||||
"`#[track_caller]` is not supported in trait declarations."
|
||||
).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: DefId) {
|
||||
@ -195,29 +183,6 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: DefId) {
|
||||
_ => None
|
||||
};
|
||||
|
||||
// Prohibits applying `#[track_caller]` to trait impls
|
||||
if method_sig.is_some() {
|
||||
let track_caller_attr = impl_item.attrs.iter()
|
||||
.find(|a| a.check_name(sym::track_caller));
|
||||
if let Some(tc_attr) = track_caller_attr {
|
||||
let parent_hir_id = tcx.hir().get_parent_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 {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
tc_attr.span,
|
||||
E0738,
|
||||
"`#[track_caller]` is not supported in traits yet."
|
||||
).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check_associated_item(tcx, impl_item.hir_id, impl_item.span, method_sig);
|
||||
}
|
||||
|
||||
|
@ -2641,7 +2641,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
||||
tcx.sess,
|
||||
attr.span,
|
||||
E0737,
|
||||
"rust ABI is required to use `#[track_caller]`"
|
||||
"Rust ABI is required to use `#[track_caller]`"
|
||||
).emit();
|
||||
}
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
|
||||
|
@ -4958,7 +4958,7 @@ and the pin is required to keep it in the same place in memory.
|
||||
"##,
|
||||
|
||||
E0737: r##"
|
||||
#[track_caller] requires functions to have the "Rust" ABI for implicitly
|
||||
`#[track_caller]` requires functions to have the `"Rust"` ABI for implicitly
|
||||
receiving caller location. See [RFC 2091] for details on this and other
|
||||
restrictions.
|
||||
|
||||
@ -4974,57 +4974,6 @@ extern "C" fn foo() {}
|
||||
[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
|
||||
"##,
|
||||
|
||||
E0738: r##"
|
||||
#[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.
|
||||
|
||||
Erroneous example with a trait method implementation:
|
||||
|
||||
```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 {
|
||||
#[track_caller]
|
||||
fn bar(&self) {}
|
||||
fn baz(&self);
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
"##,
|
||||
|
||||
E0741: r##"
|
||||
Only `structural_match` types (that is, types that derive `PartialEq` and `Eq`)
|
||||
may be used as the types of const generic parameters.
|
||||
|
@ -10,7 +10,7 @@ path = "lib.rs"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
bitflags = "1.2.1"
|
||||
rustc_serialize = { path = "../libserialize", package = "serialize" }
|
||||
log = "0.4"
|
||||
scoped-tls = "1.0"
|
||||
|
8
src/test/ui/issues/issue-52057.stderr
Normal file
8
src/test/ui/issues/issue-52057.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
warning: `#[inline]` is ignored on function prototypes
|
||||
--> $DIR/issue-52057.rs:10:5
|
||||
|
|
||||
LL | #[inline(always)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(unused_attributes)]` on by default
|
||||
|
37
src/test/ui/lint/inline-trait-and-foreign-items.rs
Normal file
37
src/test/ui/lint/inline-trait-and-foreign-items.rs
Normal file
@ -0,0 +1,37 @@
|
||||
#![feature(extern_types)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
#![warn(unused_attributes)]
|
||||
|
||||
trait Trait {
|
||||
#[inline] //~ WARN `#[inline]` is ignored on constants
|
||||
//~^ WARN this was previously accepted
|
||||
const X: u32;
|
||||
|
||||
#[inline] //~ ERROR attribute should be applied to function or closure
|
||||
type T;
|
||||
|
||||
type U;
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
#[inline] //~ WARN `#[inline]` is ignored on constants
|
||||
//~^ WARN this was previously accepted
|
||||
const X: u32 = 0;
|
||||
|
||||
#[inline] //~ ERROR attribute should be applied to function or closure
|
||||
type T = Self;
|
||||
|
||||
#[inline] //~ ERROR attribute should be applied to function or closure
|
||||
type U = impl Trait; //~ ERROR could not find defining uses
|
||||
}
|
||||
|
||||
extern {
|
||||
#[inline] //~ ERROR attribute should be applied to function or closure
|
||||
static X: u32;
|
||||
|
||||
#[inline] //~ ERROR attribute should be applied to function or closure
|
||||
type T;
|
||||
}
|
||||
|
||||
fn main() {}
|
72
src/test/ui/lint/inline-trait-and-foreign-items.stderr
Normal file
72
src/test/ui/lint/inline-trait-and-foreign-items.stderr
Normal file
@ -0,0 +1,72 @@
|
||||
error[E0518]: attribute should be applied to function or closure
|
||||
--> $DIR/inline-trait-and-foreign-items.rs:30:5
|
||||
|
|
||||
LL | #[inline]
|
||||
| ^^^^^^^^^
|
||||
LL | static X: u32;
|
||||
| -------------- not a function or closure
|
||||
|
||||
error[E0518]: attribute should be applied to function or closure
|
||||
--> $DIR/inline-trait-and-foreign-items.rs:33:5
|
||||
|
|
||||
LL | #[inline]
|
||||
| ^^^^^^^^^
|
||||
LL | type T;
|
||||
| ------- not a function or closure
|
||||
|
||||
warning: `#[inline]` is ignored on constants
|
||||
--> $DIR/inline-trait-and-foreign-items.rs:7:5
|
||||
|
|
||||
LL | #[inline]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/inline-trait-and-foreign-items.rs:4:9
|
||||
|
|
||||
LL | #![warn(unused_attributes)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #65833 <https://github.com/rust-lang/rust/issues/65833>
|
||||
|
||||
error[E0518]: attribute should be applied to function or closure
|
||||
--> $DIR/inline-trait-and-foreign-items.rs:11:5
|
||||
|
|
||||
LL | #[inline]
|
||||
| ^^^^^^^^^
|
||||
LL | type T;
|
||||
| ------- not a function or closure
|
||||
|
||||
warning: `#[inline]` is ignored on constants
|
||||
--> $DIR/inline-trait-and-foreign-items.rs:18:5
|
||||
|
|
||||
LL | #[inline]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #65833 <https://github.com/rust-lang/rust/issues/65833>
|
||||
|
||||
error[E0518]: attribute should be applied to function or closure
|
||||
--> $DIR/inline-trait-and-foreign-items.rs:22:5
|
||||
|
|
||||
LL | #[inline]
|
||||
| ^^^^^^^^^
|
||||
LL | type T = Self;
|
||||
| -------------- not a function or closure
|
||||
|
||||
error[E0518]: attribute should be applied to function or closure
|
||||
--> $DIR/inline-trait-and-foreign-items.rs:25:5
|
||||
|
|
||||
LL | #[inline]
|
||||
| ^^^^^^^^^
|
||||
LL | type U = impl Trait;
|
||||
| -------------------- not a function or closure
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/inline-trait-and-foreign-items.rs:26:5
|
||||
|
|
||||
LL | type U = impl Trait;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0518`.
|
13
src/test/ui/lint/warn-unused-inline-on-fn-prototypes.rs
Normal file
13
src/test/ui/lint/warn-unused-inline-on-fn-prototypes.rs
Normal file
@ -0,0 +1,13 @@
|
||||
#![deny(unused_attributes)]
|
||||
|
||||
trait Trait {
|
||||
#[inline] //~ ERROR `#[inline]` is ignored on function prototypes
|
||||
fn foo();
|
||||
}
|
||||
|
||||
extern {
|
||||
#[inline] //~ ERROR `#[inline]` is ignored on function prototypes
|
||||
fn foo();
|
||||
}
|
||||
|
||||
fn main() {}
|
20
src/test/ui/lint/warn-unused-inline-on-fn-prototypes.stderr
Normal file
20
src/test/ui/lint/warn-unused-inline-on-fn-prototypes.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error: `#[inline]` is ignored on function prototypes
|
||||
--> $DIR/warn-unused-inline-on-fn-prototypes.rs:9:5
|
||||
|
|
||||
LL | #[inline]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/warn-unused-inline-on-fn-prototypes.rs:1:9
|
||||
|
|
||||
LL | #![deny(unused_attributes)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `#[inline]` is ignored on function prototypes
|
||||
--> $DIR/warn-unused-inline-on-fn-prototypes.rs:4:5
|
||||
|
|
||||
LL | #[inline]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -1,7 +1,6 @@
|
||||
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
|
||||
|
||||
#[track_caller]
|
||||
#[track_caller] //~ ERROR Rust ABI is required to use `#[track_caller]`
|
||||
extern "C" fn f() {}
|
||||
//~^^ ERROR rust ABI is required to use `#[track_caller]`
|
||||
|
||||
fn main() {}
|
||||
|
@ -6,7 +6,7 @@ LL | #![feature(track_caller)]
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0737]: rust ABI is required to use `#[track_caller]`
|
||||
error[E0737]: Rust ABI is required to use `#[track_caller]`
|
||||
--> $DIR/error-with-invalid-abi.rs:3:1
|
||||
|
|
||||
LL | #[track_caller]
|
||||
|
@ -1,9 +1,8 @@
|
||||
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
|
||||
|
||||
trait Trait {
|
||||
#[track_caller]
|
||||
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods
|
||||
fn unwrap(&self);
|
||||
//~^^ ERROR: `#[track_caller]` is not supported in trait declarations.
|
||||
}
|
||||
|
||||
impl Trait for u64 {
|
||||
|
@ -6,7 +6,7 @@ LL | #![feature(track_caller)]
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0738]: `#[track_caller]` is not supported in trait declarations.
|
||||
error[E0738]: `#[track_caller]` may not be used on trait methods
|
||||
--> $DIR/error-with-trait-decl.rs:4:5
|
||||
|
|
||||
LL | #[track_caller]
|
||||
|
@ -1,9 +1,8 @@
|
||||
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
|
||||
|
||||
trait Trait {
|
||||
#[track_caller]
|
||||
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods
|
||||
fn unwrap(&self) {}
|
||||
//~^^ ERROR: `#[track_caller]` is not supported in trait declarations.
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -6,7 +6,7 @@ LL | #![feature(track_caller)]
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0738]: `#[track_caller]` is not supported in trait declarations.
|
||||
error[E0738]: `#[track_caller]` may not be used on trait methods
|
||||
--> $DIR/error-with-trait-default-impl.rs:4:5
|
||||
|
|
||||
LL | #[track_caller]
|
||||
|
@ -1,3 +1,5 @@
|
||||
// check-fail
|
||||
|
||||
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
|
||||
|
||||
trait Trait {
|
||||
@ -5,9 +7,15 @@ trait Trait {
|
||||
}
|
||||
|
||||
impl Trait for u64 {
|
||||
#[track_caller]
|
||||
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods
|
||||
fn unwrap(&self) {}
|
||||
//~^^ ERROR: `#[track_caller]` is not supported in traits yet.
|
||||
}
|
||||
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
#[track_caller] // ok
|
||||
fn foo() {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,13 +1,13 @@
|
||||
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)]
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0738]: `#[track_caller]` is not supported in traits yet.
|
||||
--> $DIR/error-with-trait-fn-impl.rs:8:5
|
||||
error[E0738]: `#[track_caller]` may not be used on trait methods
|
||||
--> $DIR/error-with-trait-fn-impl.rs:10:5
|
||||
|
|
||||
LL | #[track_caller]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
Loading…
Reference in New Issue
Block a user