about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTomasz Miąsko <tomasz.miasko@gmail.com>2020-12-07 00:00:00 +0000
committerTomasz Miąsko <tomasz.miasko@gmail.com>2020-12-07 00:00:00 +0000
commit8065dabd171f7807b47a461b17f443df47a0cad5 (patch)
tree7bd809d785d8b9b0299a14a82fa021bbca0c3074
parent91fe5488254360732d5116b4ccd136d50d01c25d (diff)
downloadrust-8065dabd171f7807b47a461b17f443df47a0cad5.tar.gz
rust-8065dabd171f7807b47a461b17f443df47a0cad5.zip
Validate naked functions definitions
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs45
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs239
-rw-r--r--src/test/ui/asm/naked-functions.rs169
-rw-r--r--src/test/ui/asm/naked-functions.stderr300
-rw-r--r--src/test/ui/asm/naked-params.rs51
-rw-r--r--src/test/ui/asm/naked-params.stderr44
-rw-r--r--src/test/ui/feature-gates/feature-gate-naked_functions.rs10
-rw-r--r--src/test/ui/feature-gates/feature-gate-naked_functions.stderr4
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-naked.rs10
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-naked.stderr2
10 files changed, 755 insertions, 119 deletions
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index fa82dce0ae2..a9358c9610a 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2742,6 +2742,50 @@ declare_lint! {
     "detects deprecation attributes with no effect",
 }
 
+declare_lint! {
+    /// The `unsupported_naked_functions` lint detects naked function
+    /// definitions that are unsupported but were previously accepted.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(naked_functions)]
+    ///
+    /// #[naked]
+    /// pub fn f() -> u32 {
+    ///     42
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The naked functions must be defined using a single inline assembly
+    /// block.
+    ///
+    /// The execution must never fall through past the end of the assembly
+    /// code so the block must use `noreturn` option. The asm block can also
+    /// use `att_syntax` option, but other options are not allowed.
+    ///
+    /// The asm block must not contain any operands other than `const` and
+    /// `sym`. Additionally, naked function should specify a non-Rust ABI.
+    ///
+    /// 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
+    /// the future.
+    ///
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
+    pub UNSUPPORTED_NAKED_FUNCTIONS,
+    Warn,
+    "unsupported naked function definitions",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #32408 <https://github.com/rust-lang/rust/issues/32408>",
+        edition: None,
+    };
+}
+
 declare_tool_lint! {
     pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
     Deny,
@@ -2832,6 +2876,7 @@ declare_lint_pass! {
         UNINHABITED_STATIC,
         FUNCTION_ITEM_REFERENCES,
         USELESS_DEPRECATED,
+        UNSUPPORTED_NAKED_FUNCTIONS,
     ]
 }
 
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 6ef45cdd391..5b50ef8627b 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -1,10 +1,16 @@
+//! Checks validity of naked functions.
+
+use rustc_ast::InlineAsmOptions;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{ErasedMap, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
+use rustc_session::lint::builtin::UNSUPPORTED_NAKED_FUNCTIONS;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
+use rustc_target::spec::abi::Abi;
 
 fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir().visit_item_likes_in_module(
@@ -33,27 +39,52 @@ impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
         fk: FnKind<'v>,
         _fd: &'tcx hir::FnDecl<'tcx>,
         body_id: hir::BodyId,
-        _span: Span,
-        _hir_id: hir::HirId,
+        span: Span,
+        hir_id: HirId,
     ) {
+        let ident_span;
+        let fn_header;
+
         match fk {
-            // Rejected during attribute check. Do not validate further.
-            FnKind::Closure(..) => return,
-            FnKind::ItemFn(..) | FnKind::Method(..) => {}
+            FnKind::Closure(..) => {
+                // Closures with a naked attribute are rejected during attribute
+                // check. Don't validate them any further.
+                return;
+            }
+            FnKind::ItemFn(ident, _, ref header, ..) => {
+                ident_span = ident.span;
+                fn_header = header;
+            }
+
+            FnKind::Method(ident, ref sig, ..) => {
+                ident_span = ident.span;
+                fn_header = &sig.header;
+            }
         }
 
         let naked = fk.attrs().iter().any(|attr| attr.has_name(sym::naked));
         if naked {
             let body = self.tcx.hir().body(body_id);
-            check_params(self.tcx, body);
-            check_body(self.tcx, body);
+            check_abi(self.tcx, hir_id, fn_header.abi, ident_span);
+            check_no_patterns(self.tcx, body.params);
+            check_no_parameters_use(self.tcx, body);
+            check_asm(self.tcx, hir_id, body, span);
         }
     }
 }
 
+/// 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 {
+        tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_ident_span, |lint| {
+            lint.build("Rust ABI is unsupported in naked functions").emit();
+        });
+    }
+}
+
 /// Checks that parameters don't use patterns. Mirrors the checks for function declarations.
-fn check_params(tcx: TyCtxt<'_>, body: &hir::Body<'_>) {
-    for param in body.params {
+fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
+    for param in params {
         match param.pat.kind {
             hir::PatKind::Wild
             | hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, _, None) => {}
@@ -69,23 +100,23 @@ fn check_params(tcx: TyCtxt<'_>, body: &hir::Body<'_>) {
     }
 }
 
-/// Checks that function parameters aren't referenced in the function body.
-fn check_body<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) {
+/// Checks that function parameters aren't used in the function body.
+fn check_no_parameters_use<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) {
     let mut params = hir::HirIdSet::default();
     for param in body.params {
         param.pat.each_binding(|_binding_mode, hir_id, _span, _ident| {
             params.insert(hir_id);
         });
     }
-    CheckBody { tcx, params }.visit_body(body);
+    CheckParameters { tcx, params }.visit_body(body);
 }
 
-struct CheckBody<'tcx> {
+struct CheckParameters<'tcx> {
     tcx: TyCtxt<'tcx>,
     params: hir::HirIdSet,
 }
 
-impl<'tcx> Visitor<'tcx> for CheckBody<'tcx> {
+impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
     type Map = ErasedMap<'tcx>;
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -103,11 +134,189 @@ impl<'tcx> Visitor<'tcx> for CheckBody<'tcx> {
                     .sess
                     .struct_span_err(
                         expr.span,
-                        "use of parameters not allowed inside naked functions",
+                        "referencing function parameters is not allowed in naked functions",
                     )
+                    .help("follow the calling convention in asm block to use parameters")
                     .emit();
+                return;
             }
         }
         hir::intravisit::walk_expr(self, expr);
     }
 }
+
+/// Checks that function body contains a single inline assembly block.
+fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
+    let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
+    this.visit_body(body);
+    if let &[(ItemKind::Asm, _)] = &this.items[..] {
+        // Ok.
+    } else {
+        tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_span, |lint| {
+            let mut diag = lint.build("naked functions must contain a single asm block");
+            let mut has_asm = false;
+            for &(kind, span) in &this.items {
+                match kind {
+                    ItemKind::Asm if has_asm => {
+                        diag.span_label(
+                            span,
+                            "multiple asm blocks are unsupported in naked functions",
+                        );
+                    }
+                    ItemKind::Asm => has_asm = true,
+                    ItemKind::NonAsm => {
+                        diag.span_label(span, "non-asm is unsupported in naked functions");
+                    }
+                }
+            }
+            diag.emit();
+        });
+    }
+}
+
+struct CheckInlineAssembly<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    items: Vec<(ItemKind, Span)>,
+}
+
+#[derive(Copy, Clone)]
+enum ItemKind {
+    Asm,
+    NonAsm,
+}
+
+impl<'tcx> CheckInlineAssembly<'tcx> {
+    fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) {
+        match expr.kind {
+            ExprKind::Box(..)
+            | ExprKind::ConstBlock(..)
+            | ExprKind::Array(..)
+            | ExprKind::Call(..)
+            | ExprKind::MethodCall(..)
+            | ExprKind::Tup(..)
+            | ExprKind::Binary(..)
+            | ExprKind::Unary(..)
+            | ExprKind::Lit(..)
+            | ExprKind::Cast(..)
+            | ExprKind::Type(..)
+            | ExprKind::Loop(..)
+            | ExprKind::Match(..)
+            | ExprKind::Closure(..)
+            | ExprKind::Assign(..)
+            | ExprKind::AssignOp(..)
+            | ExprKind::Field(..)
+            | ExprKind::Index(..)
+            | ExprKind::Path(..)
+            | ExprKind::AddrOf(..)
+            | ExprKind::Break(..)
+            | ExprKind::Continue(..)
+            | ExprKind::Ret(..)
+            | ExprKind::Struct(..)
+            | ExprKind::Repeat(..)
+            | ExprKind::Yield(..) => {
+                self.items.push((ItemKind::NonAsm, span));
+            }
+
+            ExprKind::InlineAsm(ref asm) => {
+                self.items.push((ItemKind::Asm, span));
+                self.check_inline_asm(expr.hir_id, asm, span);
+            }
+
+            ExprKind::LlvmInlineAsm(..) => {
+                self.items.push((ItemKind::Asm, span));
+                self.tcx.struct_span_lint_hir(
+                    UNSUPPORTED_NAKED_FUNCTIONS,
+                    expr.hir_id,
+                    span,
+                    |lint| {
+                        lint.build(
+                            "the LLVM-style inline assembly is unsupported in naked functions",
+                        )
+                        .help("use the new asm! syntax specified in RFC 2873")
+                        .emit();
+                    },
+                );
+            }
+
+            ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => {
+                hir::intravisit::walk_expr(self, expr);
+            }
+        }
+    }
+
+    fn check_inline_asm(&self, hir_id: HirId, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) {
+        let unsupported_operands: Vec<Span> = asm
+            .operands
+            .iter()
+            .filter_map(|&(ref op, op_sp)| match op {
+                InlineAsmOperand::Const { .. } | InlineAsmOperand::Sym { .. } => None,
+                InlineAsmOperand::In { .. }
+                | InlineAsmOperand::Out { .. }
+                | InlineAsmOperand::InOut { .. }
+                | InlineAsmOperand::SplitInOut { .. } => Some(op_sp),
+            })
+            .collect();
+        if !unsupported_operands.is_empty() {
+            self.tcx.struct_span_lint_hir(
+                UNSUPPORTED_NAKED_FUNCTIONS,
+                hir_id,
+                unsupported_operands,
+                |lint| {
+                    lint.build("only `const` and `sym` operands are supported in naked functions")
+                        .emit();
+                },
+            );
+        }
+
+        let unsupported_options: Vec<&'static str> = [
+            (InlineAsmOptions::NOMEM, "`nomem`"),
+            (InlineAsmOptions::NOSTACK, "`nostack`"),
+            (InlineAsmOptions::PRESERVES_FLAGS, "`preserves_flags`"),
+            (InlineAsmOptions::PURE, "`pure`"),
+            (InlineAsmOptions::READONLY, "`readonly`"),
+        ]
+        .iter()
+        .filter_map(|&(option, name)| if asm.options.contains(option) { Some(name) } else { None })
+        .collect();
+
+        if !unsupported_options.is_empty() {
+            self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| {
+                lint.build(&format!(
+                    "asm options unsupported in naked functions: {}",
+                    unsupported_options.join(", ")
+                ))
+                .emit();
+            });
+        }
+
+        if !asm.options.contains(InlineAsmOptions::NORETURN) {
+            self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| {
+                lint.build("asm in naked functions must use `noreturn` option").emit();
+            });
+        }
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> {
+    type Map = ErasedMap<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
+        match stmt.kind {
+            StmtKind::Item(..) => {}
+            StmtKind::Local(..) => {
+                self.items.push((ItemKind::NonAsm, stmt.span));
+            }
+            StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => {
+                self.check_expr(expr, stmt.span);
+            }
+        }
+    }
+
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+        self.check_expr(&expr, expr.span);
+    }
+}
diff --git a/src/test/ui/asm/naked-functions.rs b/src/test/ui/asm/naked-functions.rs
new file mode 100644
index 00000000000..a46ca4544a6
--- /dev/null
+++ b/src/test/ui/asm/naked-functions.rs
@@ -0,0 +1,169 @@
+// only-x86_64
+#![feature(asm)]
+#![feature(llvm_asm)]
+#![feature(naked_functions)]
+#![feature(or_patterns)]
+#![crate_type = "lib"]
+
+#[repr(C)]
+pub struct P { x: u8, y: u16 }
+
+#[naked]
+pub unsafe extern "C" fn patterns(
+    mut a: u32,
+    //~^ ERROR patterns not allowed in naked function parameters
+    &b: &i32,
+    //~^ ERROR patterns not allowed in naked function parameters
+    (None | Some(_)): Option<std::ptr::NonNull<u8>>,
+    //~^ ERROR patterns not allowed in naked function parameters
+    P { x, y }: P,
+    //~^ ERROR patterns not allowed in naked function parameters
+) {
+    asm!("", options(noreturn))
+}
+
+#[naked]
+pub unsafe extern "C" fn inc(a: u32) -> u32 {
+    //~^ WARN naked functions must contain a single asm block
+    //~| WARN this was previously accepted
+    a + 1
+    //~^ ERROR referencing function parameters is not allowed in naked functions
+}
+
+#[naked]
+pub unsafe extern "C" fn inc_asm(a: u32) -> u32 {
+    asm!("/* {0} */", in(reg) a, options(noreturn));
+    //~^ ERROR referencing function parameters is not allowed in naked functions
+    //~| WARN only `const` and `sym` operands are supported in naked functions
+    //~| WARN this was previously accepted
+}
+
+#[naked]
+pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
+    //~^ WARN naked functions must contain a single asm block
+    //~| WARN this was previously accepted
+    (|| a + 1)()
+}
+
+#[naked]
+pub unsafe extern "C" fn unsupported_operands() {
+    //~^ WARN naked functions must contain a single asm block
+    //~| WARN this was previously accepted
+    let mut a = 0usize;
+    let mut b = 0usize;
+    let mut c = 0usize;
+    let mut d = 0usize;
+    let mut e = 0usize;
+    const F: usize = 0usize;
+    static G: usize = 0usize;
+    asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
+         //~^ WARN asm in naked functions must use `noreturn` option
+         //~| WARN this was previously accepted
+         in(reg) a,
+         //~^ WARN only `const` and `sym` operands are supported in naked functions
+         //~| WARN this was previously accepted
+         inlateout(reg) b,
+         inout(reg) c,
+         lateout(reg) d,
+         out(reg) e,
+         const F,
+         sym G,
+    );
+}
+
+#[naked]
+pub extern "C" fn missing_assembly() {
+    //~^ WARN naked functions must contain a single asm block
+    //~| WARN this was previously accepted
+}
+
+#[naked]
+pub extern "C" fn too_many_asm_blocks() {
+    //~^ WARN naked functions must contain a single asm block
+    //~| WARN this was previously accepted
+    asm!("");
+    //~^ WARN asm in naked functions must use `noreturn` option
+    //~| WARN this was previously accepted
+    asm!("");
+    //~^ WARN asm in naked functions must use `noreturn` option
+    //~| WARN this was previously accepted
+    asm!("");
+    //~^ WARN asm in naked functions must use `noreturn` option
+    //~| WARN this was previously accepted
+    asm!("", options(noreturn));
+}
+
+pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
+    #[naked]
+    pub extern "C" fn inner(y: usize) -> usize {
+        //~^ WARN naked functions must contain a single asm block
+        //~| WARN this was previously accepted
+        *&y
+        //~^ ERROR referencing function parameters is not allowed in naked functions
+    }
+    inner
+}
+
+#[naked]
+unsafe extern "C" fn llvm() -> ! {
+    //~^ WARN naked functions must contain a single asm block
+    //~| WARN this was previously accepted
+    llvm_asm!("");
+    //~^ WARN LLVM-style inline assembly is unsupported in naked functions
+    //~| WARN this was previously accepted
+    core::hint::unreachable_unchecked();
+}
+
+#[naked]
+unsafe extern "C" fn invalid_options() {
+    asm!("", options(nomem, preserves_flags, noreturn));
+    //~^ WARN asm options unsupported in naked functions: `nomem`, `preserves_flags`
+    //~| WARN this was previously accepted
+}
+
+#[naked]
+unsafe extern "C" fn invalid_options_continued() {
+    asm!("", options(readonly, nostack), options(pure));
+    //~^ ERROR asm with `pure` option must have at least one output
+    //~| WARN asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
+    //~| WARN this was previously accepted
+    //~| WARN asm in naked functions must use `noreturn` option
+    //~| WARN this was previously accepted
+}
+
+#[naked]
+pub unsafe fn default_abi() {
+    //~^ WARN Rust ABI is unsupported in naked functions
+    //~| WARN this was previously accepted
+    asm!("", options(noreturn));
+}
+
+#[naked]
+pub unsafe extern "Rust" fn rust_abi() {
+    //~^ WARN Rust ABI is unsupported in naked functions
+    //~| WARN this was previously accepted
+    asm!("", options(noreturn));
+}
+
+#[naked]
+pub extern "C" fn valid_a<T>() -> T {
+    unsafe { asm!("", options(noreturn)); }
+}
+
+#[naked]
+pub extern "C" fn valid_b() {
+    unsafe { { {
+        asm!("", options(noreturn)); ; ; ;
+    } ; }  ; }
+}
+
+#[naked]
+pub unsafe extern "C" fn valid_c() {
+    asm!("", options(noreturn));
+}
+
+#[cfg(target_arch = "x86_64")]
+#[naked]
+pub unsafe extern "C" fn valid_att_syntax() {
+    asm!("", options(noreturn, att_syntax));
+}
diff --git a/src/test/ui/asm/naked-functions.stderr b/src/test/ui/asm/naked-functions.stderr
new file mode 100644
index 00000000000..076289427b5
--- /dev/null
+++ b/src/test/ui/asm/naked-functions.stderr
@@ -0,0 +1,300 @@
+error: asm with `pure` option must have at least one output
+  --> $DIR/naked-functions.rs:126:14
+   |
+LL |     asm!("", options(readonly, nostack), options(pure));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^
+
+error: patterns not allowed in naked function parameters
+  --> $DIR/naked-functions.rs:13:5
+   |
+LL |     mut a: u32,
+   |     ^^^^^
+
+error: patterns not allowed in naked function parameters
+  --> $DIR/naked-functions.rs:15:5
+   |
+LL |     &b: &i32,
+   |     ^^
+
+error: patterns not allowed in naked function parameters
+  --> $DIR/naked-functions.rs:17:6
+   |
+LL |     (None | Some(_)): Option<std::ptr::NonNull<u8>>,
+   |      ^^^^^^^^^^^^^^
+
+error: patterns not allowed in naked function parameters
+  --> $DIR/naked-functions.rs:19:5
+   |
+LL |     P { x, y }: P,
+   |     ^^^^^^^^^^
+
+error: referencing function parameters is not allowed in naked functions
+  --> $DIR/naked-functions.rs:29:5
+   |
+LL |     a + 1
+   |     ^
+   |
+   = help: follow the calling convention in asm block to use parameters
+
+warning: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:26:1
+   |
+LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
+LL | |
+LL | |
+LL | |     a + 1
+   | |     ----- non-asm is unsupported in naked functions
+LL | |
+LL | | }
+   | |_^
+   |
+   = note: `#[warn(unsupported_naked_functions)]` on by default
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+error: referencing function parameters is not allowed in naked functions
+  --> $DIR/naked-functions.rs:35:31
+   |
+LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
+   |                               ^
+   |
+   = help: follow the calling convention in asm block to use parameters
+
+warning: only `const` and `sym` operands are supported in naked functions
+  --> $DIR/naked-functions.rs:35:23
+   |
+LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
+   |                       ^^^^^^^^^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:42:1
+   |
+LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
+LL | |
+LL | |
+LL | |     (|| a + 1)()
+   | |     ------------ non-asm is unsupported in naked functions
+LL | | }
+   | |_^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: only `const` and `sym` operands are supported in naked functions
+  --> $DIR/naked-functions.rs:62:10
+   |
+LL |          in(reg) a,
+   |          ^^^^^^^^^
+...
+LL |          inlateout(reg) b,
+   |          ^^^^^^^^^^^^^^^^
+LL |          inout(reg) c,
+   |          ^^^^^^^^^^^^
+LL |          lateout(reg) d,
+   |          ^^^^^^^^^^^^^^
+LL |          out(reg) e,
+   |          ^^^^^^^^^^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:59:5
+   |
+LL | /     asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
+LL | |
+LL | |
+LL | |          in(reg) a,
+...  |
+LL | |          sym G,
+LL | |     );
+   | |______^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:49:1
+   |
+LL | / pub unsafe extern "C" fn unsupported_operands() {
+LL | |
+LL | |
+LL | |     let mut a = 0usize;
+   | |     ------------------- non-asm is unsupported in naked functions
+LL | |     let mut b = 0usize;
+   | |     ------------------- non-asm is unsupported in naked functions
+LL | |     let mut c = 0usize;
+   | |     ------------------- non-asm is unsupported in naked functions
+LL | |     let mut d = 0usize;
+   | |     ------------------- non-asm is unsupported in naked functions
+LL | |     let mut e = 0usize;
+   | |     ------------------- non-asm is unsupported in naked functions
+...  |
+LL | |     );
+LL | | }
+   | |_^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:75:1
+   |
+LL | / pub extern "C" fn missing_assembly() {
+LL | |
+LL | |
+LL | | }
+   | |_^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:84:5
+   |
+LL |     asm!("");
+   |     ^^^^^^^^^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:87:5
+   |
+LL |     asm!("");
+   |     ^^^^^^^^^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:90:5
+   |
+LL |     asm!("");
+   |     ^^^^^^^^^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:81:1
+   |
+LL | / pub extern "C" fn too_many_asm_blocks() {
+LL | |
+LL | |
+LL | |     asm!("");
+...  |
+LL | |     asm!("");
+   | |     --------- multiple asm blocks are unsupported in naked functions
+...  |
+LL | |     asm!("");
+   | |     --------- multiple asm blocks are unsupported in naked functions
+...  |
+LL | |     asm!("", options(noreturn));
+   | |     ---------------------------- multiple asm blocks are unsupported in naked functions
+LL | | }
+   | |_^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+error: referencing function parameters is not allowed in naked functions
+  --> $DIR/naked-functions.rs:101:11
+   |
+LL |         *&y
+   |           ^
+   |
+   = help: follow the calling convention in asm block to use parameters
+
+warning: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:98:5
+   |
+LL | /     pub extern "C" fn inner(y: usize) -> usize {
+LL | |
+LL | |
+LL | |         *&y
+   | |         --- non-asm is unsupported in naked functions
+LL | |
+LL | |     }
+   | |_____^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: the LLVM-style inline assembly is unsupported in naked functions
+  --> $DIR/naked-functions.rs:111:5
+   |
+LL |     llvm_asm!("");
+   |     ^^^^^^^^^^^^^^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+   = help: use the new asm! syntax specified in RFC 2873
+   = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:108:1
+   |
+LL | / unsafe extern "C" fn llvm() -> ! {
+LL | |
+LL | |
+LL | |     llvm_asm!("");
+...  |
+LL | |     core::hint::unreachable_unchecked();
+   | |     ------------------------------------ non-asm is unsupported in naked functions
+LL | | }
+   | |_^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: asm options unsupported in naked functions: `nomem`, `preserves_flags`
+  --> $DIR/naked-functions.rs:119:5
+   |
+LL |     asm!("", options(nomem, preserves_flags, noreturn));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
+  --> $DIR/naked-functions.rs:126:5
+   |
+LL |     asm!("", options(readonly, nostack), options(pure));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:126:5
+   |
+LL |     asm!("", options(readonly, nostack), options(pure));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: Rust ABI is unsupported in naked functions
+  --> $DIR/naked-functions.rs:135:15
+   |
+LL | pub unsafe fn default_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 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: Rust ABI is unsupported in naked functions
+  --> $DIR/naked-functions.rs:142:29
+   |
+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 <https://github.com/rust-lang/rust/issues/32408>
+
+error: aborting due to 8 previous errors; 19 warnings emitted
+
diff --git a/src/test/ui/asm/naked-params.rs b/src/test/ui/asm/naked-params.rs
deleted file mode 100644
index 46a4fc11e5a..00000000000
--- a/src/test/ui/asm/naked-params.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-// Check that use of function parameters is validate in naked functions.
-//
-// ignore-wasm32 asm unsupported
-#![feature(asm)]
-#![feature(naked_functions)]
-#![feature(or_patterns)]
-#![crate_type = "lib"]
-
-#[repr(C)]
-pub struct P { x: u8, y: u16 }
-
-#[naked]
-pub unsafe extern "C" fn f(
-    mut a: u32,
-    //~^ ERROR patterns not allowed in naked function parameters
-    &b: &i32,
-    //~^ ERROR patterns not allowed in naked function parameters
-    (None | Some(_)): Option<std::ptr::NonNull<u8>>,
-    //~^ ERROR patterns not allowed in naked function parameters
-    P { x, y }: P,
-    //~^ ERROR patterns not allowed in naked function parameters
-) {
-    asm!("", options(noreturn))
-}
-
-#[naked]
-pub unsafe extern "C" fn inc(a: u32) -> u32 {
-    a + 1
-    //~^ ERROR use of parameters not allowed inside naked functions
-}
-
-#[naked]
-pub unsafe extern "C" fn inc_asm(a: u32) -> u32 {
-    asm!("/* {0} */", in(reg) a, options(noreturn));
-    //~^ ERROR use of parameters not allowed inside naked functions
-}
-
-#[naked]
-pub unsafe extern "C" fn sum(x: u32, y: u32) -> u32 {
-    // FIXME: Should be detected by asm-only check.
-    (|| { x + y})()
-}
-
-pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
-    #[naked]
-    pub extern "C" fn inner(y: usize) -> usize {
-        *&y
-        //~^ ERROR use of parameters not allowed inside naked functions
-    }
-    inner
-}
diff --git a/src/test/ui/asm/naked-params.stderr b/src/test/ui/asm/naked-params.stderr
deleted file mode 100644
index 1a99e5109fc..00000000000
--- a/src/test/ui/asm/naked-params.stderr
+++ /dev/null
@@ -1,44 +0,0 @@
-error: patterns not allowed in naked function parameters
-  --> $DIR/naked-params.rs:14:5
-   |
-LL |     mut a: u32,
-   |     ^^^^^
-
-error: patterns not allowed in naked function parameters
-  --> $DIR/naked-params.rs:16:5
-   |
-LL |     &b: &i32,
-   |     ^^
-
-error: patterns not allowed in naked function parameters
-  --> $DIR/naked-params.rs:18:6
-   |
-LL |     (None | Some(_)): Option<std::ptr::NonNull<u8>>,
-   |      ^^^^^^^^^^^^^^
-
-error: patterns not allowed in naked function parameters
-  --> $DIR/naked-params.rs:20:5
-   |
-LL |     P { x, y }: P,
-   |     ^^^^^^^^^^
-
-error: use of parameters not allowed inside naked functions
-  --> $DIR/naked-params.rs:28:5
-   |
-LL |     a + 1
-   |     ^
-
-error: use of parameters not allowed inside naked functions
-  --> $DIR/naked-params.rs:34:31
-   |
-LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
-   |                               ^
-
-error: use of parameters not allowed inside naked functions
-  --> $DIR/naked-params.rs:47:11
-   |
-LL |         *&y
-   |           ^
-
-error: aborting due to 7 previous errors
-
diff --git a/src/test/ui/feature-gates/feature-gate-naked_functions.rs b/src/test/ui/feature-gates/feature-gate-naked_functions.rs
index 16a51a1e82f..06bddc422cf 100644
--- a/src/test/ui/feature-gates/feature-gate-naked_functions.rs
+++ b/src/test/ui/feature-gates/feature-gate-naked_functions.rs
@@ -1,11 +1,15 @@
+#![feature(asm)]
+
 #[naked]
 //~^ the `#[naked]` attribute is an experimental feature
-fn naked() {}
+extern "C" fn naked() {
+    asm!("", options(noreturn))
+}
 
 #[naked]
 //~^ the `#[naked]` attribute is an experimental feature
-fn naked_2() -> isize {
-    0
+extern "C" fn naked_2() -> isize {
+    asm!("", options(noreturn))
 }
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-naked_functions.stderr b/src/test/ui/feature-gates/feature-gate-naked_functions.stderr
index e24dde5429d..d95561d2013 100644
--- a/src/test/ui/feature-gates/feature-gate-naked_functions.stderr
+++ b/src/test/ui/feature-gates/feature-gate-naked_functions.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the `#[naked]` attribute is an experimental feature
-  --> $DIR/feature-gate-naked_functions.rs:1:1
+  --> $DIR/feature-gate-naked_functions.rs:3:1
    |
 LL | #[naked]
    | ^^^^^^^^
@@ -8,7 +8,7 @@ LL | #[naked]
    = help: add `#![feature(naked_functions)]` to the crate attributes to enable
 
 error[E0658]: the `#[naked]` attribute is an experimental feature
-  --> $DIR/feature-gate-naked_functions.rs:5:1
+  --> $DIR/feature-gate-naked_functions.rs:9:1
    |
 LL | #[naked]
    | ^^^^^^^^
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
index c60ff7dc934..70ec0e3033c 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
@@ -1,15 +1,19 @@
-#![feature(naked_functions)]
+#![feature(asm, naked_functions)]
 
 #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]`
 #[naked]
-fn f() {}
+extern "C" fn f() {
+    asm!("", options(noreturn));
+}
 
 struct S;
 
 impl S {
     #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]`
     #[naked]
-    fn g() {}
+    extern "C" fn g() {
+        asm!("", options(noreturn));
+    }
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr
index 211cd3f16ba..1b49148d629 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr
@@ -5,7 +5,7 @@ LL | #[track_caller]
    | ^^^^^^^^^^^^^^^
 
 error[E0736]: cannot use `#[track_caller]` with `#[naked]`
-  --> $DIR/error-with-naked.rs:10:5
+  --> $DIR/error-with-naked.rs:12:5
    |
 LL |     #[track_caller]
    |     ^^^^^^^^^^^^^^^