Skip to content

Commit a3b3782

Browse files
committed
Consolidate checking for attributes not compatible with #[naked]
Currently #[inline] and #[track_caller] are incompatible with #[naked], and there are more such attributes on the way. In preparation for this, consolidate the existing checks into a central location so that they can all be handled together. In addition, clean up the wording of the existing error messages.
1 parent 93d9578 commit a3b3782

File tree

10 files changed

+113
-127
lines changed

10 files changed

+113
-127
lines changed
Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
1-
`#[track_caller]` and `#[naked]` cannot both be applied to the same function.
1+
Functions marked with the `#[naked]` attribute are restricted in what other
2+
code generation attributes they may be marked with.
3+
4+
The following code generation attributes are incompatible with `#[naked]`:
5+
6+
* `#[inline]`
7+
* `#[track_caller]`
28

39
Erroneous code example:
410

511
```compile_fail,E0736
12+
#[inline]
613
#[naked]
7-
#[track_caller]
814
fn foo() {}
915
```
1016

11-
This is primarily due to ABI incompatibilities between the two attributes.
12-
See [RFC 2091] for details on this and other limitations.
17+
These incompatibilities are due to the fact that naked functions impose
18+
deliberately strict restrictions regarding the code that the compiler is
19+
allowed to produce for this function.
20+
21+
See [the reference page for codegen attributes] for more information.
1322

14-
[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
23+
[the reference page for codegen attributes]: https://doc.rust-lang.org/reference/attributes/codegen.html

compiler/rustc_error_codes/src/error_codes/E0739.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
`#[track_caller]` can not be applied on struct.
1+
`#[track_caller]` must be applied to a function.
22

33
Erroneous code example:
44

compiler/rustc_passes/src/check_attr.rs

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -80,51 +80,49 @@ impl CheckAttrVisitor<'_> {
8080
self.check_rustc_must_implement_one_of(attr, span, target)
8181
}
8282
sym::target_feature => self.check_target_feature(hir_id, attr, span, target),
83-
sym::track_caller => {
84-
self.check_track_caller(hir_id, attr.span, attrs, span, target)
85-
}
83+
sym::track_caller => self.check_track_caller(hir_id, attr, span, target),
8684
sym::doc => self.check_doc_attrs(
8785
attr,
8886
hir_id,
8987
target,
9088
&mut specified_inline,
9189
&mut doc_aliases,
9290
),
93-
sym::no_link => self.check_no_link(hir_id, &attr, span, target),
94-
sym::export_name => self.check_export_name(hir_id, &attr, span, target),
91+
sym::no_link => self.check_no_link(hir_id, attr, span, target),
92+
sym::export_name => self.check_export_name(hir_id, attr, span, target),
9593
sym::rustc_layout_scalar_valid_range_start
9694
| sym::rustc_layout_scalar_valid_range_end => {
97-
self.check_rustc_layout_scalar_valid_range(&attr, span, target)
95+
self.check_rustc_layout_scalar_valid_range(attr, span, target)
9896
}
9997
sym::allow_internal_unstable => {
100-
self.check_allow_internal_unstable(hir_id, &attr, span, target, &attrs)
98+
self.check_allow_internal_unstable(hir_id, attr, span, target, attrs)
10199
}
102100
sym::rustc_allow_const_fn_unstable => {
103-
self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target)
101+
self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target)
104102
}
105-
sym::naked => self.check_naked(hir_id, attr, span, target),
103+
sym::naked => self.check_naked(hir_id, attr, span, target, attrs),
106104
sym::rustc_legacy_const_generics => {
107-
self.check_rustc_legacy_const_generics(&attr, span, target, item)
105+
self.check_rustc_legacy_const_generics(attr, span, target, item)
108106
}
109107
sym::rustc_lint_query_instability => {
110-
self.check_rustc_lint_query_instability(&attr, span, target)
108+
self.check_rustc_lint_query_instability(attr, span, target)
111109
}
112110
sym::rustc_clean
113111
| sym::rustc_dirty
114112
| sym::rustc_if_this_changed
115-
| sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(&attr),
113+
| sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(attr),
116114
sym::cmse_nonsecure_entry => self.check_cmse_nonsecure_entry(attr, span, target),
117115
sym::default_method_body_is_const => {
118116
self.check_default_method_body_is_const(attr, span, target)
119117
}
120-
sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
121-
sym::must_use => self.check_must_use(hir_id, &attr, span, target),
122-
sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target),
118+
sym::must_not_suspend => self.check_must_not_suspend(attr, span, target),
119+
sym::must_use => self.check_must_use(hir_id, attr, span, target),
120+
sym::rustc_pass_by_value => self.check_pass_by_value(attr, span, target),
123121
sym::rustc_const_unstable
124122
| sym::rustc_const_stable
125123
| sym::unstable
126124
| sym::stable
127-
| sym::rustc_promotable => self.check_stability_promotable(&attr, span, target),
125+
| sym::rustc_promotable => self.check_stability_promotable(attr, span, target),
128126
_ => true,
129127
};
130128
is_valid &= attr_is_valid;
@@ -338,7 +336,27 @@ impl CheckAttrVisitor<'_> {
338336
}
339337

340338
/// Checks if `#[naked]` is applied to a function definition.
341-
fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
339+
fn check_naked(
340+
&self,
341+
hir_id: HirId,
342+
attr: &Attribute,
343+
span: Span,
344+
target: Target,
345+
attrs: &[Attribute],
346+
) -> bool {
347+
for any_attr in attrs {
348+
if any_attr.has_name(sym::track_caller) || any_attr.has_name(sym::inline) {
349+
struct_span_err!(
350+
self.tcx.sess,
351+
any_attr.span,
352+
E0736,
353+
"cannot use additional code generation attributes with `#[naked]`",
354+
)
355+
.emit();
356+
return false;
357+
}
358+
}
359+
342360
match target {
343361
Target::Fn
344362
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
@@ -383,41 +401,28 @@ impl CheckAttrVisitor<'_> {
383401
}
384402
}
385403

386-
/// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
404+
/// Checks if a `#[track_caller]` is applied to a function. Returns `true` if valid.
387405
fn check_track_caller(
388406
&self,
389407
hir_id: HirId,
390-
attr_span: Span,
391-
attrs: &[Attribute],
408+
attr: &Attribute,
392409
span: Span,
393410
target: Target,
394411
) -> bool {
395412
match target {
396-
_ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => {
397-
struct_span_err!(
398-
self.tcx.sess,
399-
attr_span,
400-
E0736,
401-
"cannot use `#[track_caller]` with `#[naked]`",
402-
)
403-
.emit();
404-
false
405-
}
406413
Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true,
407414
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
408415
// `#[track_caller]` attribute with just a lint, because we previously
409416
// erroneously allowed it and some crates used it accidentally, to to be compatible
410417
// with crates depending on them, we can't throw an error here.
411418
Target::Field | Target::Arm | Target::MacroDef => {
412-
for attr in attrs {
413-
self.inline_attr_str_error_with_macro_def(hir_id, attr, "track_caller");
414-
}
419+
self.inline_attr_str_error_with_macro_def(hir_id, attr, "track_caller");
415420
true
416421
}
417422
_ => {
418423
struct_span_err!(
419424
self.tcx.sess,
420-
attr_span,
425+
attr.span,
421426
E0739,
422427
"attribute should be applied to function"
423428
)

compiler/rustc_passes/src/naked_functions.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Checks validity of naked functions.
22
3-
use rustc_ast::{Attribute, InlineAsmOptions};
3+
use rustc_ast::InlineAsmOptions;
44
use rustc_errors::struct_span_err;
55
use rustc_hir as hir;
66
use rustc_hir::def_id::LocalDefId;
@@ -65,18 +65,10 @@ impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
6565
check_no_patterns(self.tcx, body.params);
6666
check_no_parameters_use(self.tcx, body);
6767
check_asm(self.tcx, body, span);
68-
check_inline(self.tcx, attrs);
6968
}
7069
}
7170
}
7271

73-
/// Check that the function isn't inlined.
74-
fn check_inline(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
75-
for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) {
76-
tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
77-
}
78-
}
79-
8072
/// Checks that function uses non-Rust ABI.
8173
fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) {
8274
if abi == Abi::Rust {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// needs-asm-support
2+
3+
#![feature(naked_functions)]
4+
#![crate_type = "lib"]
5+
6+
use std::arch::asm;
7+
8+
#[naked]
9+
pub unsafe extern "C" fn inline_none() {
10+
asm!("", options(noreturn));
11+
}
12+
13+
#[naked]
14+
#[inline]
15+
//~^ ERROR cannot use additional code generation attributes with `#[naked]`
16+
pub unsafe extern "C" fn inline_hint() {
17+
asm!("", options(noreturn));
18+
}
19+
20+
#[naked]
21+
#[inline(always)]
22+
//~^ ERROR cannot use additional code generation attributes with `#[naked]`
23+
pub unsafe extern "C" fn inline_always() {
24+
asm!("", options(noreturn));
25+
}
26+
27+
#[naked]
28+
#[inline(never)]
29+
//~^ ERROR cannot use additional code generation attributes with `#[naked]`
30+
pub unsafe extern "C" fn inline_never() {
31+
asm!("", options(noreturn));
32+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0736]: cannot use additional code generation attributes with `#[naked]`
2+
--> $DIR/naked-functions-inline.rs:14:1
3+
|
4+
LL | #[inline]
5+
| ^^^^^^^^^
6+
7+
error[E0736]: cannot use additional code generation attributes with `#[naked]`
8+
--> $DIR/naked-functions-inline.rs:21:1
9+
|
10+
LL | #[inline(always)]
11+
| ^^^^^^^^^^^^^^^^^
12+
13+
error[E0736]: cannot use additional code generation attributes with `#[naked]`
14+
--> $DIR/naked-functions-inline.rs:28:1
15+
|
16+
LL | #[inline(never)]
17+
| ^^^^^^^^^^^^^^^^
18+
19+
error: aborting due to 3 previous errors
20+
21+
For more information about this error, try `rustc --explain E0736`.

src/test/ui/asm/naked-functions.rs

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -160,40 +160,3 @@ pub unsafe extern "C" fn valid_c() {
160160
pub unsafe extern "C" fn valid_att_syntax() {
161161
asm!("", options(noreturn, att_syntax));
162162
}
163-
164-
#[naked]
165-
pub unsafe extern "C" fn inline_none() {
166-
asm!("", options(noreturn));
167-
}
168-
169-
#[naked]
170-
#[inline]
171-
//~^ ERROR naked functions cannot be inlined
172-
pub unsafe extern "C" fn inline_hint() {
173-
asm!("", options(noreturn));
174-
}
175-
176-
#[naked]
177-
#[inline(always)]
178-
//~^ ERROR naked functions cannot be inlined
179-
pub unsafe extern "C" fn inline_always() {
180-
asm!("", options(noreturn));
181-
}
182-
183-
#[naked]
184-
#[inline(never)]
185-
//~^ ERROR naked functions cannot be inlined
186-
pub unsafe extern "C" fn inline_never() {
187-
asm!("", options(noreturn));
188-
}
189-
190-
#[naked]
191-
#[inline]
192-
//~^ ERROR naked functions cannot be inlined
193-
#[inline(always)]
194-
//~^ ERROR naked functions cannot be inlined
195-
#[inline(never)]
196-
//~^ ERROR naked functions cannot be inlined
197-
pub unsafe extern "C" fn inline_all() {
198-
asm!("", options(noreturn));
199-
}

src/test/ui/asm/naked-functions.stderr

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -219,42 +219,6 @@ warning: Rust ABI is unsupported in naked functions
219219
LL | pub unsafe fn rust_abi() {
220220
| ^^^^^^^^
221221

222-
error: naked functions cannot be inlined
223-
--> $DIR/naked-functions.rs:170:1
224-
|
225-
LL | #[inline]
226-
| ^^^^^^^^^
227-
228-
error: naked functions cannot be inlined
229-
--> $DIR/naked-functions.rs:177:1
230-
|
231-
LL | #[inline(always)]
232-
| ^^^^^^^^^^^^^^^^^
233-
234-
error: naked functions cannot be inlined
235-
--> $DIR/naked-functions.rs:184:1
236-
|
237-
LL | #[inline(never)]
238-
| ^^^^^^^^^^^^^^^^
239-
240-
error: naked functions cannot be inlined
241-
--> $DIR/naked-functions.rs:191:1
242-
|
243-
LL | #[inline]
244-
| ^^^^^^^^^
245-
246-
error: naked functions cannot be inlined
247-
--> $DIR/naked-functions.rs:193:1
248-
|
249-
LL | #[inline(always)]
250-
| ^^^^^^^^^^^^^^^^^
251-
252-
error: naked functions cannot be inlined
253-
--> $DIR/naked-functions.rs:195:1
254-
|
255-
LL | #[inline(never)]
256-
| ^^^^^^^^^^^^^^^^
257-
258-
error: aborting due to 30 previous errors; 2 warnings emitted
222+
error: aborting due to 24 previous errors; 2 warnings emitted
259223

260224
For more information about this error, try `rustc --explain E0787`.

src/test/ui/rfc-2091-track-caller/error-with-naked.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use std::arch::asm;
55

6-
#[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]`
6+
#[track_caller] //~ ERROR cannot use additional code generation attributes with `#[naked]`
77
#[naked]
88
extern "C" fn f() {
99
asm!("", options(noreturn));
@@ -12,7 +12,7 @@ extern "C" fn f() {
1212
struct S;
1313

1414
impl S {
15-
#[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]`
15+
#[track_caller] //~ ERROR cannot use additional code generation attributes with `#[naked]`
1616
#[naked]
1717
extern "C" fn g() {
1818
asm!("", options(noreturn));

src/test/ui/rfc-2091-track-caller/error-with-naked.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error[E0736]: cannot use `#[track_caller]` with `#[naked]`
1+
error[E0736]: cannot use additional code generation attributes with `#[naked]`
22
--> $DIR/error-with-naked.rs:6:1
33
|
44
LL | #[track_caller]
55
| ^^^^^^^^^^^^^^^
66

7-
error[E0736]: cannot use `#[track_caller]` with `#[naked]`
7+
error[E0736]: cannot use additional code generation attributes with `#[naked]`
88
--> $DIR/error-with-naked.rs:15:5
99
|
1010
LL | #[track_caller]

0 commit comments

Comments
 (0)