about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-03-29 03:13:11 +0000
committerbors <bors@rust-lang.org>2018-03-29 03:13:11 +0000
commit361509320c882ee76f0d1359f842dec4637e6b08 (patch)
treef59e2b02538aa004064c90cc0e69962f5c859357
parent1e652bda20eb7a781fbec19b8c581b8dc0bb8a8d (diff)
parent4957a40d13a78e0f9f1208cc0528663c49f24386 (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.rs81
-rw-r--r--src/test/compile-fail/issue-43988.rs48
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
+
+}