diff --git a/src/librustc/front/check_attr.rs b/src/librustc/front/check_attr.rs new file mode 100644 index 0000000000000..cca14f1fbf2a3 --- /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 or the MIT license +// , 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 0bbb57afc278e..e08dc2acbc088 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 d004d557856b7..fdc522e330f18 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -129,6 +129,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 9e1e3c0e293ac..1a564eb28a3a0 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 5fe4220bd99ba..bd99d33222db1 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/compile-fail/attr-usage-inline.rs b/src/test/compile-fail/attr-usage-inline.rs new file mode 100644 index 0000000000000..c6b9b016331aa --- /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 or the MIT license +// , 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 0000000000000..9bad6a8389a5d --- /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 or the MIT license +// , 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() {}