about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-10-02 19:16:39 +0000
committerbors <bors@rust-lang.org>2015-10-02 19:16:39 +0000
commitef07d7dd40e33d7af95c7b00717503730ce69c11 (patch)
tree5725bfdeb870197fb9efa5b5ef9ca8099d7ba8e5
parente650491f209a4c76dbd31ed1cdc390dd13c3d1e9 (diff)
parent61f5b2b0ca492a7eef9c362efb2108c77eac5bf8 (diff)
downloadrust-ef07d7dd40e33d7af95c7b00717503730ce69c11.tar.gz
rust-ef07d7dd40e33d7af95c7b00717503730ce69c11.zip
Auto merge of #28650 - sanxiyn:attr-usage, r=nrc
This is technically a [breaking-change].

Fix #2809.
Fix #22746.
-rw-r--r--src/librustc/front/check_attr.rs110
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc_driver/driver.rs4
-rw-r--r--src/librustc_front/attr.rs1
-rw-r--r--src/libsyntax/attr.rs1
-rw-r--r--src/test/auxiliary/sepcomp_cci_lib.rs3
-rw-r--r--src/test/auxiliary/xcrate_static_addresses.rs3
-rw-r--r--src/test/compile-fail/attr-usage-inline.rs19
-rw-r--r--src/test/compile-fail/attr-usage-repr.rs41
-rw-r--r--src/test/run-pass/sepcomp-cci.rs12
10 files changed, 182 insertions, 13 deletions
diff --git a/src/librustc/front/check_attr.rs b/src/librustc/front/check_attr.rs
new file mode 100644
index 00000000000..cca14f1fbf2
--- /dev/null
+++ b/src/librustc/front/check_attr.rs
@@ -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);
+}
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 0bbb57afc27..e08dc2acbc0 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -101,6 +101,7 @@ pub mod back {
 }
 
 pub mod front {
+    pub mod check_attr;
     pub mod map;
 }
 
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 8b674f921b5..97fb6c3d26f 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -130,6 +130,10 @@ pub fn compile_input(sess: Session,
                                                                      &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)
         });
diff --git a/src/librustc_front/attr.rs b/src/librustc_front/attr.rs
index 9e1e3c0e293..1a564eb28a3 100644
--- a/src/librustc_front/attr.rs
+++ b/src/librustc_front/attr.rs
@@ -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" => {
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 5fe4220bd99..bd99d33222d 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -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/auxiliary/sepcomp_cci_lib.rs b/src/test/auxiliary/sepcomp_cci_lib.rs
index d62b9871402..c57d161d8f5 100644
--- a/src/test/auxiliary/sepcomp_cci_lib.rs
+++ b/src/test/auxiliary/sepcomp_cci_lib.rs
@@ -13,5 +13,4 @@ pub fn cci_fn() -> usize {
     1200
 }
 
-#[inline]
-pub static CCI_STATIC: usize = 34;
+pub const CCI_CONST: usize = 34;
diff --git a/src/test/auxiliary/xcrate_static_addresses.rs b/src/test/auxiliary/xcrate_static_addresses.rs
index 652f11a71ec..d0da80e31b9 100644
--- a/src/test/auxiliary/xcrate_static_addresses.rs
+++ b/src/test/auxiliary/xcrate_static_addresses.rs
@@ -8,13 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[inline(never)]
 pub static global: isize = 3;
 
-#[inline(never)]
 static global0: isize = 4;
 
-#[inline(never)]
 pub static global2: &'static isize = &global0;
 
 pub fn verify_same(a: &'static isize) {
diff --git a/src/test/compile-fail/attr-usage-inline.rs b/src/test/compile-fail/attr-usage-inline.rs
new file mode 100644
index 00000000000..c6b9b016331
--- /dev/null
+++ b/src/test/compile-fail/attr-usage-inline.rs
@@ -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
index 00000000000..9bad6a8389a
--- /dev/null
+++ b/src/test/compile-fail/attr-usage-repr.rs
@@ -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() {}
diff --git a/src/test/run-pass/sepcomp-cci.rs b/src/test/run-pass/sepcomp-cci.rs
index a1c5ad113c7..d3d3de0e2c0 100644
--- a/src/test/run-pass/sepcomp-cci.rs
+++ b/src/test/run-pass/sepcomp-cci.rs
@@ -16,23 +16,23 @@
 
 
 extern crate sepcomp_cci_lib;
-use sepcomp_cci_lib::{cci_fn, CCI_STATIC};
+use sepcomp_cci_lib::{cci_fn, CCI_CONST};
 
 fn call1() -> usize {
-    cci_fn() + CCI_STATIC
+    cci_fn() + CCI_CONST
 }
 
 mod a {
-    use sepcomp_cci_lib::{cci_fn, CCI_STATIC};
+    use sepcomp_cci_lib::{cci_fn, CCI_CONST};
     pub fn call2() -> usize {
-        cci_fn() + CCI_STATIC
+        cci_fn() + CCI_CONST
     }
 }
 
 mod b {
-    use sepcomp_cci_lib::{cci_fn, CCI_STATIC};
+    use sepcomp_cci_lib::{cci_fn, CCI_CONST};
     pub fn call3() -> usize {
-        cci_fn() + CCI_STATIC
+        cci_fn() + CCI_CONST
     }
 }