impl<'a> CheckAttrVisitor<'a> {
/// Check any attribute.
- fn check_attribute(&self, attr: &ast::Attribute, item: &ast::Item, target: Target) {
- if let Some(name) = attr.name() {
- match &*name.as_str() {
- "inline" => self.check_inline(attr, item, target),
- "repr" => self.check_repr(attr, item, target),
- _ => (),
+ fn check_attributes(&self, item: &ast::Item, target: Target) {
+ for attr in &item.attrs {
+ if let Some(name) = attr.name() {
+ if name == "inline" {
+ self.check_inline(attr, item, target)
+ }
}
}
+ self.check_repr(item, target);
}
/// Check if an `#[inline]` is applied to a function.
}
}
- /// Check if an `#[repr]` attr is valid.
- fn check_repr(&self, attr: &ast::Attribute, item: &ast::Item, target: Target) {
- let words = match attr.meta_item_list() {
- Some(words) => words,
- None => {
- return;
- }
- };
+ /// Check if the `#[repr]` attributes on `item` are valid.
+ fn check_repr(&self, item: &ast::Item, target: Target) {
+ // Extract the names of all repr hints, e.g., [foo, bar, align] for:
+ // ```
+ // #[repr(foo)]
+ // #[repr(bar, align(8))]
+ // ```
+ let hints: Vec<_> = item.attrs
+ .iter()
+ .filter(|attr| match attr.name() {
+ Some(name) => name == "repr",
+ None => false,
+ })
+ .filter_map(|attr| attr.meta_item_list())
+ .flat_map(|hints| hints)
+ .collect();
let mut int_reprs = 0;
let mut is_c = false;
let mut is_simd = false;
- for word in words {
-
- let name = match word.name() {
- Some(word) => word,
- None => continue,
+ for hint in &hints {
+ let name = if let Some(name) = hint.name() {
+ name
+ } else {
+ // Invalid repr hint like repr(42). We don't check for unrecognized hints here
+ // (libsyntax does that), so just ignore it.
+ continue;
};
- let (message, label) = match &*name.as_str() {
+ let (article, allowed_targets) = match &*name.as_str() {
"C" => {
is_c = true;
if target != Target::Struct &&
target != Target::Union &&
target != Target::Enum {
- ("attribute should be applied to struct, enum or union",
- "a struct, enum or union")
+ ("a", "struct, enum or union")
} else {
continue
}
}
"packed" => {
- // Do not increment conflicting_reprs here, because "packed"
- // can be used to modify another repr hint
if target != Target::Struct &&
target != Target::Union {
- ("attribute should be applied to struct or union",
- "a struct or union")
+ ("a", "struct or union")
} else {
continue
}
"simd" => {
is_simd = true;
if target != Target::Struct {
- ("attribute should be applied to struct",
- "a struct")
+ ("a", "struct")
} else {
continue
}
"align" => {
if target != Target::Struct &&
target != Target::Union {
- ("attribute should be applied to struct or union",
- "a struct or union")
+ ("a", "struct or union")
} else {
continue
}
"isize" | "usize" => {
int_reprs += 1;
if target != Target::Enum {
- ("attribute should be applied to enum",
- "an enum")
+ ("an", "enum")
} else {
continue
}
}
_ => continue,
};
- struct_span_err!(self.sess, attr.span, E0517, "{}", message)
- .span_label(item.span, format!("not {}", label))
+ struct_span_err!(self.sess, hint.span, E0517,
+ "attribute should be applied to {}", allowed_targets)
+ .span_label(item.span, format!("not {} {}", article, allowed_targets))
.emit();
}
if (int_reprs > 1)
|| (is_simd && is_c)
|| (int_reprs == 1 && is_c && is_c_like_enum(item)) {
- span_warn!(self.sess, attr.span, E0566,
+ // Just point at all repr hints. This is not ideal, but tracking precisely which ones
+ // are at fault is a huge hassle.
+ let spans: Vec<_> = hints.iter().map(|hint| hint.span).collect();
+ span_warn!(self.sess, spans, E0566,
"conflicting representation hints");
}
}
impl<'a> Visitor<'a> for CheckAttrVisitor<'a> {
fn visit_item(&mut self, item: &'a ast::Item) {
let target = Target::from_item(item);
- for attr in &item.attrs {
- self.check_attribute(attr, item, target);
- }
+ self.check_attributes(item, target);
visit::walk_item(self, item);
}
}
+++ /dev/null
-// 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(attr_literals)]
-#![feature(repr_simd)]
-
-#[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union
-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(align(8))] //~ ERROR: attribute should be applied to struct
-enum EAlign { 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() {}
--- /dev/null
+// 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.
+
+#![feature(attr_literals)]
+#![feature(repr_simd)]
+
+#[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union
+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(align(8))] //~ ERROR: attribute should be applied to struct
+enum EAlign { 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() {}
--- /dev/null
+error[E0517]: attribute should be applied to struct, enum or union
+ --> $DIR/attr-usage-repr.rs:14:8
+ |
+14 | #[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union
+ | ^
+15 | fn f() {}
+ | --------- not a struct, enum or union
+
+error[E0517]: attribute should be applied to enum
+ --> $DIR/attr-usage-repr.rs:26:8
+ |
+26 | #[repr(i8)] //~ ERROR: attribute should be applied to enum
+ | ^^
+27 | struct SInt(f64, f64);
+ | ---------------------- not an enum
+
+error[E0517]: attribute should be applied to struct or union
+ --> $DIR/attr-usage-repr.rs:32:8
+ |
+32 | #[repr(align(8))] //~ ERROR: attribute should be applied to struct
+ | ^^^^^^^^
+33 | enum EAlign { A, B }
+ | -------------------- not a struct or union
+
+error[E0517]: attribute should be applied to struct or union
+ --> $DIR/attr-usage-repr.rs:35:8
+ |
+35 | #[repr(packed)] //~ ERROR: attribute should be applied to struct
+ | ^^^^^^
+36 | enum EPacked { A, B }
+ | --------------------- not a struct or union
+
+error[E0517]: attribute should be applied to struct
+ --> $DIR/attr-usage-repr.rs:38:8
+ |
+38 | #[repr(simd)] //~ ERROR: attribute should be applied to struct
+ | ^^^^
+39 | enum ESimd { A, B }
+ | ------------------- not a struct
+
+error: aborting due to 5 previous errors
+