Skip to content

Commit a8f64c0

Browse files
authored
Rollup merge of #93153 - tmiasko:reject-unsupported-naked-functions, r=Amanieu
Reject unsupported naked functions Transition unsupported naked functions future incompatibility lint into an error: * Naked functions must contain a single inline assembly block. Introduced as future incompatibility lint in 1.50 #79653. Change into an error fixes a soundness issue described in #32489. * Naked functions must not use any forms of inline attribute. Introduced as future incompatibility lint in 1.56 #87652. Closes #32490. Closes #32489. r? ```@Amanieu``` ```@npmccallum``` ```@joshtriplett```
2 parents 5fd9c05 + beeba4b commit a8f64c0

File tree

9 files changed

+183
-283
lines changed

9 files changed

+183
-283
lines changed

compiler/rustc_error_codes/src/error_codes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ E0783: include_str!("./error_codes/E0783.md"),
486486
E0784: include_str!("./error_codes/E0784.md"),
487487
E0785: include_str!("./error_codes/E0785.md"),
488488
E0786: include_str!("./error_codes/E0786.md"),
489+
E0787: include_str!("./error_codes/E0787.md"),
489490
;
490491
// E0006, // merged with E0005
491492
// E0008, // cannot bind by-move into a pattern guard
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
An unsupported naked function definition.
2+
3+
Erroneous code example:
4+
5+
```compile_fail,E0787
6+
#![feature(naked_functions)]
7+
8+
#[naked]
9+
pub extern "C" fn f() -> u32 {
10+
42
11+
}
12+
```
13+
14+
The naked functions must be defined using a single inline assembly
15+
block.
16+
17+
The execution must never fall through past the end of the assembly
18+
code so the block must use `noreturn` option. The asm block can also
19+
use `att_syntax` and `raw` options, but others options are not allowed.
20+
21+
The asm block must not contain any operands other than `const` and
22+
`sym`.
23+
24+
### Additional information
25+
26+
For more information, please see [RFC 2972].
27+
28+
[RFC 2972]: https://github.com./rust-lang/rfcs/blob/master/text/2972-constrained-naked.md

compiler/rustc_lint/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,11 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
481481
<https://github.com./rust-lang/rust/issues/59014> for more information",
482482
);
483483
store.register_removed("plugin_as_library", "plugins have been deprecated and retired");
484+
store.register_removed(
485+
"unsupported_naked_functions",
486+
"converted into hard error, see RFC 2972 \
487+
<https://github.com./rust-lang/rfcs/blob/master/text/2972-constrained-naked.md> for more information",
488+
);
484489
}
485490

486491
fn register_internals(store: &mut LintStore) {

compiler/rustc_lint_defs/src/builtin.rs

-47
Original file line numberDiff line numberDiff line change
@@ -2759,52 +2759,6 @@ declare_lint! {
27592759
"undefined naked function ABI"
27602760
}
27612761

2762-
declare_lint! {
2763-
/// The `unsupported_naked_functions` lint detects naked function
2764-
/// definitions that are unsupported but were previously accepted.
2765-
///
2766-
/// ### Example
2767-
///
2768-
/// ```rust
2769-
/// #![feature(naked_functions)]
2770-
///
2771-
/// #[naked]
2772-
/// pub extern "C" fn f() -> u32 {
2773-
/// 42
2774-
/// }
2775-
/// ```
2776-
///
2777-
/// {{produces}}
2778-
///
2779-
/// ### Explanation
2780-
///
2781-
/// The naked functions must be defined using a single inline assembly
2782-
/// block.
2783-
///
2784-
/// The execution must never fall through past the end of the assembly
2785-
/// code so the block must use `noreturn` option. The asm block can also
2786-
/// use `att_syntax` option, but other options are not allowed.
2787-
///
2788-
/// The asm block must not contain any operands other than `const` and
2789-
/// `sym`. Additionally, naked function should specify a non-Rust ABI.
2790-
///
2791-
/// Naked functions cannot be inlined. All forms of the `inline` attribute
2792-
/// are prohibited.
2793-
///
2794-
/// While other definitions of naked functions were previously accepted,
2795-
/// they are unsupported and might not work reliably. This is a
2796-
/// [future-incompatible] lint that will transition into hard error in
2797-
/// the future.
2798-
///
2799-
/// [future-incompatible]: ../index.md#future-incompatible-lints
2800-
pub UNSUPPORTED_NAKED_FUNCTIONS,
2801-
Warn,
2802-
"unsupported naked function definitions",
2803-
@future_incompatible = FutureIncompatibleInfo {
2804-
reference: "issue #32408 <https://github.com./rust-lang/rust/issues/32408>",
2805-
};
2806-
}
2807-
28082762
declare_lint! {
28092763
/// The `ineffective_unstable_trait_impl` lint detects `#[unstable]` attributes which are not used.
28102764
///
@@ -3070,7 +3024,6 @@ declare_lint_pass! {
30703024
UNINHABITED_STATIC,
30713025
FUNCTION_ITEM_REFERENCES,
30723026
USELESS_DEPRECATED,
3073-
UNSUPPORTED_NAKED_FUNCTIONS,
30743027
MISSING_ABI,
30753028
INVALID_DOC_ATTRIBUTES,
30763029
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,

compiler/rustc_passes/src/naked_functions.rs

+47-45
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
//! Checks validity of naked functions.
22
33
use rustc_ast::{Attribute, InlineAsmOptions};
4+
use rustc_errors::struct_span_err;
45
use rustc_hir as hir;
56
use rustc_hir::def_id::LocalDefId;
67
use rustc_hir::intravisit::{FnKind, Visitor};
78
use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind};
89
use rustc_middle::ty::query::Providers;
910
use rustc_middle::ty::TyCtxt;
1011
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
11-
use rustc_session::lint::builtin::UNSUPPORTED_NAKED_FUNCTIONS;
1212
use rustc_span::symbol::sym;
1313
use rustc_span::Span;
1414
use rustc_target::spec::abi::Abi;
@@ -64,18 +64,16 @@ impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
6464
check_abi(self.tcx, hir_id, fn_header.abi, ident_span);
6565
check_no_patterns(self.tcx, body.params);
6666
check_no_parameters_use(self.tcx, body);
67-
check_asm(self.tcx, hir_id, body, span);
68-
check_inline(self.tcx, hir_id, attrs);
67+
check_asm(self.tcx, body, span);
68+
check_inline(self.tcx, attrs);
6969
}
7070
}
7171
}
7272

7373
/// Check that the function isn't inlined.
74-
fn check_inline(tcx: TyCtxt<'_>, hir_id: HirId, attrs: &[Attribute]) {
74+
fn check_inline(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
7575
for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) {
76-
tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, attr.span, |lint| {
77-
lint.build("naked functions cannot be inlined").emit();
78-
});
76+
tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
7977
}
8078
}
8179

@@ -146,31 +144,31 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
146144
}
147145

148146
/// Checks that function body contains a single inline assembly block.
149-
fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
147+
fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
150148
let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
151149
this.visit_body(body);
152150
if let [(ItemKind::Asm, _)] = this.items[..] {
153151
// Ok.
154152
} else {
155-
tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_span, |lint| {
156-
let mut diag = lint.build("naked functions must contain a single asm block");
157-
let mut has_asm = false;
158-
for &(kind, span) in &this.items {
159-
match kind {
160-
ItemKind::Asm if has_asm => {
161-
diag.span_label(
162-
span,
163-
"multiple asm blocks are unsupported in naked functions",
164-
);
165-
}
166-
ItemKind::Asm => has_asm = true,
167-
ItemKind::NonAsm => {
168-
diag.span_label(span, "non-asm is unsupported in naked functions");
169-
}
153+
let mut diag = struct_span_err!(
154+
tcx.sess,
155+
fn_span,
156+
E0787,
157+
"naked functions must contain a single asm block"
158+
);
159+
let mut has_asm = false;
160+
for &(kind, span) in &this.items {
161+
match kind {
162+
ItemKind::Asm if has_asm => {
163+
diag.span_label(span, "multiple asm blocks are unsupported in naked functions");
164+
}
165+
ItemKind::Asm => has_asm = true,
166+
ItemKind::NonAsm => {
167+
diag.span_label(span, "non-asm is unsupported in naked functions");
170168
}
171169
}
172-
diag.emit();
173-
});
170+
}
171+
diag.emit();
174172
}
175173
}
176174

@@ -221,7 +219,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
221219

222220
ExprKind::InlineAsm(ref asm) => {
223221
self.items.push((ItemKind::Asm, span));
224-
self.check_inline_asm(expr.hir_id, asm, span);
222+
self.check_inline_asm(asm, span);
225223
}
226224

227225
ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => {
@@ -230,7 +228,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
230228
}
231229
}
232230

233-
fn check_inline_asm(&self, hir_id: HirId, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) {
231+
fn check_inline_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) {
234232
let unsupported_operands: Vec<Span> = asm
235233
.operands
236234
.iter()
@@ -243,18 +241,17 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
243241
})
244242
.collect();
245243
if !unsupported_operands.is_empty() {
246-
self.tcx.struct_span_lint_hir(
247-
UNSUPPORTED_NAKED_FUNCTIONS,
248-
hir_id,
244+
struct_span_err!(
245+
self.tcx.sess,
249246
unsupported_operands,
250-
|lint| {
251-
lint.build("only `const` and `sym` operands are supported in naked functions")
252-
.emit();
253-
},
254-
);
247+
E0787,
248+
"only `const` and `sym` operands are supported in naked functions",
249+
)
250+
.emit();
255251
}
256252

257253
let unsupported_options: Vec<&'static str> = [
254+
(InlineAsmOptions::MAY_UNWIND, "`may_unwind`"),
258255
(InlineAsmOptions::NOMEM, "`nomem`"),
259256
(InlineAsmOptions::NOSTACK, "`nostack`"),
260257
(InlineAsmOptions::PRESERVES_FLAGS, "`preserves_flags`"),
@@ -266,19 +263,24 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
266263
.collect();
267264

268265
if !unsupported_options.is_empty() {
269-
self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| {
270-
lint.build(&format!(
271-
"asm options unsupported in naked functions: {}",
272-
unsupported_options.join(", ")
273-
))
274-
.emit();
275-
});
266+
struct_span_err!(
267+
self.tcx.sess,
268+
span,
269+
E0787,
270+
"asm options unsupported in naked functions: {}",
271+
unsupported_options.join(", ")
272+
)
273+
.emit();
276274
}
277275

278276
if !asm.options.contains(InlineAsmOptions::NORETURN) {
279-
self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| {
280-
lint.build("asm in naked functions must use `noreturn` option").emit();
281-
});
277+
struct_span_err!(
278+
self.tcx.sess,
279+
span,
280+
E0787,
281+
"asm in naked functions must use `noreturn` option"
282+
)
283+
.emit();
282284
}
283285
}
284286
}

src/test/codegen/naked-functions.rs

+15-25
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,32 @@
11
// compile-flags: -C no-prepopulate-passes
2+
// needs-asm-support
3+
// only-x86_64
24

35
#![crate_type = "lib"]
46
#![feature(naked_functions)]
7+
use std::arch::asm;
58

69
// CHECK: Function Attrs: naked
710
// CHECK-NEXT: define{{.*}}void @naked_empty()
811
#[no_mangle]
912
#[naked]
10-
pub fn naked_empty() {
13+
pub unsafe extern "C" fn naked_empty() {
1114
// CHECK-NEXT: {{.+}}:
12-
// CHECK-NEXT: ret void
15+
// CHECK-NEXT: call void asm
16+
// CHECK-NEXT: unreachable
17+
asm!("ret",
18+
options(noreturn));
1319
}
1420

1521
// CHECK: Function Attrs: naked
22+
// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i64 %a, i64 %b)
1623
#[no_mangle]
1724
#[naked]
18-
// CHECK-NEXT: define{{.*}}void @naked_with_args(i{{[0-9]+( %a)?}})
19-
pub fn naked_with_args(a: isize) {
25+
pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
2026
// CHECK-NEXT: {{.+}}:
21-
// CHECK: ret void
22-
}
23-
24-
// CHECK: Function Attrs: naked
25-
// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_return()
26-
#[no_mangle]
27-
#[naked]
28-
pub fn naked_with_return() -> isize {
29-
// CHECK-NEXT: {{.+}}:
30-
// CHECK-NEXT: ret i{{[0-9]+}} 0
31-
0
32-
}
33-
34-
// CHECK: Function Attrs: naked
35-
// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+( %a)?}})
36-
#[no_mangle]
37-
#[naked]
38-
pub fn naked_with_args_and_return(a: isize) -> isize {
39-
// CHECK-NEXT: {{.+}}:
40-
// CHECK: ret i{{[0-9]+}} 0
41-
0
27+
// CHECK-NEXT: call void asm
28+
// CHECK-NEXT: unreachable
29+
asm!("lea rax, [rdi + rsi]",
30+
"ret",
31+
options(noreturn));
4232
}

src/test/codegen/naked-noinline.rs

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
use std::arch::asm;
99

10-
#[inline(always)]
1110
#[naked]
1211
#[no_mangle]
1312
pub unsafe extern "C" fn f() {

0 commit comments

Comments
 (0)