Skip to content

Commit 8afa22d

Browse files
committed
Never inline naked functions
The `#[naked]` attribute disabled prologue / epilogue emission for the function and it is responsibility of a developer to provide them. The compiler is no position to inline such functions correctly. Disable inlining of naked functions at LLVM and MIR level.
1 parent 675f114 commit 8afa22d

File tree

4 files changed

+44
-4
lines changed

4 files changed

+44
-4
lines changed

compiler/rustc_attr/src/builtin.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
6767
}
6868
}
6969

70-
#[derive(Clone, PartialEq, Encodable, Decodable)]
70+
#[derive(Copy, Clone, PartialEq, Encodable, Decodable)]
7171
pub enum InlineAttr {
7272
None,
7373
Hint,

compiler/rustc_codegen_llvm/src/attributes.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::value::Value;
2525

2626
/// Mark LLVM function to use provided inline heuristic.
2727
#[inline]
28-
fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr, requires_inline: bool) {
28+
fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
2929
use self::InlineAttr::*;
3030
match inline {
3131
Hint => Attribute::InlineHint.apply_llfn(Function, val),
@@ -35,7 +35,6 @@ fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr, requires
3535
Attribute::NoInline.apply_llfn(Function, val);
3636
}
3737
}
38-
None if requires_inline => Attribute::InlineHint.apply_llfn(Function, val),
3938
None => {}
4039
};
4140
}
@@ -226,7 +225,14 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
226225
}
227226
}
228227

229-
inline(cx, llfn, codegen_fn_attrs.inline.clone(), instance.def.requires_inline(cx.tcx));
228+
let inline_attr = if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
229+
InlineAttr::Never
230+
} else if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
231+
InlineAttr::Hint
232+
} else {
233+
codegen_fn_attrs.inline
234+
};
235+
inline(cx, llfn, inline_attr);
230236

231237
// The `uwtable` attribute according to LLVM is:
232238
//

compiler/rustc_mir/src/transform/inline.rs

+5
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,11 @@ impl Inliner<'tcx> {
254254
self.tcx.sess.opts.debugging_opts.inline_mir_threshold
255255
};
256256

257+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
258+
debug!("#[naked] present - not inlining");
259+
return false;
260+
}
261+
257262
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
258263
debug!("#[cold] present - not inlining");
259264
return false;

src/test/codegen/naked-inline.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Checks that naked functions are never inlined.
2+
// compile-flags: -O -Zmir-opt-level=2
3+
#![crate_type = "lib"]
4+
#![feature(asm)]
5+
#![feature(naked_functions)]
6+
7+
#[inline(always)]
8+
#[naked]
9+
#[no_mangle]
10+
pub unsafe fn f() {
11+
// Check that f has naked and noinline attributes.
12+
//
13+
// CHECK: define void @f() unnamed_addr [[ATTR:#[0-9]+]]
14+
// CHECK-NEXT: start:
15+
// CHECK-NEXT: call void asm
16+
asm!("", options(noreturn));
17+
}
18+
19+
#[no_mangle]
20+
pub unsafe fn g() {
21+
// Check that call to f is not inlined.
22+
//
23+
// CHECK-LABEL: define void @g()
24+
// CHECK-NEXT: start:
25+
// CHECK-NEXT: call void @f()
26+
f();
27+
}
28+
29+
// CHECK: attributes [[ATTR]] = { naked noinline{{.*}} }

0 commit comments

Comments
 (0)