diff options
| author | bors <bors@rust-lang.org> | 2018-03-29 03:13:11 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-03-29 03:13:11 +0000 |
| commit | 361509320c882ee76f0d1359f842dec4637e6b08 (patch) | |
| tree | f59e2b02538aa004064c90cc0e69962f5c859357 | |
| parent | 1e652bda20eb7a781fbec19b8c581b8dc0bb8a8d (diff) | |
| parent | 4957a40d13a78e0f9f1208cc0528663c49f24386 (diff) | |
Auto merge of #49291 - tejom:check-for-known-but-incorrect-attributes, r=petrochenkov
Check for known but incorrect attributes fixes #43988 - Change nested_visit_map so it will recursively check functions - Add visit_stmt and visit_expr for impl Visitor for CheckAttrVisitor and check for incorrect inline and repr attributes on staements and expressions - Add regression test for issue #43988
| -rw-r--r-- | src/librustc/hir/check_attr.rs | 81 | ||||
| -rw-r--r-- | src/test/compile-fail/issue-43988.rs | 48 |
2 files changed, 120 insertions, 9 deletions
diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 9b2647ad4db..316ed07ca05 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -14,6 +14,7 @@ //! conflicts between multiple such attributes attached to the same //! item. +use syntax_pos::Span; use ty::TyCtxt; use hir; @@ -27,6 +28,8 @@ enum Target { Enum, Const, ForeignMod, + Expression, + Statement, Other, } @@ -62,7 +65,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { let mut has_wasm_import_module = false; for attr in &item.attrs { if attr.check_name("inline") { - self.check_inline(attr, item, target) + self.check_inline(attr, &item.span, target) } else if attr.check_name("wasm_import_module") { has_wasm_import_module = true; if attr.value_str().is_none() { @@ -99,13 +102,13 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { } /// Check if an `#[inline]` is applied to a function. - fn check_inline(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) { + fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) { if target != Target::Fn { struct_span_err!(self.tcx.sess, attr.span, E0518, "attribute should be applied to function") - .span_label(item.span, "not a function") + .span_label(*span, "not a function") .emit(); } } @@ -196,10 +199,12 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { } _ => continue, }; - 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(); + self.emit_repr_error( + hint.span, + item.span, + &format!("attribute should be applied to {}", allowed_targets), + &format!("not {} {}", article, allowed_targets), + ) } // Just point at all repr hints if there are any incompatibilities. @@ -221,17 +226,75 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { "conflicting representation hints"); } } + + 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"), + ); + } + } + } } impl<'a, 'tcx> Visitor<'tcx> for CheckAttrVisitor<'a, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::None + NestedVisitorMap::OnlyBodies(&self.tcx.hir) } fn visit_item(&mut self, item: &'tcx hir::Item) { let target = Target::from_item(item); self.check_attributes(item, target); - intravisit::walk_item(self, item); + 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) } } diff --git a/src/test/compile-fail/issue-43988.rs b/src/test/compile-fail/issue-43988.rs new file mode 100644 index 00000000000..ff1fdaef416 --- /dev/null +++ b/src/test/compile-fail/issue-43988.rs @@ -0,0 +1,48 @@ +// 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 + +} |
