Skip to content

check_attr doesn't check every HIR node type that can carry attributes. #80048

Description

@eddyb

The check_attr visitor here is missing several methods:

impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
NestedVisitorMap::OnlyBodies(self.tcx.hir())
}
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
let target = Target::from_item(item);
self.check_attributes(
item.hir_id,
item.attrs,
&item.span,
target,
Some(ItemLike::Item(item)),
);
intravisit::walk_item(self, item)
}
fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) {
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 ForeignItem<'tcx>) {
let target = Target::from_foreign_item(f_item);
self.check_attributes(
f_item.hir_id,
&f_item.attrs,
&f_item.span,
target,
Some(ItemLike::ForeignItem(f_item)),
);
intravisit::walk_foreign_item(self, f_item)
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
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<'tcx>) {
// When checking statements ignore expressions, they will be checked later.
if let hir::StmtKind::Local(ref l) = stmt.kind {
self.check_attributes(l.hir_id, &l.attrs, &stmt.span, Target::Statement, None);
}
intravisit::walk_stmt(self, stmt)
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
let target = match expr.kind {
hir::ExprKind::Closure(..) => Target::Closure,
_ => Target::Expression,
};
self.check_attributes(expr.hir_id, &expr.attrs, &expr.span, target, None);
intravisit::walk_expr(self, expr)
}
fn visit_variant(
&mut self,
variant: &'tcx hir::Variant<'tcx>,
generics: &'tcx hir::Generics<'tcx>,
item_id: HirId,
) {
self.check_attributes(variant.id, variant.attrs, &variant.span, Target::Variant, None);
intravisit::walk_variant(self, variant, generics, item_id)
}
}

A quick search (for attrs:) in the HIR definition finds these additional types that can contain attributes (they're also missing from the hir::Target enum, which should probably be renamed to AttrTarget but that's besides the point):

(click to see definition code snippets)

(summary: GenericParam, MacroDef, Arm, Param, StructField)

This isn't necessary a bug for some of them, as there is special validation elsewhere, e.g.:

"allow, cfg, cfg_attr, deny, \
forbid, and warn are the only allowed built-in attributes in function parameters",

But it's not as uniform and future-proof as it could be. It might even be worth having a contextual attribute Target, and handling all attributes on visit_attr, or a hybrid solution that ICEs when visit_attr comes across an attribute not already handled.

And I did end up finding at least one bug, this compiles without any warnings (try on playground):

fn main() {
    match 5 {
        #[inline] _ => {}
    }
}

cc @varkor @davidtwco @petrochenkov

Activity

  1. added
    A-attributesArea: Attributes (`#[…]`, `#![…]`)
    C-bugCategory: This is a bug.
    on Dec 15, 2020
  2. rylev commented on Jan 7, 2021

    @rylev
    Contributor

    @rustbot claim

  3. added a commit that references this issue on Feb 14, 2021
  4. eddyb commented on Mar 2, 2021

    @eddyb
    ContributorAuthor

    After #80641 and #80920, what's left? cc @oli-obk

  5. oli-obk commented on Mar 2, 2021

    @oli-obk
    Contributor

    Looked over those PRs, yea, this is fixed now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-attributesArea: Attributes (`#[…]`, `#![…]`)C-bugCategory: This is a bug.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions