From 157e0a0e8f68ab997b320a2d61c2d8ad20d5ce86 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Mon, 2 Aug 2021 15:03:43 -0400 Subject: [PATCH] Validate that naked functions are never inlined Reject all uses of the inline attribute on naked functions. rust-lang/rfcs#2774 rust-lang/rfcs#2972 --- compiler/rustc_lint_defs/src/builtin.rs | 3 ++ compiler/rustc_passes/src/naked_functions.rs | 12 ++++- src/test/ui/asm/naked-functions.rs | 43 +++++++++++++++ src/test/ui/asm/naked-functions.stderr | 56 +++++++++++++++++++- 4 files changed, 112 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 7195c41eae92e..b1948ae072be9 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2720,6 +2720,9 @@ declare_lint! { /// The asm block must not contain any operands other than `const` and /// `sym`. Additionally, naked function should specify a non-Rust ABI. /// + /// Naked functions cannot be inlined. All forms of the `inline` attribute + /// are prohibited. + /// /// While other definitions of naked functions were previously accepted, /// they are unsupported and might not work reliably. This is a /// [future-incompatible] lint that will transition into hard error in diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 89bc2e1a9870f..e05ec205b65b8 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -1,6 +1,6 @@ //! Checks validity of naked functions. -use rustc_ast::InlineAsmOptions; +use rustc_ast::{Attribute, InlineAsmOptions}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{ErasedMap, FnKind, NestedVisitorMap, Visitor}; @@ -70,10 +70,20 @@ impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> { check_no_patterns(self.tcx, body.params); check_no_parameters_use(self.tcx, body); check_asm(self.tcx, hir_id, body, span); + check_inline(self.tcx, hir_id, attrs); } } } +/// Check that the function isn't inlined. +fn check_inline(tcx: TyCtxt<'_>, hir_id: HirId, attrs: &[Attribute]) { + for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) { + tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, attr.span, |lint| { + lint.build("naked functions cannot be inlined").emit(); + }); + } +} + /// Checks that function uses non-Rust ABI. fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) { if abi == Abi::Rust { diff --git a/src/test/ui/asm/naked-functions.rs b/src/test/ui/asm/naked-functions.rs index a46ca4544a68f..7075995c2cfff 100644 --- a/src/test/ui/asm/naked-functions.rs +++ b/src/test/ui/asm/naked-functions.rs @@ -167,3 +167,46 @@ pub unsafe extern "C" fn valid_c() { pub unsafe extern "C" fn valid_att_syntax() { asm!("", options(noreturn, att_syntax)); } + +#[naked] +pub unsafe extern "C" fn inline_none() { + asm!("", options(noreturn)); +} + +#[naked] +#[inline] +//~^ WARN naked functions cannot be inlined +//~| WARN this was previously accepted +pub unsafe extern "C" fn inline_hint() { + asm!("", options(noreturn)); +} + +#[naked] +#[inline(always)] +//~^ WARN naked functions cannot be inlined +//~| WARN this was previously accepted +pub unsafe extern "C" fn inline_always() { + asm!("", options(noreturn)); +} + +#[naked] +#[inline(never)] +//~^ WARN naked functions cannot be inlined +//~| WARN this was previously accepted +pub unsafe extern "C" fn inline_never() { + asm!("", options(noreturn)); +} + +#[naked] +#[inline] +//~^ WARN naked functions cannot be inlined +//~| WARN this was previously accepted +#[inline(always)] +//~^ WARN naked functions cannot be inlined +//~| WARN this was previously accepted +#[inline(never)] +//~^ WARN naked functions cannot be inlined +//~| WARN this was previously accepted +pub unsafe extern "C" fn inline_all() { + asm!("", options(noreturn)); +} diff --git a/src/test/ui/asm/naked-functions.stderr b/src/test/ui/asm/naked-functions.stderr index 9a82da8d90d3c..2a186a69ff460 100644 --- a/src/test/ui/asm/naked-functions.stderr +++ b/src/test/ui/asm/naked-functions.stderr @@ -296,5 +296,59 @@ LL | pub unsafe extern "Rust" fn rust_abi() { = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #32408 -error: aborting due to 8 previous errors; 19 warnings emitted +warning: naked functions cannot be inlined + --> $DIR/naked-functions.rs:177:1 + | +LL | #[inline] + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: naked functions cannot be inlined + --> $DIR/naked-functions.rs:185:1 + | +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: naked functions cannot be inlined + --> $DIR/naked-functions.rs:193:1 + | +LL | #[inline(never)] + | ^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: naked functions cannot be inlined + --> $DIR/naked-functions.rs:201:1 + | +LL | #[inline] + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: naked functions cannot be inlined + --> $DIR/naked-functions.rs:204:1 + | +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: naked functions cannot be inlined + --> $DIR/naked-functions.rs:207:1 + | +LL | #[inline(never)] + | ^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +error: aborting due to 8 previous errors; 25 warnings emitted