Skip to content

Commit 3615093

Browse files
committed
Auto merge of #49291 - tejom:check-for-known-but-incorrect-attributes, r=petrochenkov
Check for known but incorrect attributes fixes #43988 - Change nested_visit_map so it will recursively 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 issue #43988
2 parents 1e652bd + 4957a40 commit 3615093

File tree

2 files changed

+120
-9
lines changed

2 files changed

+120
-9
lines changed

Diff for: src/librustc/hir/check_attr.rs

+72-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,75 @@ 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 a statement"),
254+
&format!("not a struct, enum or union"),
255+
);
256+
}
257+
}
258+
}
259+
}
260+
261+
fn check_expr_attributes(&self, expr: &hir::Expr) {
262+
for attr in expr.attrs.iter() {
263+
if attr.check_name("inline") {
264+
self.check_inline(attr, &expr.span, Target::Expression);
265+
}
266+
if attr.check_name("repr") {
267+
self.emit_repr_error(
268+
attr.span,
269+
expr.span,
270+
&format!("attribute should not be applied to an expression"),
271+
&format!("not defining a struct, enum or union"),
272+
);
273+
}
274+
}
275+
}
224276
}
225277

226278
impl<'a, 'tcx> Visitor<'tcx> for CheckAttrVisitor<'a, 'tcx> {
227279
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
228-
NestedVisitorMap::None
280+
NestedVisitorMap::OnlyBodies(&self.tcx.hir)
229281
}
230282

231283
fn visit_item(&mut self, item: &'tcx hir::Item) {
232284
let target = Target::from_item(item);
233285
self.check_attributes(item, target);
234-
intravisit::walk_item(self, item);
286+
intravisit::walk_item(self, item)
287+
}
288+
289+
290+
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) {
291+
self.check_stmt_attributes(stmt);
292+
intravisit::walk_stmt(self, stmt)
293+
}
294+
295+
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
296+
self.check_expr_attributes(expr);
297+
intravisit::walk_expr(self, expr)
235298
}
236299
}
237300

Diff for: src/test/compile-fail/issue-43988.rs

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
#![feature(stmt_expr_attributes)]
12+
13+
fn main() {
14+
15+
#[inline]
16+
let _a = 4;
17+
//~^^ ERROR attribute should be applied to function
18+
19+
20+
#[inline(XYZ)]
21+
let _b = 4;
22+
//~^^ ERROR attribute should be applied to function
23+
24+
#[repr(nothing)]
25+
let _x = 0;
26+
//~^^ ERROR attribute should not be applied to a statement
27+
28+
#[repr(something_not_real)]
29+
loop {
30+
()
31+
};
32+
//~^^^^ ERROR attribute should not be applied to an expression
33+
34+
#[repr]
35+
let _y = "123";
36+
//~^^ ERROR attribute should not be applied to a statement
37+
38+
39+
fn foo() {}
40+
41+
#[inline(ABC)]
42+
foo();
43+
//~^^ ERROR attribute should be applied to function
44+
45+
let _z = #[repr] 1;
46+
//~^ ERROR attribute should not be applied to an expression
47+
48+
}

0 commit comments

Comments
 (0)