Skip to content

Commit 4efe97a

Browse files
committed
Check placement of more attributes
1 parent de921ab commit 4efe97a

18 files changed

+816
-354
lines changed

compiler/rustc_passes/src/check_attr.rs

Lines changed: 105 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ impl CheckAttrVisitor<'tcx> {
7171
self.check_track_caller(&attr.span, attrs, span, target)
7272
} else if self.tcx.sess.check_name(attr, sym::doc) {
7373
self.check_doc_alias(attr, hir_id, target)
74+
} else if self.tcx.sess.check_name(attr, sym::cold) {
75+
self.check_cold(&attr, span, target)
76+
} else if self.tcx.sess.check_name(attr, sym::link_name) {
77+
self.check_link_name(&attr, span, target)
78+
} else if self.tcx.sess.check_name(attr, sym::no_link) {
79+
self.check_no_link(&attr, span, target)
80+
} else if self.tcx.sess.check_name(attr, sym::export_name) {
81+
self.check_export_name(&attr, span, target)
82+
} else if self.tcx.sess.check_name(attr, sym::link_section) {
83+
self.check_link_section(&attr, span, target)
7484
} else {
7585
true
7686
};
@@ -277,6 +287,99 @@ impl CheckAttrVisitor<'tcx> {
277287
true
278288
}
279289

290+
/// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid.
291+
fn check_cold(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
292+
match target {
293+
Target::Fn | Target::Method(..) | Target::ForeignFn => true,
294+
_ => {
295+
self.tcx
296+
.sess
297+
.struct_span_err(attr.span, "attribute should be applied to a function")
298+
.span_label(*span, "not a function")
299+
.emit();
300+
false
301+
}
302+
}
303+
}
304+
305+
/// Checks if `#[link_name]` is applied to an item other than a foreign function or static. Returns `true` if valid.
306+
fn check_link_name(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
307+
if target == Target::ForeignFn || target == Target::ForeignStatic {
308+
true
309+
} else {
310+
let mut err = self.tcx.sess.struct_span_err(
311+
attr.span,
312+
"attribute should be applied to a foreign function or static",
313+
);
314+
err.span_label(*span, "not a foreign function or static");
315+
316+
// See issue #47725
317+
if target == Target::ForeignMod {
318+
if let Some(value) = attr.value_str() {
319+
err.span_help(
320+
attr.span,
321+
&format!(r#"try `#[link(name = "{}")]` instead"#, value),
322+
);
323+
} else {
324+
err.span_help(attr.span, r#"try `#[link(name = "...")]` instead"#);
325+
}
326+
}
327+
328+
err.emit();
329+
false
330+
}
331+
}
332+
333+
/// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid.
334+
fn check_no_link(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
335+
if target == Target::ExternCrate {
336+
true
337+
} else {
338+
self.tcx
339+
.sess
340+
.struct_span_err(attr.span, "attribute should be applied to an `extern crate` item")
341+
.span_label(*span, "not an `extern crate` item")
342+
.emit();
343+
false
344+
}
345+
}
346+
347+
/// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid.
348+
fn check_export_name(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
349+
match target {
350+
Target::Static | Target::Fn | Target::Method(..) => true,
351+
_ => {
352+
self.tcx
353+
.sess
354+
.struct_span_err(
355+
attr.span,
356+
"attribute should be applied to a function or static",
357+
)
358+
.span_label(*span, "not a function or static")
359+
.emit();
360+
false
361+
}
362+
}
363+
}
364+
365+
/// Checks if `#[link_section]` is applied to a function or static. Returns `true` if valid.
366+
fn check_link_section(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
367+
match target {
368+
Target::Static | Target::Fn | Target::Method(..) => true,
369+
_ => {
370+
self.tcx
371+
.sess
372+
.struct_span_err(
373+
attr.span,
374+
"attribute should be applied to a function or static",
375+
)
376+
.span_label(*span, "not a function or static")
377+
.emit();
378+
false
379+
}
380+
}
381+
}
382+
280383
/// Checks if the `#[repr]` attributes on `item` are valid.
281384
fn check_repr(
282385
&self,
@@ -421,10 +524,8 @@ impl CheckAttrVisitor<'tcx> {
421524
fn check_stmt_attributes(&self, stmt: &hir::Stmt<'_>) {
422525
// When checking statements ignore expressions, they will be checked later
423526
if let hir::StmtKind::Local(ref l) = stmt.kind {
527+
self.check_attributes(l.hir_id, &l.attrs, &stmt.span, Target::Statement, None);
424528
for attr in l.attrs.iter() {
425-
if self.tcx.sess.check_name(attr, sym::inline) {
426-
self.check_inline(l.hir_id, attr, &stmt.span, Target::Statement);
427-
}
428529
if self.tcx.sess.check_name(attr, sym::repr) {
429530
self.emit_repr_error(
430531
attr.span,
@@ -442,10 +543,8 @@ impl CheckAttrVisitor<'tcx> {
442543
hir::ExprKind::Closure(..) => Target::Closure,
443544
_ => Target::Expression,
444545
};
546+
self.check_attributes(expr.hir_id, &expr.attrs, &expr.span, target, None);
445547
for attr in expr.attrs.iter() {
446-
if self.tcx.sess.check_name(attr, sym::inline) {
447-
self.check_inline(expr.hir_id, attr, &expr.span, target);
448-
}
449548
if self.tcx.sess.check_name(attr, sym::repr) {
450549
self.emit_repr_error(
451550
attr.span,

compiler/rustc_typeck/src/collect.rs

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2490,10 +2490,17 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
24902490
codegen_fn_attrs.export_name = Some(s);
24912491
}
24922492
} else if tcx.sess.check_name(attr, sym::target_feature) {
2493-
if !tcx.features().target_feature_11 {
2494-
check_target_feature_safe_fn(tcx, id, attr.span);
2495-
} else if let Some(local_id) = id.as_local() {
2496-
if tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal {
2493+
if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal {
2494+
if !tcx.features().target_feature_11 {
2495+
let mut err = feature_err(
2496+
&tcx.sess.parse_sess,
2497+
sym::target_feature_11,
2498+
attr.span,
2499+
"`#[target_feature(..)]` can only be applied to `unsafe` functions",
2500+
);
2501+
err.span_label(tcx.def_span(id), "not an `unsafe` function");
2502+
err.emit();
2503+
} else if let Some(local_id) = id.as_local() {
24972504
check_target_feature_trait_unsafe(tcx, local_id, attr.span);
24982505
}
24992506
}
@@ -2750,21 +2757,6 @@ fn check_link_name_xor_ordinal(
27502757
}
27512758
}
27522759

2753-
/// Checks the function annotated with `#[target_feature]` is unsafe,
2754-
/// reporting an error if it isn't.
2755-
fn check_target_feature_safe_fn(tcx: TyCtxt<'_>, id: DefId, attr_span: Span) {
2756-
if tcx.is_closure(id) || tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal {
2757-
let mut err = feature_err(
2758-
&tcx.sess.parse_sess,
2759-
sym::target_feature_11,
2760-
attr_span,
2761-
"`#[target_feature(..)]` can only be applied to `unsafe` functions",
2762-
);
2763-
err.span_label(tcx.def_span(id), "not an `unsafe` function");
2764-
err.emit();
2765-
}
2766-
}
2767-
27682760
/// Checks the function annotated with `#[target_feature]` is not a safe
27692761
/// trait method implementation, reporting an error if it is.
27702762
fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {

src/test/ui/check-static-recursion-foreign.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ extern crate libc;
1515

1616
use libc::c_int;
1717

18-
#[link_name = "check_static_recursion_foreign_helper"]
18+
#[link(name = "check_static_recursion_foreign_helper")]
1919
extern "C" {
2020
#[allow(dead_code)]
2121
static test_static: c_int;
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
// This is testing whether various builtin attributes signals an
2+
// error or warning when put in "weird" places.
3+
//
4+
// (This file sits on its own because it actually signals an error,
5+
// which would mess up the treatment of other cases in
6+
// issue-43106-gating-of-builtin-attrs.rs)
7+
8+
// ignore-tidy-linelength
9+
10+
// Crate-level is accepted, though it is almost certainly unused?
11+
#![inline]
12+
13+
#[inline]
14+
//~^ ERROR attribute should be applied to function or closure
15+
mod inline {
16+
//~^ NOTE not a function or closure
17+
18+
mod inner { #![inline] }
19+
//~^ ERROR attribute should be applied to function or closure
20+
//~| NOTE not a function or closure
21+
22+
#[inline = "2100"] fn f() { }
23+
//~^ ERROR attribute must be of the form
24+
//~| WARN this was previously accepted
25+
//~| NOTE #[deny(ill_formed_attribute_input)]` on by default
26+
//~| NOTE for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
27+
28+
#[inline] struct S;
29+
//~^ ERROR attribute should be applied to function or closure
30+
//~| NOTE not a function or closure
31+
32+
#[inline] type T = S;
33+
//~^ ERROR attribute should be applied to function or closure
34+
//~| NOTE not a function or closure
35+
36+
#[inline] impl S { }
37+
//~^ ERROR attribute should be applied to function or closure
38+
//~| NOTE not a function or closure
39+
}
40+
41+
#[no_link]
42+
//~^ ERROR attribute should be applied to an `extern crate` item
43+
mod no_link {
44+
//~^ NOTE not an `extern crate` item
45+
46+
mod inner { #![no_link] }
47+
//~^ ERROR attribute should be applied to an `extern crate` item
48+
//~| NOTE not an `extern crate` item
49+
50+
#[no_link] fn f() { }
51+
//~^ ERROR attribute should be applied to an `extern crate` item
52+
//~| NOTE not an `extern crate` item
53+
54+
#[no_link] struct S;
55+
//~^ ERROR attribute should be applied to an `extern crate` item
56+
//~| NOTE not an `extern crate` item
57+
58+
#[no_link]type T = S;
59+
//~^ ERROR attribute should be applied to an `extern crate` item
60+
//~| NOTE not an `extern crate` item
61+
62+
#[no_link] impl S { }
63+
//~^ ERROR attribute should be applied to an `extern crate` item
64+
//~| NOTE not an `extern crate` item
65+
}
66+
67+
#[cold]
68+
//~^ ERROR attribute should be applied to a function
69+
mod cold {
70+
//~^ NOTE not a function
71+
72+
mod inner { #![cold] }
73+
//~^ ERROR attribute should be applied to a function
74+
//~| NOTE not a function
75+
76+
#[cold] fn f() { }
77+
78+
#[cold] struct S;
79+
//~^ ERROR attribute should be applied to a function
80+
//~| NOTE not a function
81+
82+
#[cold] type T = S;
83+
//~^ ERROR attribute should be applied to a function
84+
//~| NOTE not a function
85+
86+
#[cold] impl S { }
87+
//~^ ERROR attribute should be applied to a function
88+
//~| NOTE not a function
89+
}
90+
91+
#[export_name = "2200"]
92+
//~^ ERROR attribute should be applied to a function or static
93+
mod export_name {
94+
//~^ NOTE not a function or static
95+
96+
mod inner { #![export_name="2200"] }
97+
//~^ ERROR attribute should be applied to a function or static
98+
//~| NOTE not a function or static
99+
100+
#[export_name = "2200"] fn f() { }
101+
102+
#[export_name = "2200"] struct S;
103+
//~^ ERROR attribute should be applied to a function or static
104+
//~| NOTE not a function or static
105+
106+
#[export_name = "2200"] type T = S;
107+
//~^ ERROR attribute should be applied to a function or static
108+
//~| NOTE not a function or static
109+
110+
#[export_name = "2200"] impl S { }
111+
//~^ ERROR attribute should be applied to a function or static
112+
//~| NOTE not a function or static
113+
}
114+
115+
#[link_name = "1900"]
116+
//~^ ERROR attribute should be applied to a foreign function or static
117+
mod link_name {
118+
//~^ NOTE not a foreign function or static
119+
120+
#[link_name = "1900"]
121+
//~^ ERROR attribute should be applied to a foreign function or static
122+
//~| HELP try `#[link(name = "1900")]` instead
123+
extern { }
124+
//~^ NOTE not a foreign function or static
125+
126+
mod inner { #![link_name="1900"] }
127+
//~^ ERROR attribute should be applied to a foreign function or static
128+
//~| NOTE not a foreign function or static
129+
130+
#[link_name = "1900"] fn f() { }
131+
//~^ ERROR attribute should be applied to a foreign function or static
132+
//~| NOTE not a foreign function or static
133+
134+
#[link_name = "1900"] struct S;
135+
//~^ ERROR attribute should be applied to a foreign function or static
136+
//~| NOTE not a foreign function or static
137+
138+
#[link_name = "1900"] type T = S;
139+
//~^ ERROR attribute should be applied to a foreign function or static
140+
//~| NOTE not a foreign function or static
141+
142+
#[link_name = "1900"] impl S { }
143+
//~^ ERROR attribute should be applied to a foreign function or static
144+
//~| NOTE not a foreign function or static
145+
}
146+
147+
#[link_section = "1800"]
148+
//~^ ERROR attribute should be applied to a function or static
149+
mod link_section {
150+
//~^ NOTE not a function or static
151+
152+
mod inner { #![link_section="1800"] }
153+
//~^ ERROR attribute should be applied to a function or static
154+
//~| NOTE not a function or static
155+
156+
#[link_section = "1800"] fn f() { }
157+
158+
#[link_section = "1800"] struct S;
159+
//~^ ERROR attribute should be applied to a function or static
160+
//~| NOTE not a function or static
161+
162+
#[link_section = "1800"] type T = S;
163+
//~^ ERROR attribute should be applied to a function or static
164+
//~| NOTE not a function or static
165+
166+
#[link_section = "1800"] impl S { }
167+
//~^ ERROR attribute should be applied to a function or static
168+
//~| NOTE not a function or static
169+
}
170+
171+
fn main() {}

0 commit comments

Comments
 (0)