mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Auto merge of #80641 - Danue1:patch-1, r=oli-obk
Add visitors for checking #[inline] For #80564
This commit is contained in:
commit
d4e3570db4
@ -38,12 +38,14 @@ pub enum Target {
|
||||
Enum,
|
||||
Variant,
|
||||
Struct,
|
||||
Field,
|
||||
Union,
|
||||
Trait,
|
||||
TraitAlias,
|
||||
Impl,
|
||||
Expression,
|
||||
Statement,
|
||||
Arm,
|
||||
AssocConst,
|
||||
Method(MethodKind),
|
||||
AssocTy,
|
||||
@ -51,6 +53,7 @@ pub enum Target {
|
||||
ForeignStatic,
|
||||
ForeignTy,
|
||||
GenericParam(GenericParamKind),
|
||||
MacroDef,
|
||||
}
|
||||
|
||||
impl Display for Target {
|
||||
@ -73,12 +76,14 @@ impl Display for Target {
|
||||
Target::Enum => "enum",
|
||||
Target::Variant => "enum variant",
|
||||
Target::Struct => "struct",
|
||||
Target::Field => "struct field",
|
||||
Target::Union => "union",
|
||||
Target::Trait => "trait",
|
||||
Target::TraitAlias => "trait alias",
|
||||
Target::Impl => "item",
|
||||
Target::Expression => "expression",
|
||||
Target::Statement => "statement",
|
||||
Target::Arm => "match arm",
|
||||
Target::AssocConst => "associated const",
|
||||
Target::Method(_) => "method",
|
||||
Target::AssocTy => "associated type",
|
||||
@ -90,6 +95,7 @@ impl Display for Target {
|
||||
GenericParamKind::Lifetime => "lifetime parameter",
|
||||
GenericParamKind::Const => "const parameter",
|
||||
},
|
||||
Target::MacroDef => "macro def",
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -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::definitions::{DefKey, DefPath, Definitions};
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::*;
|
||||
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.
|
||||
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))
|
||||
@ -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> {
|
||||
match self.find(id) {
|
||||
Some(Node::Expr(expr)) => expr,
|
||||
@ -821,6 +838,7 @@ impl<'hir> Map<'hir> {
|
||||
Node::GenericParam(param) => param.name.ident().name,
|
||||
Node::Binding(&Pat { kind: PatKind::Binding(_, _, l, _), .. }) => l.name,
|
||||
Node::Ctor(..) => self.name(self.get_parent_item(id)),
|
||||
Node::MacroDef(md) => md.ident.name,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
@ -70,27 +70,27 @@ impl CheckAttrVisitor<'tcx> {
|
||||
is_valid &= if self.tcx.sess.check_name(attr, sym::inline) {
|
||||
self.check_inline(hir_id, attr, span, target)
|
||||
} 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) {
|
||||
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) {
|
||||
self.check_target_feature(hir_id, attr, span, target)
|
||||
} 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) {
|
||||
self.check_doc_attrs(attr, hir_id, target)
|
||||
} 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) {
|
||||
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) {
|
||||
self.check_rustc_args_required_const(&attr, span, target, item)
|
||||
} 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) {
|
||||
self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target)
|
||||
} 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 {
|
||||
// lint-only checks
|
||||
if self.tcx.sess.check_name(attr, sym::cold) {
|
||||
@ -118,6 +118,41 @@ impl CheckAttrVisitor<'tcx> {
|
||||
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.
|
||||
fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
|
||||
match target {
|
||||
@ -150,6 +185,11 @@ impl CheckAttrVisitor<'tcx> {
|
||||
});
|
||||
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!(
|
||||
self.tcx.sess,
|
||||
@ -165,10 +205,18 @@ impl CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
Target::Fn
|
||||
| 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
|
||||
.sess
|
||||
@ -186,6 +234,7 @@ impl CheckAttrVisitor<'tcx> {
|
||||
/// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
|
||||
fn check_track_caller(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
attr_span: &Span,
|
||||
attrs: &'hir [Attribute],
|
||||
span: &Span,
|
||||
@ -203,6 +252,16 @@ impl CheckAttrVisitor<'tcx> {
|
||||
false
|
||||
}
|
||||
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!(
|
||||
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.
|
||||
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 {
|
||||
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!(
|
||||
self.tcx.sess,
|
||||
@ -236,9 +309,17 @@ impl CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
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
|
||||
.sess
|
||||
@ -276,6 +357,14 @@ impl CheckAttrVisitor<'tcx> {
|
||||
});
|
||||
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
|
||||
.sess
|
||||
@ -464,6 +553,13 @@ impl CheckAttrVisitor<'tcx> {
|
||||
fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
|
||||
match target {
|
||||
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
|
||||
// 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) {
|
||||
match target {
|
||||
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
|
||||
// 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.
|
||||
fn check_no_link(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
|
||||
if target == Target::ExternCrate {
|
||||
true
|
||||
} else {
|
||||
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
|
||||
fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
|
||||
match target {
|
||||
Target::ExternCrate => true,
|
||||
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||
// `#[no_link]` 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_link");
|
||||
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.
|
||||
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 {
|
||||
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
|
||||
.sess
|
||||
@ -625,6 +754,13 @@ impl CheckAttrVisitor<'tcx> {
|
||||
fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
|
||||
match target {
|
||||
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
|
||||
// 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) {
|
||||
match target {
|
||||
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
|
||||
// crates used this, so only emit a warning.
|
||||
@ -828,27 +971,46 @@ impl CheckAttrVisitor<'tcx> {
|
||||
/// (Allows proc_macro functions)
|
||||
fn check_allow_internal_unstable(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
attr: &Attribute,
|
||||
span: &Span,
|
||||
target: Target,
|
||||
attrs: &[Attribute],
|
||||
) -> bool {
|
||||
debug!("Checking target: {:?}", target);
|
||||
if target == Target::Fn {
|
||||
for attr in attrs {
|
||||
if self.tcx.sess.is_proc_macro_attr(attr) {
|
||||
debug!("Is proc macro attr");
|
||||
return true;
|
||||
match target {
|
||||
Target::Fn => {
|
||||
for attr in attrs {
|
||||
if self.tcx.sess.is_proc_macro_attr(attr) {
|
||||
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.
|
||||
@ -860,17 +1022,29 @@ impl CheckAttrVisitor<'tcx> {
|
||||
span: &Span,
|
||||
target: Target,
|
||||
) -> bool {
|
||||
if let Target::Fn | Target::Method(_) = target {
|
||||
if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id)) {
|
||||
return true;
|
||||
match target {
|
||||
Target::Fn | Target::Method(_)
|
||||
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)
|
||||
}
|
||||
|
||||
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,
|
||||
¯o_def.attrs,
|
||||
¯o_def.span,
|
||||
Target::MacroDef,
|
||||
None,
|
||||
);
|
||||
intravisit::walk_macro_def(self, macro_def);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
|
||||
let target = Target::from_foreign_item(f_item);
|
||||
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) {
|
||||
tcx.hir()
|
||||
.visit_item_likes_in_module(module_def_id, &mut CheckAttrVisitor { tcx }.as_deep_visitor());
|
||||
let check_attr_visitor = &mut CheckAttrVisitor { tcx };
|
||||
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() {
|
||||
CheckAttrVisitor { tcx }.check_attributes(
|
||||
check_attr_visitor.check_attributes(
|
||||
CRATE_HIR_ID,
|
||||
tcx.hir().krate_attrs(),
|
||||
&DUMMY_SP,
|
||||
|
@ -6,4 +6,20 @@ fn f() {}
|
||||
#[inline] //~ ERROR: attribute should be applied to function or closure
|
||||
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() {}
|
||||
|
@ -6,6 +6,12 @@ LL | #[inline]
|
||||
LL | struct S;
|
||||
| --------- 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`.
|
||||
|
@ -1,10 +1,17 @@
|
||||
// aux-build:internal_unstable.rs
|
||||
|
||||
#![feature(allow_internal_unstable)]
|
||||
#[allow(dead_code)]
|
||||
|
||||
#[macro_use]
|
||||
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 {
|
||||
($e: expr, $f: expr) => {{
|
||||
$e;
|
||||
@ -40,4 +47,10 @@ fn main() {
|
||||
println!("{:?}", 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
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
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());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -7,7 +7,7 @@ LL | pass_through_allow!(internal_unstable::unstable());
|
||||
= help: add `#![feature(function)]` to the crate attributes to enable
|
||||
|
||||
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());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -15,7 +15,7 @@ LL | pass_through_noallow!(internal_unstable::unstable());
|
||||
= help: add `#![feature(function)]` to the crate attributes to enable
|
||||
|
||||
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());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -23,7 +23,7 @@ LL | println!("{:?}", internal_unstable::unstable());
|
||||
= help: add `#![feature(function)]` to the crate attributes to enable
|
||||
|
||||
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());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -31,7 +31,7 @@ LL | bar!(internal_unstable::unstable());
|
||||
= help: add `#![feature(function)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: use of unstable library feature 'function'
|
||||
--> $DIR/internal-unstable.rs:12:9
|
||||
--> $DIR/internal-unstable.rs:19:9
|
||||
|
|
||||
LL | internal_unstable::unstable();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -21,7 +21,9 @@ fn non_macro_expanded_location<#[repr(C)] T>() {
|
||||
//~^ ERROR `repr` is ambiguous
|
||||
//~| ERROR attribute should be applied to a struct, enum, or union
|
||||
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
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
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;
|
||||
| ^^^^^^^^^^^ not found in this scope
|
||||
@ -61,14 +61,14 @@ LL | use builtin_attrs::*;
|
||||
= help: use `crate::repr` to refer to this attribute macro unambiguously
|
||||
|
||||
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)]
|
||||
| ^^^^^ ambiguous name
|
||||
|
|
||||
= note: `allow` could refer to a built-in attribute
|
||||
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;
|
||||
| ^^^^^^^^^^^^^
|
||||
@ -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>() {
|
||||
| ^ - 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.
|
||||
For more information about an error, try `rustc --explain E0425`.
|
||||
|
Loading…
Reference in New Issue
Block a user