about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_attr/src/builtin.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs12
-rw-r--r--compiler/rustc_mir/src/transform/inline.rs5
-rw-r--r--src/test/codegen/naked-noinline.rs30
4 files changed, 45 insertions, 4 deletions
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 2fd625c2a6c..364a3a1eeb5 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -67,7 +67,7 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
     }
 }
 
-#[derive(Clone, PartialEq, Encodable, Decodable)]
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable)]
 pub enum InlineAttr {
     None,
     Hint,
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 9a2fbf359ea..62a7986c194 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -25,7 +25,7 @@ use crate::value::Value;
 
 /// Mark LLVM function to use provided inline heuristic.
 #[inline]
-fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr, requires_inline: bool) {
+fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
     use self::InlineAttr::*;
     match inline {
         Hint => Attribute::InlineHint.apply_llfn(Function, val),
@@ -35,7 +35,6 @@ fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr, requires
                 Attribute::NoInline.apply_llfn(Function, val);
             }
         }
-        None if requires_inline => Attribute::InlineHint.apply_llfn(Function, val),
         None => {}
     };
 }
@@ -226,7 +225,14 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
         }
     }
 
-    inline(cx, llfn, codegen_fn_attrs.inline.clone(), instance.def.requires_inline(cx.tcx));
+    let inline_attr = if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
+        InlineAttr::Never
+    } else if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
+        InlineAttr::Hint
+    } else {
+        codegen_fn_attrs.inline
+    };
+    inline(cx, llfn, inline_attr);
 
     // The `uwtable` attribute according to LLVM is:
     //
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index 094c1513118..4eeb8969bb1 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -254,6 +254,11 @@ impl Inliner<'tcx> {
             self.tcx.sess.opts.debugging_opts.inline_mir_threshold
         };
 
+        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
+            debug!("#[naked] present - not inlining");
+            return false;
+        }
+
         if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
             debug!("#[cold] present - not inlining");
             return false;
diff --git a/src/test/codegen/naked-noinline.rs b/src/test/codegen/naked-noinline.rs
new file mode 100644
index 00000000000..2a2208d4fce
--- /dev/null
+++ b/src/test/codegen/naked-noinline.rs
@@ -0,0 +1,30 @@
+// Checks that naked functions are never inlined.
+// compile-flags: -O -Zmir-opt-level=2
+// ignore-wasm32
+#![crate_type = "lib"]
+#![feature(asm)]
+#![feature(naked_functions)]
+
+#[inline(always)]
+#[naked]
+#[no_mangle]
+pub unsafe extern "C" fn f() {
+// Check that f has naked and noinline attributes.
+//
+// CHECK:       define void @f() unnamed_addr [[ATTR:#[0-9]+]]
+// CHECK-NEXT:  start:
+// CHECK-NEXT:    call void asm
+    asm!("", options(noreturn));
+}
+
+#[no_mangle]
+pub unsafe fn g() {
+// Check that call to f is not inlined.
+//
+// CHECK-LABEL: define void @g()
+// CHECK-NEXT:  start:
+// CHECK-NEXT:    call void @f()
+    f();
+}
+
+// CHECK: attributes [[ATTR]] = { naked noinline{{.*}} }