]> git.lizzy.rs Git - rust.git/commitdiff
Check attribute usage
authorSeo Sanghyeon <sanxiyn@gmail.com>
Fri, 25 Sep 2015 06:25:59 +0000 (15:25 +0900)
committerSeo Sanghyeon <sanxiyn@gmail.com>
Fri, 2 Oct 2015 15:01:49 +0000 (00:01 +0900)
src/librustc/front/check_attr.rs [new file with mode: 0644]
src/librustc/lib.rs
src/librustc_driver/driver.rs
src/librustc_front/attr.rs
src/libsyntax/attr.rs
src/test/compile-fail/attr-usage-inline.rs [new file with mode: 0644]
src/test/compile-fail/attr-usage-repr.rs [new file with mode: 0644]

diff --git a/src/librustc/front/check_attr.rs b/src/librustc/front/check_attr.rs
new file mode 100644 (file)
index 0000000..cca14f1
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright 2015 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.
+
+use session::Session;
+
+use syntax::ast;
+use syntax::attr::AttrMetaMethods;
+use syntax::visit;
+use syntax::visit::Visitor;
+
+#[derive(Copy, Clone, PartialEq)]
+enum Target {
+    Fn,
+    Struct,
+    Enum,
+    Other,
+}
+
+impl Target {
+    fn from_item(item: &ast::Item) -> Target {
+        match item.node {
+            ast::ItemFn(..) => Target::Fn,
+            ast::ItemStruct(..) => Target::Struct,
+            ast::ItemEnum(..) => Target::Enum,
+            _ => Target::Other,
+        }
+    }
+}
+
+struct CheckAttrVisitor<'a> {
+    sess: &'a Session,
+}
+
+impl<'a> CheckAttrVisitor<'a> {
+    fn check_inline(&self, attr: &ast::Attribute, target: Target) {
+        if target != Target::Fn {
+            self.sess.span_err(
+                attr.span,
+                "attribute should be applied to function");
+        }
+    }
+
+    fn check_repr(&self, attr: &ast::Attribute, target: Target) {
+        let words = match attr.meta_item_list() {
+            Some(words) => words,
+            None => {
+                return;
+            }
+        };
+        for word in words {
+            let word: &str = &word.name();
+            match word {
+                "C" => {
+                    if target != Target::Struct && target != Target::Enum {
+                        self.sess.span_err(
+                            attr.span,
+                            "attribute should be applied to struct or enum");
+                    }
+                }
+                "packed" |
+                "simd" => {
+                    if target != Target::Struct {
+                        self.sess.span_err(
+                            attr.span,
+                            "attribute should be applied to struct");
+                    }
+                }
+                "i8" | "u8" | "i16" | "u16" |
+                "i32" | "u32" | "i64" | "u64" |
+                "isize" | "usize" => {
+                    if target != Target::Enum {
+                        self.sess.span_err(
+                            attr.span,
+                            "attribute should be applied to enum");
+                    }
+                }
+                _ => (),
+            }
+        }
+    }
+
+    fn check_attribute(&self, attr: &ast::Attribute, target: Target) {
+        let name: &str = &attr.name();
+        match name {
+            "inline" => self.check_inline(attr, target),
+            "repr" => self.check_repr(attr, target),
+            _ => (),
+        }
+    }
+}
+
+impl<'a, 'v> Visitor<'v> for CheckAttrVisitor<'a> {
+    fn visit_item(&mut self, item: &ast::Item) {
+        let target = Target::from_item(item);
+        for attr in &item.attrs {
+            self.check_attribute(attr, target);
+        }
+    }
+}
+
+pub fn check_crate(sess: &Session, krate: &ast::Crate) {
+    visit::walk_crate(&mut CheckAttrVisitor { sess: sess }, krate);
+}
index 0bbb57afc278e0604e4e658787ef02ee3e7d4dcc..e08dc2acbc0885e61712286ba2af9454cee3c18a 100644 (file)
@@ -101,6 +101,7 @@ pub mod back {
 }
 
 pub mod front {
+    pub mod check_attr;
     pub mod map;
 }
 
index d004d557856b7e3c124d66e12f0d716a61fe5f36..fdc522e330f18ac716f74adfc66dbe74d5b9518f 100644 (file)
@@ -129,6 +129,10 @@ macro_rules! controller_entry_point{($point: ident, $tsess: expr, $make_state: e
                                                                      &ast_map.krate(),
                                                                      &id[..]));
 
+        time(sess.time_passes(), "attribute checking", || {
+            front::check_attr::check_crate(&sess, &expanded_crate);
+        });
+
         time(sess.time_passes(), "early lint checks", || {
             lint::check_ast_crate(&sess, &expanded_crate)
         });
index 9e1e3c0e293ac1ed44bd7b8dce01b7f8a2a9f2f8..1a564eb28a3a039874bde3aacff131ac1d33dfed 100644 (file)
@@ -300,7 +300,6 @@ pub enum InlineAttr {
 
 /// Determine what `#[inline]` attribute is present in `attrs`, if any.
 pub fn find_inline_attr(diagnostic: Option<&SpanHandler>, attrs: &[Attribute]) -> InlineAttr {
-    // FIXME (#2809)---validate the usage of #[inline] and #[inline]
     attrs.iter().fold(InlineAttr::None, |ia,attr| {
         match attr.node.value.node {
             MetaWord(ref n) if *n == "inline" => {
index 5fe4220bd99ba5b13340a94b8a97897f054bfffb..bd99d33222db1ab4a25747e1cef1718b0f0d59bb 100644 (file)
@@ -323,7 +323,6 @@ pub enum InlineAttr {
 
 /// Determine what `#[inline]` attribute is present in `attrs`, if any.
 pub fn find_inline_attr(diagnostic: Option<&SpanHandler>, attrs: &[Attribute]) -> InlineAttr {
-    // FIXME (#2809)---validate the usage of #[inline] and #[inline]
     attrs.iter().fold(InlineAttr::None, |ia,attr| {
         match attr.node.value.node {
             MetaWord(ref n) if *n == "inline" => {
diff --git a/src/test/compile-fail/attr-usage-inline.rs b/src/test/compile-fail/attr-usage-inline.rs
new file mode 100644 (file)
index 0000000..c6b9b01
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2015 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.
+
+#![allow(dead_code)]
+
+#[inline]
+fn f() {}
+
+#[inline] //~ ERROR: attribute should be applied to function
+struct S;
+
+fn main() {}
diff --git a/src/test/compile-fail/attr-usage-repr.rs b/src/test/compile-fail/attr-usage-repr.rs
new file mode 100644 (file)
index 0000000..9bad6a8
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2015 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.
+
+#![allow(dead_code)]
+#![feature(repr_simd)]
+
+#[repr(C)] //~ ERROR: attribute should be applied to struct or enum
+fn f() {}
+
+#[repr(C)]
+struct SExtern(f64, f64);
+
+#[repr(packed)]
+struct SPacked(f64, f64);
+
+#[repr(simd)]
+struct SSimd(f64, f64);
+
+#[repr(i8)] //~ ERROR: attribute should be applied to enum
+struct SInt(f64, f64);
+
+#[repr(C)]
+enum EExtern { A, B }
+
+#[repr(packed)] //~ ERROR: attribute should be applied to struct
+enum EPacked { A, B }
+
+#[repr(simd)] //~ ERROR: attribute should be applied to struct
+enum ESimd { A, B }
+
+#[repr(i8)]
+enum EInt { A, B }
+
+fn main() {}