Skip to content

Commit 816c1b1

Browse files
committed
Check for known but incorrect attributes
- Change nested_visit_map so it will recusively 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 isssue #43988
1 parent c08480f commit 816c1b1

File tree

2 files changed

+118
-9
lines changed

2 files changed

+118
-9
lines changed

src/librustc/hir/check_attr.rs

+82-9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//! conflicts between multiple such attributes attached to the same
1515
//! item.
1616
17+
use syntax_pos::Span;
1718
use ty::TyCtxt;
1819

1920
use hir;
@@ -27,6 +28,8 @@ enum Target {
2728
Enum,
2829
Const,
2930
ForeignMod,
31+
Expression,
32+
Statement,
3033
Other,
3134
}
3235

@@ -62,7 +65,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
6265
let mut has_wasm_import_module = false;
6366
for attr in &item.attrs {
6467
if attr.check_name("inline") {
65-
self.check_inline(attr, item, target)
68+
self.check_inline(attr, &item.span, target)
6669
} else if attr.check_name("wasm_import_module") {
6770
has_wasm_import_module = true;
6871
if attr.value_str().is_none() {
@@ -99,13 +102,13 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
99102
}
100103

101104
/// Check if an `#[inline]` is applied to a function.
102-
fn check_inline(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) {
105+
fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) {
103106
if target != Target::Fn {
104107
struct_span_err!(self.tcx.sess,
105108
attr.span,
106109
E0518,
107110
"attribute should be applied to function")
108-
.span_label(item.span, "not a function")
111+
.span_label(*span, "not a function")
109112
.emit();
110113
}
111114
}
@@ -196,10 +199,12 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
196199
}
197200
_ => continue,
198201
};
199-
struct_span_err!(self.tcx.sess, hint.span, E0517,
200-
"attribute should be applied to {}", allowed_targets)
201-
.span_label(item.span, format!("not {} {}", article, allowed_targets))
202-
.emit();
202+
self.emit_repr_error(
203+
hint.span,
204+
item.span,
205+
&format!("attribute should be applied to {}", allowed_targets),
206+
&format!("not {} {}", article, allowed_targets),
207+
)
203208
}
204209

205210
// Just point at all repr hints if there are any incompatibilities.
@@ -221,17 +226,85 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
221226
"conflicting representation hints");
222227
}
223228
}
229+
230+
fn emit_repr_error(
231+
&self,
232+
hint_span: Span,
233+
label_span: Span,
234+
hint_message: &str,
235+
label_message: &str,
236+
) {
237+
struct_span_err!(self.tcx.sess, hint_span, E0517, "{}", hint_message)
238+
.span_label(label_span, label_message)
239+
.emit();
240+
}
241+
242+
fn check_stmt_attributes(&self, stmt: &hir::Stmt) {
243+
// When checking statements ignore expressions, they will be checked later
244+
if let hir::Stmt_::StmtDecl(_, _) = stmt.node {
245+
for attr in stmt.node.attrs() {
246+
if attr.check_name("inline") {
247+
self.check_inline(attr, &stmt.span, Target::Statement);
248+
}
249+
if attr.check_name("repr") {
250+
self.emit_repr_error(
251+
attr.span,
252+
stmt.span,
253+
&format!("attribute should not be applied to statements"),
254+
&format!("not a struct, enum or union"),
255+
);
256+
}
257+
}
258+
}
259+
}
260+
261+
fn check_expr_attributes(&self, expr: &hir::Expr) {
262+
use hir::Expr_::*;
263+
match expr.node {
264+
// Assignments, Calls and Structs were handled by Items and Statements
265+
ExprCall(..) |
266+
ExprAssign(..) |
267+
ExprMethodCall(..) |
268+
ExprStruct(..) => return,
269+
_ => (),
270+
}
271+
272+
for attr in expr.attrs.iter() {
273+
if attr.check_name("inline") {
274+
self.check_inline(attr, &expr.span, Target::Expression);
275+
}
276+
if attr.check_name("repr") {
277+
self.emit_repr_error(
278+
attr.span,
279+
expr.span,
280+
&format!("attribute should not be applied to an expression"),
281+
&format!("not a struct, enum or union"),
282+
);
283+
}
284+
}
285+
}
224286
}
225287

226288
impl<'a, 'tcx> Visitor<'tcx> for CheckAttrVisitor<'a, 'tcx> {
227289
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
228-
NestedVisitorMap::None
290+
NestedVisitorMap::OnlyBodies(&self.tcx.hir)
229291
}
230292

231293
fn visit_item(&mut self, item: &'tcx hir::Item) {
232294
let target = Target::from_item(item);
233295
self.check_attributes(item, target);
234-
intravisit::walk_item(self, item);
296+
intravisit::walk_item(self, item)
297+
}
298+
299+
300+
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) {
301+
self.check_stmt_attributes(stmt);
302+
intravisit::walk_stmt(self, stmt)
303+
}
304+
305+
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
306+
self.check_expr_attributes(expr);
307+
intravisit::walk_expr(self, expr)
235308
}
236309
}
237310

src/test/compile-fail/issue-43988.rs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
13+
#[inline]
14+
let _a = 4;
15+
//~^^ ERROR attribute should be applied to function
16+
17+
18+
#[inline(XYZ)]
19+
let _b = 4;
20+
//~^^ ERROR attribute should be applied to function
21+
22+
#[repr(nothing)]
23+
let _x = 0;
24+
//~^^ ERROR attribute should not be applied to statements
25+
26+
27+
#[repr(something_not_real)]
28+
loop {
29+
()
30+
};
31+
//~^^^^ ERROR attribute should not be applied to an expression
32+
33+
#[repr]
34+
let _y = "123";
35+
//~^^ ERROR attribute should not be applied to statements
36+
}

0 commit comments

Comments
 (0)