Auto merge of #80641 - Danue1:patch-1, r=oli-obk

Add visitors for checking #[inline]

For #80564
This commit is contained in:
bors 2021-02-01 19:31:01 +00:00
commit d4e3570db4
9 changed files with 344 additions and 56 deletions

View File

@ -38,12 +38,14 @@ pub enum Target {
Enum, Enum,
Variant, Variant,
Struct, Struct,
Field,
Union, Union,
Trait, Trait,
TraitAlias, TraitAlias,
Impl, Impl,
Expression, Expression,
Statement, Statement,
Arm,
AssocConst, AssocConst,
Method(MethodKind), Method(MethodKind),
AssocTy, AssocTy,
@ -51,6 +53,7 @@ pub enum Target {
ForeignStatic, ForeignStatic,
ForeignTy, ForeignTy,
GenericParam(GenericParamKind), GenericParam(GenericParamKind),
MacroDef,
} }
impl Display for Target { impl Display for Target {
@ -73,12 +76,14 @@ impl Display for Target {
Target::Enum => "enum", Target::Enum => "enum",
Target::Variant => "enum variant", Target::Variant => "enum variant",
Target::Struct => "struct", Target::Struct => "struct",
Target::Field => "struct field",
Target::Union => "union", Target::Union => "union",
Target::Trait => "trait", Target::Trait => "trait",
Target::TraitAlias => "trait alias", Target::TraitAlias => "trait alias",
Target::Impl => "item", Target::Impl => "item",
Target::Expression => "expression", Target::Expression => "expression",
Target::Statement => "statement", Target::Statement => "statement",
Target::Arm => "match arm",
Target::AssocConst => "associated const", Target::AssocConst => "associated const",
Target::Method(_) => "method", Target::Method(_) => "method",
Target::AssocTy => "associated type", Target::AssocTy => "associated type",
@ -90,6 +95,7 @@ impl Display for Target {
GenericParamKind::Lifetime => "lifetime parameter", GenericParamKind::Lifetime => "lifetime parameter",
GenericParamKind::Const => "const parameter", GenericParamKind::Const => "const parameter",
}, },
Target::MacroDef => "macro def",
} }
) )
} }

View File

@ -8,6 +8,7 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, Definitions}; use rustc_hir::definitions::{DefKey, DefPath, Definitions};
use rustc_hir::intravisit; use rustc_hir::intravisit;
use rustc_hir::intravisit::Visitor;
use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::*; use rustc_hir::*;
use rustc_index::vec::IndexVec; use rustc_index::vec::IndexVec;
@ -494,6 +495,15 @@ impl<'hir> Map<'hir> {
} }
} }
pub fn visit_exported_macros_in_krate<V>(&self, visitor: &mut V)
where
V: Visitor<'hir>,
{
for id in self.krate().exported_macros {
visitor.visit_macro_def(self.expect_macro_def(id.hir_id));
}
}
/// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found. /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
pub fn get(&self, id: HirId) -> Node<'hir> { pub fn get(&self, id: HirId) -> Node<'hir> {
self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id)) self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
@ -802,6 +812,13 @@ impl<'hir> Map<'hir> {
} }
} }
pub fn expect_macro_def(&self, id: HirId) -> &'hir MacroDef<'hir> {
match self.find(id) {
Some(Node::MacroDef(macro_def)) => macro_def,
_ => bug!("expected macro def, found {}", self.node_to_string(id)),
}
}
pub fn expect_expr(&self, id: HirId) -> &'hir Expr<'hir> { pub fn expect_expr(&self, id: HirId) -> &'hir Expr<'hir> {
match self.find(id) { match self.find(id) {
Some(Node::Expr(expr)) => expr, Some(Node::Expr(expr)) => expr,
@ -821,6 +838,7 @@ impl<'hir> Map<'hir> {
Node::GenericParam(param) => param.name.ident().name, Node::GenericParam(param) => param.name.ident().name,
Node::Binding(&Pat { kind: PatKind::Binding(_, _, l, _), .. }) => l.name, Node::Binding(&Pat { kind: PatKind::Binding(_, _, l, _), .. }) => l.name,
Node::Ctor(..) => self.name(self.get_parent_item(id)), Node::Ctor(..) => self.name(self.get_parent_item(id)),
Node::MacroDef(md) => md.ident.name,
_ => return None, _ => return None,
}) })
} }

View File

@ -70,27 +70,27 @@ impl CheckAttrVisitor<'tcx> {
is_valid &= if self.tcx.sess.check_name(attr, sym::inline) { is_valid &= if self.tcx.sess.check_name(attr, sym::inline) {
self.check_inline(hir_id, attr, span, target) self.check_inline(hir_id, attr, span, target)
} else if self.tcx.sess.check_name(attr, sym::non_exhaustive) { } else if self.tcx.sess.check_name(attr, sym::non_exhaustive) {
self.check_non_exhaustive(attr, span, target) self.check_non_exhaustive(hir_id, attr, span, target)
} else if self.tcx.sess.check_name(attr, sym::marker) { } else if self.tcx.sess.check_name(attr, sym::marker) {
self.check_marker(attr, span, target) self.check_marker(hir_id, attr, span, target)
} else if self.tcx.sess.check_name(attr, sym::target_feature) { } else if self.tcx.sess.check_name(attr, sym::target_feature) {
self.check_target_feature(hir_id, attr, span, target) self.check_target_feature(hir_id, attr, span, target)
} else if self.tcx.sess.check_name(attr, sym::track_caller) { } else if self.tcx.sess.check_name(attr, sym::track_caller) {
self.check_track_caller(&attr.span, attrs, span, target) self.check_track_caller(hir_id, &attr.span, attrs, span, target)
} else if self.tcx.sess.check_name(attr, sym::doc) { } else if self.tcx.sess.check_name(attr, sym::doc) {
self.check_doc_attrs(attr, hir_id, target) self.check_doc_attrs(attr, hir_id, target)
} else if self.tcx.sess.check_name(attr, sym::no_link) { } else if self.tcx.sess.check_name(attr, sym::no_link) {
self.check_no_link(&attr, span, target) self.check_no_link(hir_id, &attr, span, target)
} else if self.tcx.sess.check_name(attr, sym::export_name) { } else if self.tcx.sess.check_name(attr, sym::export_name) {
self.check_export_name(&attr, span, target) self.check_export_name(hir_id, &attr, span, target)
} else if self.tcx.sess.check_name(attr, sym::rustc_args_required_const) { } else if self.tcx.sess.check_name(attr, sym::rustc_args_required_const) {
self.check_rustc_args_required_const(&attr, span, target, item) self.check_rustc_args_required_const(&attr, span, target, item)
} else if self.tcx.sess.check_name(attr, sym::allow_internal_unstable) { } else if self.tcx.sess.check_name(attr, sym::allow_internal_unstable) {
self.check_allow_internal_unstable(&attr, span, target, &attrs) self.check_allow_internal_unstable(hir_id, &attr, span, target, &attrs)
} else if self.tcx.sess.check_name(attr, sym::rustc_allow_const_fn_unstable) { } else if self.tcx.sess.check_name(attr, sym::rustc_allow_const_fn_unstable) {
self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target) self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target)
} else if self.tcx.sess.check_name(attr, sym::naked) { } else if self.tcx.sess.check_name(attr, sym::naked) {
self.check_naked(attr, span, target) self.check_naked(hir_id, attr, span, target)
} else { } else {
// lint-only checks // lint-only checks
if self.tcx.sess.check_name(attr, sym::cold) { if self.tcx.sess.check_name(attr, sym::cold) {
@ -118,6 +118,41 @@ impl CheckAttrVisitor<'tcx> {
self.check_used(attrs, target); self.check_used(attrs, target);
} }
fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
lint.build(&format!(
"`#[{}]` is ignored on struct fields, match arms and macro defs",
sym,
))
.warn(
"this was previously accepted by the compiler but is \
being phased out; it will become a hard error in \
a future release!",
)
.note(
"see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \
for more information",
)
.emit();
});
}
fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
lint.build(&format!("`#[{}]` is ignored on struct fields and match arms", sym))
.warn(
"this was previously accepted by the compiler but is \
being phased out; it will become a hard error in \
a future release!",
)
.note(
"see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \
for more information",
)
.emit();
});
}
/// 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 {
@ -150,6 +185,11 @@ impl CheckAttrVisitor<'tcx> {
}); });
true true
} }
// FIXME(#80564): Same for fields, arms, and macro defs
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "inline");
true
}
_ => { _ => {
struct_span_err!( struct_span_err!(
self.tcx.sess, self.tcx.sess,
@ -165,10 +205,18 @@ impl CheckAttrVisitor<'tcx> {
} }
/// Checks if `#[naked]` is applied to a function definition. /// Checks if `#[naked]` is applied to a function definition.
fn check_naked(&self, attr: &Attribute, span: &Span, target: Target) -> bool { fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
match target { match target {
Target::Fn Target::Fn
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[allow_internal_unstable]` 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::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked");
true
}
_ => { _ => {
self.tcx self.tcx
.sess .sess
@ -186,6 +234,7 @@ impl CheckAttrVisitor<'tcx> {
/// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid. /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
fn check_track_caller( fn check_track_caller(
&self, &self,
hir_id: HirId,
attr_span: &Span, attr_span: &Span,
attrs: &'hir [Attribute], attrs: &'hir [Attribute],
span: &Span, span: &Span,
@ -203,6 +252,16 @@ impl CheckAttrVisitor<'tcx> {
false false
} }
Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true, Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[track_caller]` 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::Field | Target::Arm | Target::MacroDef => {
for attr in attrs {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "track_caller");
}
true
}
_ => { _ => {
struct_span_err!( struct_span_err!(
self.tcx.sess, self.tcx.sess,
@ -218,9 +277,23 @@ impl CheckAttrVisitor<'tcx> {
} }
/// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid. /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
fn check_non_exhaustive(&self, attr: &Attribute, span: &Span, target: Target) -> bool { fn check_non_exhaustive(
&self,
hir_id: HirId,
attr: &Attribute,
span: &Span,
target: Target,
) -> bool {
match target { match target {
Target::Struct | Target::Enum | Target::Variant => true, Target::Struct | Target::Enum | Target::Variant => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[non_exhaustive]` 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::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "non_exhaustive");
true
}
_ => { _ => {
struct_span_err!( struct_span_err!(
self.tcx.sess, self.tcx.sess,
@ -236,9 +309,17 @@ impl CheckAttrVisitor<'tcx> {
} }
/// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid. /// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid.
fn check_marker(&self, attr: &Attribute, span: &Span, target: Target) -> bool { fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
match target { match target {
Target::Trait => true, Target::Trait => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[marker]` 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::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "marker");
true
}
_ => { _ => {
self.tcx self.tcx
.sess .sess
@ -276,6 +357,14 @@ impl CheckAttrVisitor<'tcx> {
}); });
true true
} }
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[target_feature]` 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::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature");
true
}
_ => { _ => {
self.tcx self.tcx
.sess .sess
@ -464,6 +553,13 @@ impl CheckAttrVisitor<'tcx> {
fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
match target { match target {
Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {} Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[cold]` 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::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "cold");
}
_ => { _ => {
// FIXME: #[cold] was previously allowed on non-functions and some crates used // FIXME: #[cold] was previously allowed on non-functions and some crates used
// this, so only emit a warning. // this, so only emit a warning.
@ -485,6 +581,13 @@ impl CheckAttrVisitor<'tcx> {
fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
match target { match target {
Target::ForeignFn | Target::ForeignStatic => {} Target::ForeignFn | Target::ForeignStatic => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[link_name]` 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::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_name");
}
_ => { _ => {
// FIXME: #[cold] was previously allowed on non-functions/statics and some crates // FIXME: #[cold] was previously allowed on non-functions/statics and some crates
// used this, so only emit a warning. // used this, so only emit a warning.
@ -517,23 +620,49 @@ impl CheckAttrVisitor<'tcx> {
} }
/// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid. /// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid.
fn check_no_link(&self, attr: &Attribute, span: &Span, target: Target) -> bool { fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
if target == Target::ExternCrate { match target {
true Target::ExternCrate => true,
} else { // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
self.tcx // `#[no_link]` attribute with just a lint, because we previously
.sess // erroneously allowed it and some crates used it accidentally, to to be compatible
.struct_span_err(attr.span, "attribute should be applied to an `extern crate` item") // with crates depending on them, we can't throw an error here.
.span_label(*span, "not an `extern crate` item") Target::Field | Target::Arm | Target::MacroDef => {
.emit(); self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link");
false true
}
_ => {
self.tcx
.sess
.struct_span_err(
attr.span,
"attribute should be applied to an `extern crate` item",
)
.span_label(*span, "not an `extern crate` item")
.emit();
false
}
} }
} }
/// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid. /// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid.
fn check_export_name(&self, attr: &Attribute, span: &Span, target: Target) -> bool { fn check_export_name(
&self,
hir_id: HirId,
attr: &Attribute,
span: &Span,
target: Target,
) -> bool {
match target { match target {
Target::Static | Target::Fn | Target::Method(..) => true, Target::Static | Target::Fn | Target::Method(..) => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[export_name]` 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::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name");
true
}
_ => { _ => {
self.tcx self.tcx
.sess .sess
@ -625,6 +754,13 @@ impl CheckAttrVisitor<'tcx> {
fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
match target { match target {
Target::Static | Target::Fn | Target::Method(..) => {} Target::Static | Target::Fn | Target::Method(..) => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[link_section]` 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::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_section");
}
_ => { _ => {
// FIXME: #[link_section] was previously allowed on non-functions/statics and some // FIXME: #[link_section] was previously allowed on non-functions/statics and some
// crates used this, so only emit a warning. // crates used this, so only emit a warning.
@ -646,6 +782,13 @@ impl CheckAttrVisitor<'tcx> {
fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
match target { match target {
Target::Static | Target::Fn | Target::Method(..) => {} Target::Static | Target::Fn | Target::Method(..) => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[no_mangle]` 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::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_mangle");
}
_ => { _ => {
// FIXME: #[no_mangle] was previously allowed on non-functions/statics and some // FIXME: #[no_mangle] was previously allowed on non-functions/statics and some
// crates used this, so only emit a warning. // crates used this, so only emit a warning.
@ -828,27 +971,46 @@ impl CheckAttrVisitor<'tcx> {
/// (Allows proc_macro functions) /// (Allows proc_macro functions)
fn check_allow_internal_unstable( fn check_allow_internal_unstable(
&self, &self,
hir_id: HirId,
attr: &Attribute, attr: &Attribute,
span: &Span, span: &Span,
target: Target, target: Target,
attrs: &[Attribute], attrs: &[Attribute],
) -> bool { ) -> bool {
debug!("Checking target: {:?}", target); debug!("Checking target: {:?}", target);
if target == Target::Fn { match target {
for attr in attrs { Target::Fn => {
if self.tcx.sess.is_proc_macro_attr(attr) { for attr in attrs {
debug!("Is proc macro attr"); if self.tcx.sess.is_proc_macro_attr(attr) {
return true; debug!("Is proc macro attr");
return true;
}
} }
debug!("Is not proc macro attr");
false
}
Target::MacroDef => true,
// FIXME(#80564): We permit struct fields and match arms to have an
// `#[allow_internal_unstable]` 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::Field | Target::Arm => {
self.inline_attr_str_error_without_macro_def(
hir_id,
attr,
"allow_internal_unstable",
);
true
}
_ => {
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied to a macro")
.span_label(*span, "not a macro")
.emit();
false
} }
debug!("Is not proc macro attr");
} }
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied to a macro")
.span_label(*span, "not a macro")
.emit();
false
} }
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros. /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
@ -860,17 +1022,29 @@ impl CheckAttrVisitor<'tcx> {
span: &Span, span: &Span,
target: Target, target: Target,
) -> bool { ) -> bool {
if let Target::Fn | Target::Method(_) = target { match target {
if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id)) { Target::Fn | Target::Method(_)
return true; if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id)) =>
{
true
}
// FIXME(#80564): We permit struct fields and match arms to have an
// `#[allow_internal_unstable]` 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::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable");
true
}
_ => {
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied to `const fn`")
.span_label(*span, "not a `const fn`")
.emit();
false
} }
} }
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied to `const fn`")
.span_label(*span, "not a `const fn`")
.emit();
false
} }
} }
@ -911,6 +1085,33 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
intravisit::walk_trait_item(self, trait_item) intravisit::walk_trait_item(self, trait_item)
} }
fn visit_struct_field(&mut self, struct_field: &'tcx hir::StructField<'tcx>) {
self.check_attributes(
struct_field.hir_id,
&struct_field.attrs,
&struct_field.span,
Target::Field,
None,
);
intravisit::walk_struct_field(self, struct_field);
}
fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
self.check_attributes(arm.hir_id, &arm.attrs, &arm.span, Target::Arm, None);
intravisit::walk_arm(self, arm);
}
fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef<'tcx>) {
self.check_attributes(
macro_def.hir_id,
&macro_def.attrs,
&macro_def.span,
Target::MacroDef,
None,
);
intravisit::walk_macro_def(self, macro_def);
}
fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) { fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
let target = Target::from_foreign_item(f_item); let target = Target::from_foreign_item(f_item);
self.check_attributes( self.check_attributes(
@ -999,11 +1200,28 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
} }
} }
fn check_invalid_macro_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
for attr in attrs {
if tcx.sess.check_name(attr, sym::inline) {
struct_span_err!(
tcx.sess,
attr.span,
E0518,
"attribute should be applied to function or closure",
)
.span_label(attr.span, "not a function or closure")
.emit();
}
}
}
fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir() let check_attr_visitor = &mut CheckAttrVisitor { tcx };
.visit_item_likes_in_module(module_def_id, &mut CheckAttrVisitor { tcx }.as_deep_visitor()); tcx.hir().visit_item_likes_in_module(module_def_id, &mut check_attr_visitor.as_deep_visitor());
tcx.hir().visit_exported_macros_in_krate(check_attr_visitor);
check_invalid_macro_level_attr(tcx, tcx.hir().krate().non_exported_macro_attrs);
if module_def_id.is_top_level_module() { if module_def_id.is_top_level_module() {
CheckAttrVisitor { tcx }.check_attributes( check_attr_visitor.check_attributes(
CRATE_HIR_ID, CRATE_HIR_ID,
tcx.hir().krate_attrs(), tcx.hir().krate_attrs(),
&DUMMY_SP, &DUMMY_SP,

View File

@ -6,4 +6,20 @@ fn f() {}
#[inline] //~ ERROR: attribute should be applied to function or closure #[inline] //~ ERROR: attribute should be applied to function or closure
struct S; struct S;
struct I {
#[inline]
i: u8,
}
#[macro_export]
#[inline]
macro_rules! m_e {
() => {};
}
#[inline] //~ ERROR: attribute should be applied to function or closure
macro_rules! m {
() => {};
}
fn main() {} fn main() {}

View File

@ -6,6 +6,12 @@ LL | #[inline]
LL | struct S; LL | struct S;
| --------- not a function or closure | --------- not a function or closure
error: aborting due to previous error error[E0518]: attribute should be applied to function or closure
--> $DIR/attr-usage-inline.rs:20:1
|
LL | #[inline]
| ^^^^^^^^^ not a function or closure
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0518`. For more information about this error, try `rustc --explain E0518`.

View File

@ -1,10 +1,17 @@
// aux-build:internal_unstable.rs // aux-build:internal_unstable.rs
#![feature(allow_internal_unstable)] #![feature(allow_internal_unstable)]
#[allow(dead_code)]
#[macro_use] #[macro_use]
extern crate internal_unstable; extern crate internal_unstable;
struct Baz {
#[allow_internal_unstable]
//^ WARN `#[allow_internal_unstable]` is ignored on struct fields and match arms
baz: u8,
}
macro_rules! foo { macro_rules! foo {
($e: expr, $f: expr) => {{ ($e: expr, $f: expr) => {{
$e; $e;
@ -40,4 +47,10 @@ fn main() {
println!("{:?}", internal_unstable::unstable()); //~ ERROR use of unstable println!("{:?}", internal_unstable::unstable()); //~ ERROR use of unstable
bar!(internal_unstable::unstable()); //~ ERROR use of unstable bar!(internal_unstable::unstable()); //~ ERROR use of unstable
match true {
#[allow_internal_unstable]
//^ WARN `#[allow_internal_unstable]` is ignored on struct fields and match arms
_ => {}
}
} }

View File

@ -1,5 +1,5 @@
error[E0658]: use of unstable library feature 'function' error[E0658]: use of unstable library feature 'function'
--> $DIR/internal-unstable.rs:34:25 --> $DIR/internal-unstable.rs:41:25
| |
LL | pass_through_allow!(internal_unstable::unstable()); LL | pass_through_allow!(internal_unstable::unstable());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -7,7 +7,7 @@ LL | pass_through_allow!(internal_unstable::unstable());
= help: add `#![feature(function)]` to the crate attributes to enable = help: add `#![feature(function)]` to the crate attributes to enable
error[E0658]: use of unstable library feature 'function' error[E0658]: use of unstable library feature 'function'
--> $DIR/internal-unstable.rs:36:27 --> $DIR/internal-unstable.rs:43:27
| |
LL | pass_through_noallow!(internal_unstable::unstable()); LL | pass_through_noallow!(internal_unstable::unstable());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -15,7 +15,7 @@ LL | pass_through_noallow!(internal_unstable::unstable());
= help: add `#![feature(function)]` to the crate attributes to enable = help: add `#![feature(function)]` to the crate attributes to enable
error[E0658]: use of unstable library feature 'function' error[E0658]: use of unstable library feature 'function'
--> $DIR/internal-unstable.rs:40:22 --> $DIR/internal-unstable.rs:47:22
| |
LL | println!("{:?}", internal_unstable::unstable()); LL | println!("{:?}", internal_unstable::unstable());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -23,7 +23,7 @@ LL | println!("{:?}", internal_unstable::unstable());
= help: add `#![feature(function)]` to the crate attributes to enable = help: add `#![feature(function)]` to the crate attributes to enable
error[E0658]: use of unstable library feature 'function' error[E0658]: use of unstable library feature 'function'
--> $DIR/internal-unstable.rs:42:10 --> $DIR/internal-unstable.rs:49:10
| |
LL | bar!(internal_unstable::unstable()); LL | bar!(internal_unstable::unstable());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -31,7 +31,7 @@ LL | bar!(internal_unstable::unstable());
= help: add `#![feature(function)]` to the crate attributes to enable = help: add `#![feature(function)]` to the crate attributes to enable
error[E0658]: use of unstable library feature 'function' error[E0658]: use of unstable library feature 'function'
--> $DIR/internal-unstable.rs:12:9 --> $DIR/internal-unstable.rs:19:9
| |
LL | internal_unstable::unstable(); LL | internal_unstable::unstable();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -21,7 +21,9 @@ fn non_macro_expanded_location<#[repr(C)] T>() {
//~^ ERROR `repr` is ambiguous //~^ ERROR `repr` is ambiguous
//~| ERROR attribute should be applied to a struct, enum, or union //~| ERROR attribute should be applied to a struct, enum, or union
match 0u8 { match 0u8 {
#[repr(C)] //~ ERROR `repr` is ambiguous #[repr(C)]
//~^ ERROR `repr` is ambiguous
//~| ERROR attribute should be applied to a struct, enum, or union
_ => {} _ => {}
} }
} }

View File

@ -1,5 +1,5 @@
error[E0425]: cannot find value `NonExistent` in this scope error[E0425]: cannot find value `NonExistent` in this scope
--> $DIR/ambiguous-builtin-attrs.rs:32:5 --> $DIR/ambiguous-builtin-attrs.rs:34:5
| |
LL | NonExistent; LL | NonExistent;
| ^^^^^^^^^^^ not found in this scope | ^^^^^^^^^^^ not found in this scope
@ -61,14 +61,14 @@ LL | use builtin_attrs::*;
= help: use `crate::repr` to refer to this attribute macro unambiguously = help: use `crate::repr` to refer to this attribute macro unambiguously
error[E0659]: `allow` is ambiguous (built-in attribute vs any other name) error[E0659]: `allow` is ambiguous (built-in attribute vs any other name)
--> $DIR/ambiguous-builtin-attrs.rs:36:3 --> $DIR/ambiguous-builtin-attrs.rs:38:3
| |
LL | #[allow(unused)] LL | #[allow(unused)]
| ^^^^^ ambiguous name | ^^^^^ ambiguous name
| |
= note: `allow` could refer to a built-in attribute = note: `allow` could refer to a built-in attribute
note: `allow` could also refer to the built-in attribute imported here note: `allow` could also refer to the built-in attribute imported here
--> $DIR/ambiguous-builtin-attrs.rs:35:5 --> $DIR/ambiguous-builtin-attrs.rs:37:5
| |
LL | use deny as allow; LL | use deny as allow;
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
@ -94,7 +94,16 @@ error[E0517]: attribute should be applied to a struct, enum, or union
LL | fn non_macro_expanded_location<#[repr(C)] T>() { LL | fn non_macro_expanded_location<#[repr(C)] T>() {
| ^ - not a struct, enum, or union | ^ - not a struct, enum, or union
error: aborting due to 8 previous errors error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/ambiguous-builtin-attrs.rs:24:16
|
LL | #[repr(C)]
| ^
...
LL | _ => {}
| ------- not a struct, enum, or union
error: aborting due to 9 previous errors
Some errors have detailed explanations: E0425, E0517, E0659. Some errors have detailed explanations: E0425, E0517, E0659.
For more information about an error, try `rustc --explain E0425`. For more information about an error, try `rustc --explain E0425`.