Change:
I tried to look for this, but I couldn't find an existing issue. Or is this expected behaviour? Putting attributes that exist (though the arguments can be bogus) seem to be ignored when one would expect an error, or at least a warning. E.g like this: or This seems to be the case on stable, beta and nightly. More examples here:
Possibly related to
Turns out this is not related to . This is because  only visits items. This should be a pretty straightforward fix, actually, and wouldn't be a bad introduction to some concepts used in the compiler frontend. I'm willing to mentor this bug if you want to add and
Done!
This bug is caused by the fact that  doesn't visit statements. What does this mean? Attributes can be applied to a lot of things and the parser will accept all of them. However, most attributes don't make sense in a certain context: tells the compiler (which tells LLVM) that a function should be inlined to eliminate call overhead, but that doesn't make sense when applied to a struct, or an enum, or an individual statement in the block. It also doesn't make sense for a function to have a attribute because that is meant to tell the compiler what alignment a type should have or what size an enum's discriminator should be. is the bit that walks the after parsing and points out all the places a given built-in attribute like or doesn't belong. But how do you walk over the AST? You implement the  trait. The trait has provided methods for inspecting every kind of node in the AST (items, functions, statements, expressions, individual identifiers, etc.), so implementors that are only concerned with certain node kinds only have to override those methods. The default implementation just recurses into the subnodes of every node and calls the appropriate trait method for them. The implementation of the recursing lives in the functions; I'm not entirely sure why it's not in the trait methods themselves but I'm sure there's a good reason. The discrepancy in is that it only overrides , so that's all it observes. However, it needs to also override and , look at the attributes on them and generate an error if any of the attributes aren't supposed to be there. You can see the error generation being done , where it emits an error for the attribute being applied to a non-function item. Notice also that it doesn't actually return from there; it keeps walking the tree. This is so we get all the errors out that we can before we stop compiling so the user can fix them all in one fell swoop.
Hey, I should have time to look at this. From the instructions and what I read so far there seems to be a bit of new code that needs to be written to do this? Something similar to but for a and ?
Yeah, all you should have to do is add and on , look at the attributes on or , respectively, and emit an error if they're one of the attribute names checked in the other methods (, , , and any others). I made a mistake in my original assessment and assumed that this code used types from but that's not correct. They look very similar but they're actually defined in . The methods on you would be overriding are defined and . For the attributes are accessible through and for they're just a field . derefs to a slice so you can handle both cases with the same code probably. is the same that's defined in , I recommend just using  which marks it used (otherwise the "unused attribute" lint will fire on it later). And then the final step would be to write a regression test under . These are just single-file tests like you'd find in the folder of a Cargo project, except they're expected to fail compilation with a certain message. You can copy the MIT license header from another file in that directory and just update the copyright year to 2018. Compile-fail tests have comments telling the test suite what error messages to expect for what lines. They would look something like this: The file name for regression tests associated with a certain issue is just , as you might be able to see in that directory, so this would be .
For bonus points, you could add a help message that suggests using or when you encounter on statements and expressions; bonus bonus points if you copy the argument from to the suggested / .
Hey, Maybe I misunderstood something but the two extra functions in that trait don't seem to be used. These are the two extra functions I in the impl Visitor here isn't to interesting so Ill leave it out. I also debug lines to the visititems function. I do see those being printed out. I am not seeing either of the debug lines from the two new functions. My test program is
Ah, you have to change the return value of in that impl block. The trait won't recurse into function bodies unless you tell it to and give it a way to resolve them.
Cool. I'm moving forward again heh. I guess that makes sense then. I was seeing as an item I think, but I guess that allows it to actually look inside Thanks
Hey so I pushed a commit on my own fork. I wasn't sure if its ready for a pull request but feedback on the code i think could be helpful just in case I did anything incredibly wrong heh. I wasn't sure what the best way to share a commit would be. If there's a better or more preferred way let me know.
I've left a couple of comments but you can probably go ahead and open a pull request, it'll start running tests on it. It also makes it easier to review. I don't have review permissions so add to get a reviewer who knows the frontend and mention me.
Cool. Thanks a lot. I'll address your comments and open a pull request

Discussion:
//! conflicts between multiple such attributes attached to the same //! item. <ins> use syntax_pos::Span; </ins> use ty::TyCtxt; use hir;

Enum, Const, ForeignMod, <ins> Expression, Statement, </ins> Other, }

let mut has_wasm_import_module = false; for attr in &item.attrs { if attr.check_name("inline") { <del> self.check_inline(attr, item, target) </del> <ins> self.check_inline(attr, &item.span, target) </ins> } else if attr.check_name("wasm_import_module") { has_wasm_import_module = true; if attr.value_str().is_none() {

} /// Check if an `#[inline]` is applied to a function. <del> fn check_inline(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) { </del> <ins> fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) { </ins> if target != Target::Fn { struct_span_err!(self.tcx.sess, attr.span, E0518, "attribute should be applied to function") <del> .span_label(item.span, "not a function") </del> <ins> .span_label(*span, "not a function") </ins> .emit(); } }

} _ => continue, }; <del> struct_span_err!(self.tcx.sess, hint.span, E0517, "attribute should be applied to {}", allowed_targets) .span_label(item.span, format!("not {} {}", article, allowed_targets)) .emit(); </del> <ins> self.emit_repr_error( hint.span, item.span, &format!("attribute should be applied to {}", allowed_targets), &format!("not {} {}", article, allowed_targets), ) </ins> } // Just point at all repr hints if there are any incompatibilities.

"conflicting representation hints"); } } <ins> fn emit_repr_error( &self, hint_span: Span, label_span: Span, hint_message: &str, label_message: &str, ) { struct_span_err!(self.tcx.sess, hint_span, E0517, "{}", hint_message) .span_label(label_span, label_message) .emit(); } fn check_stmt_attributes(&self, stmt: &hir::Stmt) { // When checking statements ignore expressions, they will be checked later if let hir::Stmt_::StmtDecl(_, _) = stmt.node { for attr in stmt.node.attrs() { if attr.check_name("inline") { self.check_inline(attr, &stmt.span, Target::Statement); } if attr.check_name("repr") { self.emit_repr_error( attr.span, stmt.span, &format!("attribute should not be applied to a statement"), &format!("not a struct, enum or union"), ); } } } } fn check_expr_attributes(&self, expr: &hir::Expr) { for attr in expr.attrs.iter() { if attr.check_name("inline") { self.check_inline(attr, &expr.span, Target::Expression); } if attr.check_name("repr") { self.emit_repr_error( attr.span, expr.span, &format!("attribute should not be applied to an expression"), &format!("not defining a struct, enum or union"), ); } } } </ins> } impl<'a, 'tcx> Visitor<'tcx> for CheckAttrVisitor<'a, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { <del> NestedVisitorMap::None </del> <ins> NestedVisitorMap::OnlyBodies(&self.tcx.hir) </ins> } fn visit_item(&mut self, item: &'tcx hir::Item) { let target = Target::from_item(item); self.check_attributes(item, target); <del> intravisit::walk_item(self, item); </del> <ins> intravisit::walk_item(self, item) } fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) { self.check_stmt_attributes(stmt); intravisit::walk_stmt(self, stmt) } fn visit_expr(&mut self, expr: &'tcx hir::Expr) { self.check_expr_attributes(expr); intravisit::walk_expr(self, expr) </ins> } }

<ins> // Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(stmt_expr_attributes)] fn main() { #[inline] let _a = 4; //~^^ ERROR attribute should be applied to function #[inline(XYZ)] let _b = 4; //~^^ ERROR attribute should be applied to function #[repr(nothing)] let _x = 0; //~^^ ERROR attribute should not be applied to a statement #[repr(something_not_real)] loop { () }; //~^^^^ ERROR attribute should not be applied to an expression #[repr] let _y = "123"; //~^^ ERROR attribute should not be applied to a statement fn foo() {} #[inline(ABC)] foo(); //~^^ ERROR attribute should be applied to function let _z = #[repr] 1; //~^ ERROR attribute should not be applied to an expression } </ins>