about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-10-06 21:51:18 +0000
committerbors <bors@rust-lang.org>2024-10-06 21:51:18 +0000
commit1b3b8e7b0265162853c650ead09905bc3cdaeae9 (patch)
treedd08cfa972234cc2bfcb8339fcdcaacfb8a6b995 /compiler
parent55a22d2a63334e0faff0202b72a31ce832b56125 (diff)
parent5fc60d1e52ea12f53d2c8d22fee94592860739ad (diff)
downloadrust-1b3b8e7b0265162853c650ead09905bc3cdaeae9.tar.gz
rust-1b3b8e7b0265162853c650ead09905bc3cdaeae9.zip
Auto merge of #128651 - folkertdev:naked-asm-macro-v2, r=Amanieu
add `naked_asm!` macro for use in `#[naked]` functions

tracking issue: https://github.com/rust-lang/rust/issues/90957

Adds the `core::arch::naked_asm` macro, to be used in `#[naked]` functions, but providing better error messages and a place to explain the restrictions on assembly in naked functions.

This PR does not yet require that the `naked_asm!` macro is used inside of `#[naked]` functions:

- the `asm!` macro can still be used in `#[naked]` functions currently, with the same restrictions and error messages as before.
- the `naked_asm!` macro can be used outside of `#[naked]` functions. It has not yet been decided whether that should be allowed long-term.

In this PR, the parsing code of `naked_asm!` now enforces the restrictions on assembly in naked functions, with the exception of checking that the `noreturn` option is specified. It also has not currently been decided if `noreturn` should be implicit or not.

This PR looks large because it touches a bunch of tests. The code changes are mostly straightforward I think: we now have 3 flavors of assembly macro, and that information must be propagated through the parsing code and error messages.

cc `@Lokathor`

r? `@Amanieu`
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/ast.rs28
-rw-r--r--compiler/rustc_borrowck/src/lib.rs1
-rw-r--r--compiler/rustc_borrowck/src/polonius/loan_invalidations.rs1
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl24
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs128
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs27
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs13
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0787.md5
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs2
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs6
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs6
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs24
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs1
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs1
-rw-r--r--compiler/rustc_middle/src/thir.rs3
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs19
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs1
-rw-r--r--compiler/rustc_passes/messages.ftl18
-rw-r--r--compiler/rustc_passes/src/errors.rs22
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs94
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs1
28 files changed, 244 insertions, 207 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 37f429cce44..733c2d93114 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2278,7 +2278,7 @@ impl InlineAsmOptions {
     pub const COUNT: usize = Self::all().bits().count_ones() as usize;
 
     pub const GLOBAL_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW);
-    pub const NAKED_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW).union(Self::NORETURN);
+    pub const NAKED_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW);
 
     pub fn human_readable_names(&self) -> Vec<&'static str> {
         let mut options = vec![];
@@ -2434,6 +2434,32 @@ pub enum AsmMacro {
     NakedAsm,
 }
 
+impl AsmMacro {
+    pub const fn macro_name(self) -> &'static str {
+        match self {
+            AsmMacro::Asm => "asm",
+            AsmMacro::GlobalAsm => "global_asm",
+            AsmMacro::NakedAsm => "naked_asm",
+        }
+    }
+
+    pub const fn is_supported_option(self, option: InlineAsmOptions) -> bool {
+        match self {
+            AsmMacro::Asm => true,
+            AsmMacro::GlobalAsm => InlineAsmOptions::GLOBAL_OPTIONS.contains(option),
+            AsmMacro::NakedAsm => InlineAsmOptions::NAKED_OPTIONS.contains(option),
+        }
+    }
+
+    pub const fn diverges(self, options: InlineAsmOptions) -> bool {
+        match self {
+            AsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN),
+            AsmMacro::GlobalAsm => true,
+            AsmMacro::NakedAsm => true,
+        }
+    }
+}
+
 /// Inline assembly.
 ///
 /// E.g., `asm!("NOP");`.
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 3b0b3ee1a74..fad4d790be4 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -742,6 +742,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
             }
 
             TerminatorKind::InlineAsm {
+                asm_macro: _,
                 template: _,
                 operands,
                 options: _,
diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
index afd811a0efb..d1b65943199 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
+++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
@@ -169,6 +169,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
                 }
             }
             TerminatorKind::InlineAsm {
+                asm_macro: _,
                 template: _,
                 operands,
                 options: _,
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 9695df9c87e..b25892242b5 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -12,9 +12,9 @@ builtin_macros_asm_duplicate_arg = duplicate argument named `{$name}`
 builtin_macros_asm_expected_comma = expected token: `,`
     .label = expected `,`
 
-builtin_macros_asm_expected_other = expected operand, {$is_global_asm ->
-    [true] options
-    *[false] clobber_abi, options
+builtin_macros_asm_expected_other = expected operand, {$is_inline_asm ->
+    [false] options
+    *[true] clobber_abi, options
     }, or additional template string
 
 builtin_macros_asm_expected_string_literal = expected string literal
@@ -51,6 +51,15 @@ builtin_macros_asm_sym_no_path = expected a path for argument to `sym`
 
 builtin_macros_asm_underscore_input = _ cannot be used for input operands
 
+builtin_macros_asm_unsupported_clobber_abi = `clobber_abi` cannot be used with `{$macro_name}!`
+
+builtin_macros_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `{$macro_name}!`
+    .label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it
+
+builtin_macros_asm_unsupported_option = the `{$symbol}` option cannot be used with `{$macro_name}!`
+    .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
+    .suggestion = remove this option
+
 builtin_macros_assert_missing_comma = unexpected string literal
     .suggestion = try adding a comma
 
@@ -194,15 +203,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments
 
 builtin_macros_format_use_positional = consider using a positional formatting argument instead
 
-builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
-
-builtin_macros_global_asm_unsupported_operand = the `{$symbol}` operand cannot be used with `global_asm!`
-    .label = the `{$symbol}` operand is not meaningful for global-scoped inline assembly, remove it
-
-builtin_macros_global_asm_unsupported_option = the `{$symbol}` option cannot be used with `global_asm!`
-    .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
-    .suggestion = remove this option
-
 builtin_macros_invalid_crate_attribute = invalid crate attribute
 
 builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 75dbb3d8e6a..9ae48024f44 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -37,15 +37,23 @@ pub struct AsmArgs {
 /// - `Ok(true)` if the current token matches the keyword, and was expected
 /// - `Ok(false)` if the current token does not match the keyword
 /// - `Err(_)` if the current token matches the keyword, but was not expected
-fn eat_operand_keyword<'a>(p: &mut Parser<'a>, symbol: Symbol, expect: bool) -> PResult<'a, bool> {
-    if expect {
+fn eat_operand_keyword<'a>(
+    p: &mut Parser<'a>,
+    symbol: Symbol,
+    asm_macro: AsmMacro,
+) -> PResult<'a, bool> {
+    if matches!(asm_macro, AsmMacro::Asm) {
         Ok(p.eat_keyword(symbol))
     } else {
         let span = p.token.span;
         if p.eat_keyword_noexpect(symbol) {
             // in gets printed as `r#in` otherwise
             let symbol = if symbol == kw::In { "in" } else { symbol.as_str() };
-            Err(p.dcx().create_err(errors::GlobalAsmUnsupportedOperand { span, symbol }))
+            Err(p.dcx().create_err(errors::AsmUnsupportedOperand {
+                span,
+                symbol,
+                macro_name: asm_macro.macro_name(),
+            }))
         } else {
             Ok(false)
         }
@@ -56,10 +64,10 @@ fn parse_args<'a>(
     ecx: &ExtCtxt<'a>,
     sp: Span,
     tts: TokenStream,
-    is_global_asm: bool,
+    asm_macro: AsmMacro,
 ) -> PResult<'a, AsmArgs> {
     let mut p = ecx.new_parser_from_tts(tts);
-    parse_asm_args(&mut p, sp, is_global_asm)
+    parse_asm_args(&mut p, sp, asm_macro)
 }
 
 // Primarily public for rustfmt consumption.
@@ -67,7 +75,7 @@ fn parse_args<'a>(
 pub fn parse_asm_args<'a>(
     p: &mut Parser<'a>,
     sp: Span,
-    is_global_asm: bool,
+    asm_macro: AsmMacro,
 ) -> PResult<'a, AsmArgs> {
     let dcx = p.dcx();
 
@@ -110,7 +118,7 @@ pub fn parse_asm_args<'a>(
 
         // Parse options
         if p.eat_keyword(sym::options) {
-            parse_options(p, &mut args, is_global_asm)?;
+            parse_options(p, &mut args, asm_macro)?;
             allow_templates = false;
             continue;
         }
@@ -129,7 +137,7 @@ pub fn parse_asm_args<'a>(
         };
 
         let mut explicit_reg = false;
-        let op = if eat_operand_keyword(p, kw::In, !is_global_asm)? {
+        let op = if eat_operand_keyword(p, kw::In, asm_macro)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -137,15 +145,15 @@ pub fn parse_asm_args<'a>(
             }
             let expr = p.parse_expr()?;
             ast::InlineAsmOperand::In { reg, expr }
-        } else if eat_operand_keyword(p, sym::out, !is_global_asm)? {
+        } else if eat_operand_keyword(p, sym::out, asm_macro)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: false }
-        } else if eat_operand_keyword(p, sym::lateout, !is_global_asm)? {
+        } else if eat_operand_keyword(p, sym::lateout, asm_macro)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: true }
-        } else if eat_operand_keyword(p, sym::inout, !is_global_asm)? {
+        } else if eat_operand_keyword(p, sym::inout, asm_macro)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -159,7 +167,7 @@ pub fn parse_asm_args<'a>(
             } else {
                 ast::InlineAsmOperand::InOut { reg, expr, late: false }
             }
-        } else if eat_operand_keyword(p, sym::inlateout, !is_global_asm)? {
+        } else if eat_operand_keyword(p, sym::inlateout, asm_macro)? {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
                 let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@@ -173,7 +181,7 @@ pub fn parse_asm_args<'a>(
             } else {
                 ast::InlineAsmOperand::InOut { reg, expr, late: true }
             }
-        } else if eat_operand_keyword(p, sym::label, !is_global_asm)? {
+        } else if eat_operand_keyword(p, sym::label, asm_macro)? {
             let block = p.parse_block()?;
             ast::InlineAsmOperand::Label { block }
         } else if p.eat_keyword(kw::Const) {
@@ -205,7 +213,7 @@ pub fn parse_asm_args<'a>(
                 _ => {
                     let err = dcx.create_err(errors::AsmExpectedOther {
                         span: template.span,
-                        is_global_asm,
+                        is_inline_asm: matches!(asm_macro, AsmMacro::Asm),
                     });
                     return Err(err);
                 }
@@ -301,20 +309,25 @@ pub fn parse_asm_args<'a>(
         dcx.emit_err(errors::AsmMayUnwind { labels_sp });
     }
 
-    if args.clobber_abis.len() > 0 {
-        if is_global_asm {
-            let err = dcx.create_err(errors::GlobalAsmClobberAbi {
-                spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
-            });
+    if !args.clobber_abis.is_empty() {
+        match asm_macro {
+            AsmMacro::GlobalAsm | AsmMacro::NakedAsm => {
+                let err = dcx.create_err(errors::AsmUnsupportedClobberAbi {
+                    spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
+                    macro_name: asm_macro.macro_name(),
+                });
 
-            // Bail out now since this is likely to confuse later stages
-            return Err(err);
-        }
-        if !regclass_outputs.is_empty() {
-            dcx.emit_err(errors::AsmClobberNoReg {
-                spans: regclass_outputs,
-                clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
-            });
+                // Bail out now since this is likely to confuse later stages
+                return Err(err);
+            }
+            AsmMacro::Asm => {
+                if !regclass_outputs.is_empty() {
+                    dcx.emit_err(errors::AsmClobberNoReg {
+                        spans: regclass_outputs,
+                        clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
+                    });
+                }
+            }
         }
     }
 
@@ -335,10 +348,15 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
 ///
 /// This function must be called immediately after the option token is parsed.
 /// Otherwise, the suggestion will be incorrect.
-fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
+fn err_unsupported_option(p: &Parser<'_>, asm_macro: AsmMacro, symbol: Symbol, span: Span) {
     // Tool-only output
     let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span };
-    p.dcx().emit_err(errors::GlobalAsmUnsupportedOption { span, symbol, full_span });
+    p.dcx().emit_err(errors::AsmUnsupportedOption {
+        span,
+        symbol,
+        full_span,
+        macro_name: asm_macro.macro_name(),
+    });
 }
 
 /// Try to set the provided option in the provided `AsmArgs`.
@@ -349,12 +367,12 @@ fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
 fn try_set_option<'a>(
     p: &Parser<'a>,
     args: &mut AsmArgs,
-    is_global_asm: bool,
+    asm_macro: AsmMacro,
     symbol: Symbol,
     option: ast::InlineAsmOptions,
 ) {
-    if is_global_asm && !ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) {
-        err_unsupported_option(p, symbol, p.prev_token.span);
+    if !asm_macro.is_supported_option(option) {
+        err_unsupported_option(p, asm_macro, symbol, p.prev_token.span);
     } else if args.options.contains(option) {
         err_duplicate_option(p, symbol, p.prev_token.span);
     } else {
@@ -365,7 +383,7 @@ fn try_set_option<'a>(
 fn parse_options<'a>(
     p: &mut Parser<'a>,
     args: &mut AsmArgs,
-    is_global_asm: bool,
+    asm_macro: AsmMacro,
 ) -> PResult<'a, ()> {
     let span_start = p.prev_token.span;
 
@@ -386,15 +404,14 @@ fn parse_options<'a>(
 
         'blk: {
             for (symbol, option) in OPTIONS {
-                let kw_matched =
-                    if !is_global_asm || ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) {
-                        p.eat_keyword(symbol)
-                    } else {
-                        p.eat_keyword_noexpect(symbol)
-                    };
+                let kw_matched = if asm_macro.is_supported_option(option) {
+                    p.eat_keyword(symbol)
+                } else {
+                    p.eat_keyword_noexpect(symbol)
+                };
 
                 if kw_matched {
-                    try_set_option(p, args, is_global_asm, symbol, option);
+                    try_set_option(p, args, asm_macro, symbol, option);
                     break 'blk;
                 }
             }
@@ -483,7 +500,7 @@ fn parse_reg<'a>(
 
 fn expand_preparsed_asm(
     ecx: &mut ExtCtxt<'_>,
-    asm_macro: ast::AsmMacro,
+    asm_macro: AsmMacro,
     args: AsmArgs,
 ) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
     let mut template = vec![];
@@ -797,7 +814,7 @@ pub(super) fn expand_asm<'cx>(
     sp: Span,
     tts: TokenStream,
 ) -> MacroExpanderResult<'cx> {
-    ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
+    ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::Asm) {
         Ok(args) => {
             let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::Asm, args) else {
                 return ExpandResult::Retry(());
@@ -826,29 +843,20 @@ pub(super) fn expand_naked_asm<'cx>(
     sp: Span,
     tts: TokenStream,
 ) -> MacroExpanderResult<'cx> {
-    ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
+    ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::NakedAsm) {
         Ok(args) => {
             let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::NakedAsm, args)
             else {
                 return ExpandResult::Retry(());
             };
             let expr = match mac {
-                Ok(mut inline_asm) => {
-                    // for future compatibility, we always set the NORETURN option.
-                    //
-                    // When we turn `asm!` into `naked_asm!` with this implementation, we can drop
-                    // the `options(noreturn)`, which makes the upgrade smooth when `naked_asm!`
-                    // starts disallowing the `noreturn` option in the future
-                    inline_asm.options |= ast::InlineAsmOptions::NORETURN;
-
-                    P(ast::Expr {
-                        id: ast::DUMMY_NODE_ID,
-                        kind: ast::ExprKind::InlineAsm(P(inline_asm)),
-                        span: sp,
-                        attrs: ast::AttrVec::new(),
-                        tokens: None,
-                    })
-                }
+                Ok(inline_asm) => P(ast::Expr {
+                    id: ast::DUMMY_NODE_ID,
+                    kind: ast::ExprKind::InlineAsm(P(inline_asm)),
+                    span: sp,
+                    attrs: ast::AttrVec::new(),
+                    tokens: None,
+                }),
                 Err(guar) => DummyResult::raw_expr(sp, Some(guar)),
             };
             MacEager::expr(expr)
@@ -865,7 +873,7 @@ pub(super) fn expand_global_asm<'cx>(
     sp: Span,
     tts: TokenStream,
 ) -> MacroExpanderResult<'cx> {
-    ExpandResult::Ready(match parse_args(ecx, sp, tts, true) {
+    ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::GlobalAsm) {
         Ok(args) => {
             let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::GlobalAsm, args)
             else {
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 4fffffb91c8..f13ca224a45 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -751,7 +751,7 @@ pub(crate) struct AsmExpectedOther {
     #[primary_span]
     #[label(builtin_macros_asm_expected_other)]
     pub(crate) span: Span,
-    pub(crate) is_global_asm: bool,
+    pub(crate) is_inline_asm: bool,
 }
 
 #[derive(Diagnostic)]
@@ -799,13 +799,6 @@ pub(crate) struct AsmMayUnwind {
     pub(crate) labels_sp: Vec<Span>,
 }
 
-#[derive(Diagnostic)]
-#[diag(builtin_macros_global_asm_clobber_abi)]
-pub(crate) struct GlobalAsmClobberAbi {
-    #[primary_span]
-    pub(crate) spans: Vec<Span>,
-}
-
 pub(crate) struct AsmClobberNoReg {
     pub(crate) spans: Vec<Span>,
     pub(crate) clobbers: Vec<Span>,
@@ -841,23 +834,33 @@ pub(crate) struct AsmOptAlreadyprovided {
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros_global_asm_unsupported_option)]
-pub(crate) struct GlobalAsmUnsupportedOption {
+#[diag(builtin_macros_asm_unsupported_option)]
+pub(crate) struct AsmUnsupportedOption {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
     pub(crate) symbol: Symbol,
     #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
     pub(crate) full_span: Span,
+    pub(crate) macro_name: &'static str,
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros_global_asm_unsupported_operand)]
-pub(crate) struct GlobalAsmUnsupportedOperand<'a> {
+#[diag(builtin_macros_asm_unsupported_operand)]
+pub(crate) struct AsmUnsupportedOperand<'a> {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
     pub(crate) symbol: &'a str,
+    pub(crate) macro_name: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_unsupported_clobber_abi)]
+pub(crate) struct AsmUnsupportedClobberAbi {
+    #[primary_span]
+    pub(crate) spans: Vec<Span>,
+    pub(crate) macro_name: &'static str,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 5e535ff62e1..9fc0318df5d 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -726,6 +726,12 @@ pub macro global_asm() {
     /* compiler built-in */
 }
 
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro naked_asm() {
+    /* compiler built-in */
+}
+
 pub static A_STATIC: u8 = 42;
 
 #[lang = "panic_location"]
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index ccbd5a78485..e47431e0f87 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -390,7 +390,7 @@ global_asm! {
 #[naked]
 extern "C" fn naked_test() {
     unsafe {
-        asm!("ret", options(noreturn));
+        naked_asm!("ret");
     }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 09680622069..a681e6d9f3c 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -8,6 +8,7 @@ use rustc_ast::InlineAsmOptions;
 use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
 use rustc_index::IndexVec;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::mir::InlineAsmMacro;
 use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::layout::FnAbiOf;
@@ -57,6 +58,7 @@ pub(crate) fn codegen_fn<'tcx>(
 
         match &mir.basic_blocks[START_BLOCK].terminator().kind {
             TerminatorKind::InlineAsm {
+                asm_macro: InlineAsmMacro::NakedAsm,
                 template,
                 operands,
                 options,
@@ -498,6 +500,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                 "tail calls are not yet supported in `rustc_codegen_cranelift` backend"
             ),
             TerminatorKind::InlineAsm {
+                asm_macro: _,
                 template,
                 operands,
                 options,
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 125d3b908c7..be9a6d9a90e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -3,7 +3,9 @@ use std::cmp;
 use rustc_ast as ast;
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_hir::lang_items::LangItem;
-use rustc_middle::mir::{self, AssertKind, BasicBlock, SwitchTargets, UnwindTerminateReason};
+use rustc_middle::mir::{
+    self, AssertKind, BasicBlock, InlineAsmMacro, SwitchTargets, UnwindTerminateReason,
+};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Instance, Ty};
@@ -1133,6 +1135,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         &mut self,
         helper: TerminatorCodegenHelper<'tcx>,
         bx: &mut Bx,
+        asm_macro: InlineAsmMacro,
         terminator: &mir::Terminator<'tcx>,
         template: &[ast::InlineAsmTemplatePiece],
         operands: &[mir::InlineAsmOperand<'tcx>],
@@ -1203,11 +1206,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             &operands,
             options,
             line_spans,
-            if options.contains(InlineAsmOptions::NORETURN) {
-                None
-            } else {
-                targets.get(0).copied()
-            },
+            if asm_macro.diverges(options) { None } else { targets.get(0).copied() },
             unwind,
             instance,
             mergeable_succ,
@@ -1381,6 +1380,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
 
             mir::TerminatorKind::InlineAsm {
+                asm_macro,
                 template,
                 ref operands,
                 options,
@@ -1390,6 +1390,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             } => self.codegen_asm_terminator(
                 helper,
                 bx,
+                asm_macro,
                 terminator,
                 template,
                 operands,
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 0f796c31222..89d49ba046e 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -395,7 +395,7 @@ pub trait Machine<'tcx>: Sized {
     ///
     /// This should take care of jumping to the next block (one of `targets`) when asm goto
     /// is triggered, `targets[0]` when the assembly falls through, or diverge in case of
-    /// `InlineAsmOptions::NORETURN` being set.
+    /// naked_asm! or `InlineAsmOptions::NORETURN` being set.
     fn eval_inline_asm(
         _ecx: &mut InterpCx<'tcx, Self>,
         _template: &'tcx [InlineAsmTemplatePiece],
diff --git a/compiler/rustc_error_codes/src/error_codes/E0787.md b/compiler/rustc_error_codes/src/error_codes/E0787.md
index cee50829270..f5c5faa066b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0787.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0787.md
@@ -11,11 +11,10 @@ pub extern "C" fn f() -> u32 {
 }
 ```
 
-The naked functions must be defined using a single inline assembly
-block.
+The naked function must be defined using a single `naked_asm!` 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
+code, so it must either return or diverge. The asm block can also
 use `att_syntax` and `raw` options, but others options are not allowed.
 
 The asm block must not contain any operands other than `const` and
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 2d718295374..95ca3e66472 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -3507,7 +3507,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> {
-        let mut diverge = asm.options.contains(ast::InlineAsmOptions::NORETURN);
+        let mut diverge = asm.asm_macro.diverges(asm.options);
 
         for (op, _op_sp) in asm.operands {
             match op {
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index e1b710b72f6..a123059df8f 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2925,16 +2925,16 @@ declare_lint! {
     /// ```rust
     /// #![feature(asm_experimental_arch, naked_functions)]
     ///
-    /// use std::arch::asm;
+    /// use std::arch::naked_asm;
     ///
     /// #[naked]
     /// pub fn default_abi() -> u32 {
-    ///     unsafe { asm!("", options(noreturn)); }
+    ///     unsafe { naked_asm!(""); }
     /// }
     ///
     /// #[naked]
     /// pub extern "Rust" fn rust_abi() -> u32 {
-    ///     unsafe { asm!("", options(noreturn)); }
+    ///     unsafe { naked_asm!(""); }
     /// }
     /// ```
     ///
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 48789565218..9cafe804a8e 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -4,7 +4,7 @@ use std::fs;
 use std::io::{self, Write as _};
 use std::path::{Path, PathBuf};
 
-use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_ast::InlineAsmTemplatePiece;
 use rustc_middle::mir::interpret::{
     AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer, Provenance, alloc_range,
     read_target_uint,
@@ -1024,9 +1024,9 @@ impl<'tcx> TerminatorKind<'tcx> {
                 vec!["real".into(), "unwind".into()]
             }
             FalseUnwind { unwind: _, .. } => vec!["real".into()],
-            InlineAsm { options, ref targets, unwind, .. } => {
+            InlineAsm { asm_macro, options, ref targets, unwind, .. } => {
                 let mut vec = Vec::with_capacity(targets.len() + 1);
-                if !options.contains(InlineAsmOptions::NORETURN) {
+                if !asm_macro.diverges(options) {
                     vec.push("return".into());
                 }
                 vec.resize(targets.len(), "label".into());
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 1722a7a1f35..c610fac80f6 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -605,6 +605,25 @@ impl CallSource {
     }
 }
 
+#[derive(Clone, Copy, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
+#[derive(TypeFoldable, TypeVisitable)]
+/// The macro that an inline assembly block was created by
+pub enum InlineAsmMacro {
+    /// The `asm!` macro
+    Asm,
+    /// The `naked_asm!` macro
+    NakedAsm,
+}
+
+impl InlineAsmMacro {
+    pub const fn diverges(self, options: InlineAsmOptions) -> bool {
+        match self {
+            InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN),
+            InlineAsmMacro::NakedAsm => true,
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // Terminators
 
@@ -859,6 +878,9 @@ pub enum TerminatorKind<'tcx> {
     /// Block ends with an inline assembly block. This is a terminator since
     /// inline assembly is allowed to diverge.
     InlineAsm {
+        /// Macro used to create this inline asm: one of `asm!` or `naked_asm!`
+        asm_macro: InlineAsmMacro,
+
         /// The template for the inline assembly, with placeholders.
         template: &'tcx [InlineAsmTemplatePiece],
 
@@ -874,7 +896,7 @@ pub enum TerminatorKind<'tcx> {
 
         /// Valid targets for the inline assembly.
         /// The first element is the fallthrough destination, unless
-        /// InlineAsmOptions::NORETURN is set.
+        /// asm_macro == InlineAsmMacro::NakedAsm or InlineAsmOptions::NORETURN is set.
         targets: Box<[BasicBlock]>,
 
         /// Action to be taken if the inline assembly unwinds. This is present
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 783952fb9cb..b919f5726db 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -666,6 +666,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             },
 
             InlineAsm {
+                asm_macro: _,
                 template: _,
                 ref operands,
                 options: _,
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 64898a8495e..9f9ee8497b6 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -576,6 +576,7 @@ macro_rules! make_mir_visitor {
                     }
 
                     TerminatorKind::InlineAsm {
+                        asm_macro: _,
                         template: _,
                         operands,
                         options: _,
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index e614d41899a..fe865b8a515 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -12,7 +12,7 @@ use std::cmp::Ordering;
 use std::fmt;
 use std::ops::Index;
 
-use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_ast::{AsmMacro, InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd};
@@ -173,6 +173,7 @@ pub struct ClosureExpr<'tcx> {
 
 #[derive(Clone, Debug, HashStable)]
 pub struct InlineAsmExpr<'tcx> {
+    pub asm_macro: AsmMacro,
     pub template: &'tcx [InlineAsmTemplatePiece],
     pub operands: Box<[InlineAsmOperand<'tcx>]>,
     pub options: InlineAsmOptions,
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 58e2ebaeaf8..36f0e3d890c 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -148,7 +148,13 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
         NamedConst { def_id: _, args: _, user_ty: _ } => {}
         ConstParam { param: _, def_id: _ } => {}
         StaticRef { alloc_id: _, ty: _, def_id: _ } => {}
-        InlineAsm(box InlineAsmExpr { ref operands, template: _, options: _, line_spans: _ }) => {
+        InlineAsm(box InlineAsmExpr {
+            asm_macro: _,
+            ref operands,
+            template: _,
+            options: _,
+            line_spans: _,
+        }) => {
             for op in &**operands {
                 use InlineAsmOperand::*;
                 match op {
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 86fe447f399..dc317feb20c 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -2,7 +2,7 @@
 
 use std::iter;
 
-use rustc_ast::InlineAsmOptions;
+use rustc_ast::{AsmMacro, InlineAsmOptions};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
@@ -384,6 +384,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.unit()
             }
             ExprKind::InlineAsm(box InlineAsmExpr {
+                asm_macro,
                 template,
                 ref operands,
                 options,
@@ -392,11 +393,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 use rustc_middle::{mir, thir};
 
                 let destination_block = this.cfg.start_new_block();
-                let mut targets = if options.contains(InlineAsmOptions::NORETURN) {
-                    vec![]
-                } else {
-                    vec![destination_block]
-                };
+                let mut targets =
+                    if asm_macro.diverges(options) { vec![] } else { vec![destination_block] };
 
                 let operands = operands
                     .into_iter()
@@ -474,7 +472,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
                 }
 
+                let asm_macro = match asm_macro {
+                    AsmMacro::Asm => InlineAsmMacro::Asm,
+                    AsmMacro::GlobalAsm => {
+                        span_bug!(expr_span, "unexpected global_asm! in inline asm")
+                    }
+                    AsmMacro::NakedAsm => InlineAsmMacro::NakedAsm,
+                };
+
                 this.cfg.terminate(block, source_info, TerminatorKind::InlineAsm {
+                    asm_macro,
                     template,
                     operands,
                     options,
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 2ffad0b4834..abf486af962 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -672,6 +672,7 @@ impl<'tcx> Cx<'tcx> {
             }
 
             hir::ExprKind::InlineAsm(asm) => ExprKind::InlineAsm(Box::new(InlineAsmExpr {
+                asm_macro: asm.asm_macro,
                 template: asm.template,
                 operands: asm
                     .operands
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 61317925d09..dae13df4054 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -818,10 +818,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
     }
 
     fn print_inline_asm_expr(&mut self, expr: &InlineAsmExpr<'tcx>, depth_lvl: usize) {
-        let InlineAsmExpr { template, operands, options, line_spans } = expr;
+        let InlineAsmExpr { asm_macro, template, operands, options, line_spans } = expr;
 
         print_indented!(self, "InlineAsmExpr {", depth_lvl);
 
+        print_indented!(self, format!("asm_macro: {:?}", asm_macro), depth_lvl + 1);
+
         print_indented!(self, "template: [", depth_lvl + 1);
         for template_piece in template.iter() {
             print_indented!(self, format!("{:?}", template_piece), depth_lvl + 2);
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 3c8be2f73e1..162245cb950 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -481,6 +481,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
                 }
             }
             TerminatorKind::InlineAsm {
+                asm_macro: _,
                 template: _,
                 ref operands,
                 options: _,
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index f2682acf8aa..be76d6cef2b 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -488,24 +488,18 @@ passes_naked_asm_outside_naked_fn =
     the `naked_asm!` macro can only be used in functions marked with `#[naked]`
 
 passes_naked_functions_asm_block =
-    naked functions must contain a single asm block
-    .label_multiple_asm = multiple asm blocks are unsupported in naked functions
-    .label_non_asm = non-asm is unsupported in naked functions
-
-passes_naked_functions_asm_options =
-    asm options unsupported in naked functions: {$unsupported_options}
+    naked functions must contain a single `naked_asm!` invocation
+    .label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions
+    .label_non_asm = not allowed in naked functions
 
 passes_naked_functions_incompatible_attribute =
     attribute incompatible with `#[naked]`
     .label = the `{$attr}` attribute is incompatible with `#[naked]`
     .naked_attribute = function marked with `#[naked]` here
 
-passes_naked_functions_must_use_noreturn =
-    asm in naked functions must use `noreturn` option
-    .suggestion = consider specifying that the asm block is responsible for returning from the function
-
-passes_naked_functions_operands =
-    only `const` and `sym` operands are supported in naked functions
+passes_naked_functions_must_naked_asm =
+    the `asm!` macro is not allowed in naked functions
+    .label = consider using the `naked_asm!` macro instead
 
 passes_no_link =
     attribute should be applied to an `extern crate` item
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 29a087bf759..4f00c90fa3b 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1187,27 +1187,11 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for NakedFunctionsAsmBlock {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_naked_functions_operands, code = E0787)]
-pub(crate) struct NakedFunctionsOperands {
-    #[primary_span]
-    pub unsupported_operands: Vec<Span>,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_naked_functions_asm_options, code = E0787)]
-pub(crate) struct NakedFunctionsAsmOptions {
-    #[primary_span]
-    pub span: Span,
-    pub unsupported_options: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_naked_functions_must_use_noreturn, code = E0787)]
-pub(crate) struct NakedFunctionsMustUseNoreturn {
+#[diag(passes_naked_functions_must_naked_asm, code = E0787)]
+pub(crate) struct NakedFunctionsMustNakedAsm {
     #[primary_span]
+    #[label]
     pub span: Span,
-    #[suggestion(code = ", options(noreturn)", applicability = "machine-applicable")]
-    pub last_span: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 8d3f7e0231f..b2f8d7dadff 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -1,13 +1,13 @@
 //! Checks validity of naked functions.
 
-use rustc_ast::InlineAsmOptions;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{LocalDefId, LocalModDefId};
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{ExprKind, HirIdSet, InlineAsmOperand, StmtKind};
+use rustc_hir::{ExprKind, HirIdSet, StmtKind};
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::query::Providers;
+use rustc_middle::span_bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
 use rustc_span::Span;
@@ -15,9 +15,8 @@ use rustc_span::symbol::sym;
 use rustc_target::spec::abi::Abi;
 
 use crate::errors::{
-    NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions,
-    NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed,
-    UndefinedNakedFunctionAbi,
+    NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns,
+    ParamsNotAllowed, UndefinedNakedFunctionAbi,
 };
 
 pub(crate) fn provide(providers: &mut Providers) {
@@ -119,23 +118,28 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
 
 /// Checks that function body contains a single inline assembly block.
 fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) {
-    let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
+    let mut this = CheckInlineAssembly { items: Vec::new() };
     this.visit_body(body);
-    if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
+    if let [(ItemKind::NakedAsm | ItemKind::Err, _)] = this.items[..] {
         // Ok.
     } else {
         let mut must_show_error = false;
-        let mut has_asm = false;
+        let mut has_naked_asm = false;
         let mut has_err = false;
         let mut multiple_asms = vec![];
         let mut non_asms = vec![];
         for &(kind, span) in &this.items {
             match kind {
-                ItemKind::Asm if has_asm => {
+                ItemKind::NakedAsm if has_naked_asm => {
                     must_show_error = true;
                     multiple_asms.push(span);
                 }
-                ItemKind::Asm => has_asm = true,
+                ItemKind::NakedAsm => has_naked_asm = true,
+                ItemKind::InlineAsm => {
+                    has_err = true;
+
+                    tcx.dcx().emit_err(NakedFunctionsMustNakedAsm { span });
+                }
                 ItemKind::NonAsm => {
                     must_show_error = true;
                     non_asms.push(span);
@@ -157,20 +161,20 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<
     }
 }
 
-struct CheckInlineAssembly<'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct CheckInlineAssembly {
     items: Vec<(ItemKind, Span)>,
 }
 
 #[derive(Copy, Clone)]
 enum ItemKind {
-    Asm,
+    NakedAsm,
+    InlineAsm,
     NonAsm,
     Err,
 }
 
-impl<'tcx> CheckInlineAssembly<'tcx> {
-    fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) {
+impl CheckInlineAssembly {
+    fn check_expr<'tcx>(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) {
         match expr.kind {
             ExprKind::ConstBlock(..)
             | ExprKind::Array(..)
@@ -204,10 +208,17 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
                 self.items.push((ItemKind::NonAsm, span));
             }
 
-            ExprKind::InlineAsm(asm) => {
-                self.items.push((ItemKind::Asm, span));
-                self.check_inline_asm(asm, span);
-            }
+            ExprKind::InlineAsm(asm) => match asm.asm_macro {
+                rustc_ast::AsmMacro::Asm => {
+                    self.items.push((ItemKind::InlineAsm, span));
+                }
+                rustc_ast::AsmMacro::NakedAsm => {
+                    self.items.push((ItemKind::NakedAsm, span));
+                }
+                rustc_ast::AsmMacro::GlobalAsm => {
+                    span_bug!(span, "`global_asm!` is not allowed in this position")
+                }
+            },
 
             ExprKind::DropTemps(..) | ExprKind::Block(..) => {
                 hir::intravisit::walk_expr(self, expr);
@@ -218,52 +229,9 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
             }
         }
     }
-
-    fn check_inline_asm(&self, 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::SymFn { .. }
-                | InlineAsmOperand::SymStatic { .. } => None,
-                InlineAsmOperand::In { .. }
-                | InlineAsmOperand::Out { .. }
-                | InlineAsmOperand::InOut { .. }
-                | InlineAsmOperand::SplitInOut { .. }
-                | InlineAsmOperand::Label { .. } => Some(op_sp),
-            })
-            .collect();
-        if !unsupported_operands.is_empty() {
-            self.tcx.dcx().emit_err(NakedFunctionsOperands { unsupported_operands });
-        }
-
-        let unsupported_options = asm.options.difference(InlineAsmOptions::NAKED_OPTIONS);
-        if !unsupported_options.is_empty() {
-            self.tcx.dcx().emit_err(NakedFunctionsAsmOptions {
-                span,
-                unsupported_options: unsupported_options
-                    .human_readable_names()
-                    .into_iter()
-                    .map(|name| format!("`{name}`"))
-                    .collect::<Vec<_>>()
-                    .join(", "),
-            });
-        }
-
-        if !asm.options.contains(InlineAsmOptions::NORETURN) {
-            let last_span = asm
-                .operands
-                .last()
-                .map_or_else(|| asm.template_strs.last().unwrap().2, |op| op.1)
-                .shrink_to_hi();
-
-            self.tcx.dcx().emit_err(NakedFunctionsMustUseNoreturn { span, last_span });
-        }
-    }
 }
 
-impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> {
+impl<'tcx> Visitor<'tcx> for CheckInlineAssembly {
     fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
         match stmt.kind {
             StmtKind::Item(..) => {}
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index 0dbbc338e73..dbae4b7e719 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -655,6 +655,7 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
                 }
             }
             mir::TerminatorKind::InlineAsm {
+                asm_macro: _,
                 template,
                 operands,
                 options,