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`
This commit is contained in:
bors 2024-10-06 21:51:18 +00:00
commit 1b3b8e7b02
56 changed files with 552 additions and 520 deletions

View File

@ -2278,7 +2278,7 @@ impl InlineAsmOptions {
pub const COUNT: usize = Self::all().bits().count_ones() as usize; pub const COUNT: usize = Self::all().bits().count_ones() as usize;
pub const GLOBAL_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW); 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> { pub fn human_readable_names(&self) -> Vec<&'static str> {
let mut options = vec![]; let mut options = vec![];
@ -2434,6 +2434,32 @@ pub enum AsmMacro {
NakedAsm, 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. /// Inline assembly.
/// ///
/// E.g., `asm!("NOP");`. /// E.g., `asm!("NOP");`.

View File

@ -742,6 +742,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
} }
TerminatorKind::InlineAsm { TerminatorKind::InlineAsm {
asm_macro: _,
template: _, template: _,
operands, operands,
options: _, options: _,

View File

@ -169,6 +169,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
} }
} }
TerminatorKind::InlineAsm { TerminatorKind::InlineAsm {
asm_macro: _,
template: _, template: _,
operands, operands,
options: _, options: _,

View File

@ -12,9 +12,9 @@ builtin_macros_asm_duplicate_arg = duplicate argument named `{$name}`
builtin_macros_asm_expected_comma = expected token: `,` builtin_macros_asm_expected_comma = expected token: `,`
.label = expected `,` .label = expected `,`
builtin_macros_asm_expected_other = expected operand, {$is_global_asm -> builtin_macros_asm_expected_other = expected operand, {$is_inline_asm ->
[true] options [false] options
*[false] clobber_abi, options *[true] clobber_abi, options
}, or additional template string }, or additional template string
builtin_macros_asm_expected_string_literal = expected string literal 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_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 builtin_macros_assert_missing_comma = unexpected string literal
.suggestion = try adding a comma .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_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_invalid_crate_attribute = invalid crate attribute
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes builtin_macros_multiple_default_attrs = multiple `#[default]` attributes

View File

@ -37,15 +37,23 @@ pub struct AsmArgs {
/// - `Ok(true)` if the current token matches the keyword, and was expected /// - `Ok(true)` if the current token matches the keyword, and was expected
/// - `Ok(false)` if the current token does not match the keyword /// - `Ok(false)` if the current token does not match the keyword
/// - `Err(_)` if the current token matches the keyword, but was not expected /// - `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> { fn eat_operand_keyword<'a>(
if expect { p: &mut Parser<'a>,
symbol: Symbol,
asm_macro: AsmMacro,
) -> PResult<'a, bool> {
if matches!(asm_macro, AsmMacro::Asm) {
Ok(p.eat_keyword(symbol)) Ok(p.eat_keyword(symbol))
} else { } else {
let span = p.token.span; let span = p.token.span;
if p.eat_keyword_noexpect(symbol) { if p.eat_keyword_noexpect(symbol) {
// in gets printed as `r#in` otherwise // in gets printed as `r#in` otherwise
let symbol = if symbol == kw::In { "in" } else { symbol.as_str() }; 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 { } else {
Ok(false) Ok(false)
} }
@ -56,10 +64,10 @@ fn parse_args<'a>(
ecx: &ExtCtxt<'a>, ecx: &ExtCtxt<'a>,
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
is_global_asm: bool, asm_macro: AsmMacro,
) -> PResult<'a, AsmArgs> { ) -> PResult<'a, AsmArgs> {
let mut p = ecx.new_parser_from_tts(tts); 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. // Primarily public for rustfmt consumption.
@ -67,7 +75,7 @@ fn parse_args<'a>(
pub fn parse_asm_args<'a>( pub fn parse_asm_args<'a>(
p: &mut Parser<'a>, p: &mut Parser<'a>,
sp: Span, sp: Span,
is_global_asm: bool, asm_macro: AsmMacro,
) -> PResult<'a, AsmArgs> { ) -> PResult<'a, AsmArgs> {
let dcx = p.dcx(); let dcx = p.dcx();
@ -110,7 +118,7 @@ pub fn parse_asm_args<'a>(
// Parse options // Parse options
if p.eat_keyword(sym::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; allow_templates = false;
continue; continue;
} }
@ -129,7 +137,7 @@ pub fn parse_asm_args<'a>(
}; };
let mut explicit_reg = false; 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)?; let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) { if p.eat_keyword(kw::Underscore) {
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); 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()?; let expr = p.parse_expr()?;
ast::InlineAsmOperand::In { reg, 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 reg = parse_reg(p, &mut explicit_reg)?;
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::Out { reg, expr, late: false } 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 reg = parse_reg(p, &mut explicit_reg)?;
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) }; let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::Out { reg, expr, late: true } 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)?; let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) { if p.eat_keyword(kw::Underscore) {
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@ -159,7 +167,7 @@ pub fn parse_asm_args<'a>(
} else { } else {
ast::InlineAsmOperand::InOut { reg, expr, late: false } 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)?; let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) { if p.eat_keyword(kw::Underscore) {
let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span }); let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
@ -173,7 +181,7 @@ pub fn parse_asm_args<'a>(
} else { } else {
ast::InlineAsmOperand::InOut { reg, expr, late: true } 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()?; let block = p.parse_block()?;
ast::InlineAsmOperand::Label { block } ast::InlineAsmOperand::Label { block }
} else if p.eat_keyword(kw::Const) { } else if p.eat_keyword(kw::Const) {
@ -205,7 +213,7 @@ pub fn parse_asm_args<'a>(
_ => { _ => {
let err = dcx.create_err(errors::AsmExpectedOther { let err = dcx.create_err(errors::AsmExpectedOther {
span: template.span, span: template.span,
is_global_asm, is_inline_asm: matches!(asm_macro, AsmMacro::Asm),
}); });
return Err(err); return Err(err);
} }
@ -301,20 +309,25 @@ pub fn parse_asm_args<'a>(
dcx.emit_err(errors::AsmMayUnwind { labels_sp }); dcx.emit_err(errors::AsmMayUnwind { labels_sp });
} }
if args.clobber_abis.len() > 0 { if !args.clobber_abis.is_empty() {
if is_global_asm { match asm_macro {
let err = dcx.create_err(errors::GlobalAsmClobberAbi { AsmMacro::GlobalAsm | AsmMacro::NakedAsm => {
spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(), 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 // Bail out now since this is likely to confuse later stages
return Err(err); return Err(err);
} }
if !regclass_outputs.is_empty() { AsmMacro::Asm => {
dcx.emit_err(errors::AsmClobberNoReg { if !regclass_outputs.is_empty() {
spans: regclass_outputs, dcx.emit_err(errors::AsmClobberNoReg {
clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(), 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. /// This function must be called immediately after the option token is parsed.
/// Otherwise, the suggestion will be incorrect. /// 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 // Tool-only output
let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span }; 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`. /// 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>( fn try_set_option<'a>(
p: &Parser<'a>, p: &Parser<'a>,
args: &mut AsmArgs, args: &mut AsmArgs,
is_global_asm: bool, asm_macro: AsmMacro,
symbol: Symbol, symbol: Symbol,
option: ast::InlineAsmOptions, option: ast::InlineAsmOptions,
) { ) {
if is_global_asm && !ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) { if !asm_macro.is_supported_option(option) {
err_unsupported_option(p, symbol, p.prev_token.span); err_unsupported_option(p, asm_macro, symbol, p.prev_token.span);
} else if args.options.contains(option) { } else if args.options.contains(option) {
err_duplicate_option(p, symbol, p.prev_token.span); err_duplicate_option(p, symbol, p.prev_token.span);
} else { } else {
@ -365,7 +383,7 @@ fn try_set_option<'a>(
fn parse_options<'a>( fn parse_options<'a>(
p: &mut Parser<'a>, p: &mut Parser<'a>,
args: &mut AsmArgs, args: &mut AsmArgs,
is_global_asm: bool, asm_macro: AsmMacro,
) -> PResult<'a, ()> { ) -> PResult<'a, ()> {
let span_start = p.prev_token.span; let span_start = p.prev_token.span;
@ -386,15 +404,14 @@ fn parse_options<'a>(
'blk: { 'blk: {
for (symbol, option) in OPTIONS { for (symbol, option) in OPTIONS {
let kw_matched = let kw_matched = if asm_macro.is_supported_option(option) {
if !is_global_asm || ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) { p.eat_keyword(symbol)
p.eat_keyword(symbol) } else {
} else { p.eat_keyword_noexpect(symbol)
p.eat_keyword_noexpect(symbol) };
};
if kw_matched { if kw_matched {
try_set_option(p, args, is_global_asm, symbol, option); try_set_option(p, args, asm_macro, symbol, option);
break 'blk; break 'blk;
} }
} }
@ -483,7 +500,7 @@ fn parse_reg<'a>(
fn expand_preparsed_asm( fn expand_preparsed_asm(
ecx: &mut ExtCtxt<'_>, ecx: &mut ExtCtxt<'_>,
asm_macro: ast::AsmMacro, asm_macro: AsmMacro,
args: AsmArgs, args: AsmArgs,
) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> { ) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
let mut template = vec![]; let mut template = vec![];
@ -797,7 +814,7 @@ pub(super) fn expand_asm<'cx>(
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> MacroExpanderResult<'cx> { ) -> MacroExpanderResult<'cx> {
ExpandResult::Ready(match parse_args(ecx, sp, tts, false) { ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::Asm) {
Ok(args) => { Ok(args) => {
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::Asm, args) else { let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::Asm, args) else {
return ExpandResult::Retry(()); return ExpandResult::Retry(());
@ -826,29 +843,20 @@ pub(super) fn expand_naked_asm<'cx>(
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> MacroExpanderResult<'cx> { ) -> MacroExpanderResult<'cx> {
ExpandResult::Ready(match parse_args(ecx, sp, tts, false) { ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::NakedAsm) {
Ok(args) => { Ok(args) => {
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::NakedAsm, args) let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::NakedAsm, args)
else { else {
return ExpandResult::Retry(()); return ExpandResult::Retry(());
}; };
let expr = match mac { let expr = match mac {
Ok(mut inline_asm) => { Ok(inline_asm) => P(ast::Expr {
// for future compatibility, we always set the NORETURN option. id: ast::DUMMY_NODE_ID,
// kind: ast::ExprKind::InlineAsm(P(inline_asm)),
// When we turn `asm!` into `naked_asm!` with this implementation, we can drop span: sp,
// the `options(noreturn)`, which makes the upgrade smooth when `naked_asm!` attrs: ast::AttrVec::new(),
// starts disallowing the `noreturn` option in the future tokens: None,
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,
})
}
Err(guar) => DummyResult::raw_expr(sp, Some(guar)), Err(guar) => DummyResult::raw_expr(sp, Some(guar)),
}; };
MacEager::expr(expr) MacEager::expr(expr)
@ -865,7 +873,7 @@ pub(super) fn expand_global_asm<'cx>(
sp: Span, sp: Span,
tts: TokenStream, tts: TokenStream,
) -> MacroExpanderResult<'cx> { ) -> MacroExpanderResult<'cx> {
ExpandResult::Ready(match parse_args(ecx, sp, tts, true) { ExpandResult::Ready(match parse_args(ecx, sp, tts, AsmMacro::GlobalAsm) {
Ok(args) => { Ok(args) => {
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::GlobalAsm, args) let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::GlobalAsm, args)
else { else {

View File

@ -751,7 +751,7 @@ pub(crate) struct AsmExpectedOther {
#[primary_span] #[primary_span]
#[label(builtin_macros_asm_expected_other)] #[label(builtin_macros_asm_expected_other)]
pub(crate) span: Span, pub(crate) span: Span,
pub(crate) is_global_asm: bool, pub(crate) is_inline_asm: bool,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
@ -799,13 +799,6 @@ pub(crate) struct AsmMayUnwind {
pub(crate) labels_sp: Vec<Span>, 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) struct AsmClobberNoReg {
pub(crate) spans: Vec<Span>, pub(crate) spans: Vec<Span>,
pub(crate) clobbers: Vec<Span>, pub(crate) clobbers: Vec<Span>,
@ -841,23 +834,33 @@ pub(crate) struct AsmOptAlreadyprovided {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(builtin_macros_global_asm_unsupported_option)] #[diag(builtin_macros_asm_unsupported_option)]
pub(crate) struct GlobalAsmUnsupportedOption { pub(crate) struct AsmUnsupportedOption {
#[primary_span] #[primary_span]
#[label] #[label]
pub(crate) span: Span, pub(crate) span: Span,
pub(crate) symbol: Symbol, pub(crate) symbol: Symbol,
#[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
pub(crate) full_span: Span, pub(crate) full_span: Span,
pub(crate) macro_name: &'static str,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(builtin_macros_global_asm_unsupported_operand)] #[diag(builtin_macros_asm_unsupported_operand)]
pub(crate) struct GlobalAsmUnsupportedOperand<'a> { pub(crate) struct AsmUnsupportedOperand<'a> {
#[primary_span] #[primary_span]
#[label] #[label]
pub(crate) span: Span, pub(crate) span: Span,
pub(crate) symbol: &'a str, 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)] #[derive(Diagnostic)]

View File

@ -726,6 +726,12 @@ pub macro global_asm() {
/* compiler built-in */ /* compiler built-in */
} }
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro naked_asm() {
/* compiler built-in */
}
pub static A_STATIC: u8 = 42; pub static A_STATIC: u8 = 42;
#[lang = "panic_location"] #[lang = "panic_location"]

View File

@ -390,7 +390,7 @@ global_asm! {
#[naked] #[naked]
extern "C" fn naked_test() { extern "C" fn naked_test() {
unsafe { unsafe {
asm!("ret", options(noreturn)); naked_asm!("ret");
} }
} }

View File

@ -8,6 +8,7 @@ use rustc_ast::InlineAsmOptions;
use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::InlineAsmMacro;
use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::layout::FnAbiOf;
@ -57,6 +58,7 @@ pub(crate) fn codegen_fn<'tcx>(
match &mir.basic_blocks[START_BLOCK].terminator().kind { match &mir.basic_blocks[START_BLOCK].terminator().kind {
TerminatorKind::InlineAsm { TerminatorKind::InlineAsm {
asm_macro: InlineAsmMacro::NakedAsm,
template, template,
operands, operands,
options, 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" "tail calls are not yet supported in `rustc_codegen_cranelift` backend"
), ),
TerminatorKind::InlineAsm { TerminatorKind::InlineAsm {
asm_macro: _,
template, template,
operands, operands,
options, options,

View File

@ -3,7 +3,9 @@ use std::cmp;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir::lang_items::LangItem; 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::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::ty::{self, Instance, Ty};
@ -1133,6 +1135,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
&mut self, &mut self,
helper: TerminatorCodegenHelper<'tcx>, helper: TerminatorCodegenHelper<'tcx>,
bx: &mut Bx, bx: &mut Bx,
asm_macro: InlineAsmMacro,
terminator: &mir::Terminator<'tcx>, terminator: &mir::Terminator<'tcx>,
template: &[ast::InlineAsmTemplatePiece], template: &[ast::InlineAsmTemplatePiece],
operands: &[mir::InlineAsmOperand<'tcx>], operands: &[mir::InlineAsmOperand<'tcx>],
@ -1203,11 +1206,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
&operands, &operands,
options, options,
line_spans, line_spans,
if options.contains(InlineAsmOptions::NORETURN) { if asm_macro.diverges(options) { None } else { targets.get(0).copied() },
None
} else {
targets.get(0).copied()
},
unwind, unwind,
instance, instance,
mergeable_succ, mergeable_succ,
@ -1381,6 +1380,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} }
mir::TerminatorKind::InlineAsm { mir::TerminatorKind::InlineAsm {
asm_macro,
template, template,
ref operands, ref operands,
options, options,
@ -1390,6 +1390,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} => self.codegen_asm_terminator( } => self.codegen_asm_terminator(
helper, helper,
bx, bx,
asm_macro,
terminator, terminator,
template, template,
operands, operands,

View File

@ -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 /// 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 /// 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( fn eval_inline_asm(
_ecx: &mut InterpCx<'tcx, Self>, _ecx: &mut InterpCx<'tcx, Self>,
_template: &'tcx [InlineAsmTemplatePiece], _template: &'tcx [InlineAsmTemplatePiece],

View File

@ -11,11 +11,10 @@ pub extern "C" fn f() -> u32 {
} }
``` ```
The naked functions must be defined using a single inline assembly The naked function must be defined using a single `naked_asm!` assembly block.
block.
The execution must never fall through past the end of the assembly 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. use `att_syntax` and `raw` options, but others options are not allowed.
The asm block must not contain any operands other than `const` and The asm block must not contain any operands other than `const` and

View File

@ -3507,7 +3507,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'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 { for (op, _op_sp) in asm.operands {
match op { match op {

View File

@ -2925,16 +2925,16 @@ declare_lint! {
/// ```rust /// ```rust
/// #![feature(asm_experimental_arch, naked_functions)] /// #![feature(asm_experimental_arch, naked_functions)]
/// ///
/// use std::arch::asm; /// use std::arch::naked_asm;
/// ///
/// #[naked] /// #[naked]
/// pub fn default_abi() -> u32 { /// pub fn default_abi() -> u32 {
/// unsafe { asm!("", options(noreturn)); } /// unsafe { naked_asm!(""); }
/// } /// }
/// ///
/// #[naked] /// #[naked]
/// pub extern "Rust" fn rust_abi() -> u32 { /// pub extern "Rust" fn rust_abi() -> u32 {
/// unsafe { asm!("", options(noreturn)); } /// unsafe { naked_asm!(""); }
/// } /// }
/// ``` /// ```
/// ///

View File

@ -4,7 +4,7 @@ use std::fs;
use std::io::{self, Write as _}; use std::io::{self, Write as _};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::InlineAsmTemplatePiece;
use rustc_middle::mir::interpret::{ use rustc_middle::mir::interpret::{
AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer, Provenance, alloc_range, AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer, Provenance, alloc_range,
read_target_uint, read_target_uint,
@ -1024,9 +1024,9 @@ impl<'tcx> TerminatorKind<'tcx> {
vec!["real".into(), "unwind".into()] vec!["real".into(), "unwind".into()]
} }
FalseUnwind { unwind: _, .. } => vec!["real".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); let mut vec = Vec::with_capacity(targets.len() + 1);
if !options.contains(InlineAsmOptions::NORETURN) { if !asm_macro.diverges(options) {
vec.push("return".into()); vec.push("return".into());
} }
vec.resize(targets.len(), "label".into()); vec.resize(targets.len(), "label".into());

View File

@ -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 // Terminators
@ -859,6 +878,9 @@ pub enum TerminatorKind<'tcx> {
/// Block ends with an inline assembly block. This is a terminator since /// Block ends with an inline assembly block. This is a terminator since
/// inline assembly is allowed to diverge. /// inline assembly is allowed to diverge.
InlineAsm { 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. /// The template for the inline assembly, with placeholders.
template: &'tcx [InlineAsmTemplatePiece], template: &'tcx [InlineAsmTemplatePiece],
@ -874,7 +896,7 @@ pub enum TerminatorKind<'tcx> {
/// Valid targets for the inline assembly. /// Valid targets for the inline assembly.
/// The first element is the fallthrough destination, unless /// The first element is the fallthrough destination, unless
/// InlineAsmOptions::NORETURN is set. /// asm_macro == InlineAsmMacro::NakedAsm or InlineAsmOptions::NORETURN is set.
targets: Box<[BasicBlock]>, targets: Box<[BasicBlock]>,
/// Action to be taken if the inline assembly unwinds. This is present /// Action to be taken if the inline assembly unwinds. This is present

View File

@ -666,6 +666,7 @@ impl<'tcx> TerminatorKind<'tcx> {
}, },
InlineAsm { InlineAsm {
asm_macro: _,
template: _, template: _,
ref operands, ref operands,
options: _, options: _,

View File

@ -576,6 +576,7 @@ macro_rules! make_mir_visitor {
} }
TerminatorKind::InlineAsm { TerminatorKind::InlineAsm {
asm_macro: _,
template: _, template: _,
operands, operands,
options: _, options: _,

View File

@ -12,7 +12,7 @@ use std::cmp::Ordering;
use std::fmt; use std::fmt;
use std::ops::Index; use std::ops::Index;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::{AsmMacro, InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd}; use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd};
@ -173,6 +173,7 @@ pub struct ClosureExpr<'tcx> {
#[derive(Clone, Debug, HashStable)] #[derive(Clone, Debug, HashStable)]
pub struct InlineAsmExpr<'tcx> { pub struct InlineAsmExpr<'tcx> {
pub asm_macro: AsmMacro,
pub template: &'tcx [InlineAsmTemplatePiece], pub template: &'tcx [InlineAsmTemplatePiece],
pub operands: Box<[InlineAsmOperand<'tcx>]>, pub operands: Box<[InlineAsmOperand<'tcx>]>,
pub options: InlineAsmOptions, pub options: InlineAsmOptions,

View File

@ -148,7 +148,13 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
NamedConst { def_id: _, args: _, user_ty: _ } => {} NamedConst { def_id: _, args: _, user_ty: _ } => {}
ConstParam { param: _, def_id: _ } => {} ConstParam { param: _, def_id: _ } => {}
StaticRef { alloc_id: _, ty: _, 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 { for op in &**operands {
use InlineAsmOperand::*; use InlineAsmOperand::*;
match op { match op {

View File

@ -2,7 +2,7 @@
use std::iter; use std::iter;
use rustc_ast::InlineAsmOptions; use rustc_ast::{AsmMacro, InlineAsmOptions};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir; use rustc_hir as hir;
@ -384,6 +384,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block.unit() block.unit()
} }
ExprKind::InlineAsm(box InlineAsmExpr { ExprKind::InlineAsm(box InlineAsmExpr {
asm_macro,
template, template,
ref operands, ref operands,
options, options,
@ -392,11 +393,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
use rustc_middle::{mir, thir}; use rustc_middle::{mir, thir};
let destination_block = this.cfg.start_new_block(); let destination_block = this.cfg.start_new_block();
let mut targets = if options.contains(InlineAsmOptions::NORETURN) { let mut targets =
vec![] if asm_macro.diverges(options) { vec![] } else { vec![destination_block] };
} else {
vec![destination_block]
};
let operands = operands let operands = operands
.into_iter() .into_iter()
@ -474,7 +472,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.cfg.push_assign_unit(block, source_info, destination, this.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 { this.cfg.terminate(block, source_info, TerminatorKind::InlineAsm {
asm_macro,
template, template,
operands, operands,
options, options,

View File

@ -672,6 +672,7 @@ impl<'tcx> Cx<'tcx> {
} }
hir::ExprKind::InlineAsm(asm) => ExprKind::InlineAsm(Box::new(InlineAsmExpr { hir::ExprKind::InlineAsm(asm) => ExprKind::InlineAsm(Box::new(InlineAsmExpr {
asm_macro: asm.asm_macro,
template: asm.template, template: asm.template,
operands: asm operands: asm
.operands .operands

View File

@ -818,10 +818,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
} }
fn print_inline_asm_expr(&mut self, expr: &InlineAsmExpr<'tcx>, depth_lvl: usize) { 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, "InlineAsmExpr {", depth_lvl);
print_indented!(self, format!("asm_macro: {:?}", asm_macro), depth_lvl + 1);
print_indented!(self, "template: [", depth_lvl + 1); print_indented!(self, "template: [", depth_lvl + 1);
for template_piece in template.iter() { for template_piece in template.iter() {
print_indented!(self, format!("{:?}", template_piece), depth_lvl + 2); print_indented!(self, format!("{:?}", template_piece), depth_lvl + 2);

View File

@ -481,6 +481,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
} }
} }
TerminatorKind::InlineAsm { TerminatorKind::InlineAsm {
asm_macro: _,
template: _, template: _,
ref operands, ref operands,
options: _, options: _,

View File

@ -488,24 +488,18 @@ passes_naked_asm_outside_naked_fn =
the `naked_asm!` macro can only be used in functions marked with `#[naked]` the `naked_asm!` macro can only be used in functions marked with `#[naked]`
passes_naked_functions_asm_block = passes_naked_functions_asm_block =
naked functions must contain a single asm block naked functions must contain a single `naked_asm!` invocation
.label_multiple_asm = multiple asm blocks are unsupported in naked functions .label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions
.label_non_asm = non-asm is unsupported in naked functions .label_non_asm = not allowed in naked functions
passes_naked_functions_asm_options =
asm options unsupported in naked functions: {$unsupported_options}
passes_naked_functions_incompatible_attribute = passes_naked_functions_incompatible_attribute =
attribute incompatible with `#[naked]` attribute incompatible with `#[naked]`
.label = the `{$attr}` attribute is incompatible with `#[naked]` .label = the `{$attr}` attribute is incompatible with `#[naked]`
.naked_attribute = function marked with `#[naked]` here .naked_attribute = function marked with `#[naked]` here
passes_naked_functions_must_use_noreturn = passes_naked_functions_must_naked_asm =
asm in naked functions must use `noreturn` option the `asm!` macro is not allowed in naked functions
.suggestion = consider specifying that the asm block is responsible for returning from the function .label = consider using the `naked_asm!` macro instead
passes_naked_functions_operands =
only `const` and `sym` operands are supported in naked functions
passes_no_link = passes_no_link =
attribute should be applied to an `extern crate` item attribute should be applied to an `extern crate` item

View File

@ -1187,27 +1187,11 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for NakedFunctionsAsmBlock {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(passes_naked_functions_operands, code = E0787)] #[diag(passes_naked_functions_must_naked_asm, code = E0787)]
pub(crate) struct NakedFunctionsOperands { pub(crate) struct NakedFunctionsMustNakedAsm {
#[primary_span]
pub unsupported_operands: Vec<Span>,
}
#[derive(Diagnostic)]
#[diag(passes_naked_functions_asm_options, code = E0787)]
pub(crate) struct NakedFunctionsAsmOptions {
#[primary_span] #[primary_span]
#[label]
pub span: Span, pub span: Span,
pub unsupported_options: String,
}
#[derive(Diagnostic)]
#[diag(passes_naked_functions_must_use_noreturn, code = E0787)]
pub(crate) struct NakedFunctionsMustUseNoreturn {
#[primary_span]
pub span: Span,
#[suggestion(code = ", options(noreturn)", applicability = "machine-applicable")]
pub last_span: Span,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]

View File

@ -1,13 +1,13 @@
//! Checks validity of naked functions. //! Checks validity of naked functions.
use rustc_ast::InlineAsmOptions;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::def_id::{LocalDefId, LocalModDefId};
use rustc_hir::intravisit::Visitor; 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::hir::nested_filter::OnlyBodies;
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::span_bug;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI; use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
use rustc_span::Span; use rustc_span::Span;
@ -15,9 +15,8 @@ use rustc_span::symbol::sym;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use crate::errors::{ use crate::errors::{
NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions, NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns,
NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, ParamsNotAllowed, UndefinedNakedFunctionAbi,
UndefinedNakedFunctionAbi,
}; };
pub(crate) fn provide(providers: &mut Providers) { 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. /// 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>) { 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); this.visit_body(body);
if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] { if let [(ItemKind::NakedAsm | ItemKind::Err, _)] = this.items[..] {
// Ok. // Ok.
} else { } else {
let mut must_show_error = false; let mut must_show_error = false;
let mut has_asm = false; let mut has_naked_asm = false;
let mut has_err = false; let mut has_err = false;
let mut multiple_asms = vec![]; let mut multiple_asms = vec![];
let mut non_asms = vec![]; let mut non_asms = vec![];
for &(kind, span) in &this.items { for &(kind, span) in &this.items {
match kind { match kind {
ItemKind::Asm if has_asm => { ItemKind::NakedAsm if has_naked_asm => {
must_show_error = true; must_show_error = true;
multiple_asms.push(span); 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 => { ItemKind::NonAsm => {
must_show_error = true; must_show_error = true;
non_asms.push(span); 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> { struct CheckInlineAssembly {
tcx: TyCtxt<'tcx>,
items: Vec<(ItemKind, Span)>, items: Vec<(ItemKind, Span)>,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
enum ItemKind { enum ItemKind {
Asm, NakedAsm,
InlineAsm,
NonAsm, NonAsm,
Err, Err,
} }
impl<'tcx> CheckInlineAssembly<'tcx> { impl CheckInlineAssembly {
fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) { fn check_expr<'tcx>(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) {
match expr.kind { match expr.kind {
ExprKind::ConstBlock(..) ExprKind::ConstBlock(..)
| ExprKind::Array(..) | ExprKind::Array(..)
@ -204,10 +208,17 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
self.items.push((ItemKind::NonAsm, span)); self.items.push((ItemKind::NonAsm, span));
} }
ExprKind::InlineAsm(asm) => { ExprKind::InlineAsm(asm) => match asm.asm_macro {
self.items.push((ItemKind::Asm, span)); rustc_ast::AsmMacro::Asm => {
self.check_inline_asm(asm, span); 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(..) => { ExprKind::DropTemps(..) | ExprKind::Block(..) => {
hir::intravisit::walk_expr(self, expr); 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>) { fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
match stmt.kind { match stmt.kind {
StmtKind::Item(..) => {} StmtKind::Item(..) => {}

View File

@ -655,6 +655,7 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
} }
} }
mir::TerminatorKind::InlineAsm { mir::TerminatorKind::InlineAsm {
asm_macro: _,
template, template,
operands, operands,
options, options,

View File

@ -7,5 +7,5 @@ use crate::rewrite::RewriteContext;
pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option<AsmArgs> { pub(crate) fn parse_asm(context: &RewriteContext<'_>, mac: &ast::MacCall) -> Option<AsmArgs> {
let ts = mac.args.tokens.clone(); let ts = mac.args.tokens.clone();
let mut parser = super::build_parser(context, ts); let mut parser = super::build_parser(context, ts);
parse_asm_args(&mut parser, mac.span(), false).ok() parse_asm_args(&mut parser, mac.span(), ast::AsmMacro::Asm).ok()
} }

View File

@ -5,7 +5,7 @@
#![crate_type = "lib"] #![crate_type = "lib"]
#![feature(naked_functions)] #![feature(naked_functions)]
use std::arch::asm; use std::arch::naked_asm;
// The problem at hand: Rust has adopted a fairly strict meaning for "naked functions", // The problem at hand: Rust has adopted a fairly strict meaning for "naked functions",
// meaning "no prologue whatsoever, no, really, not one instruction." // meaning "no prologue whatsoever, no, really, not one instruction."
@ -17,5 +17,5 @@ use std::arch::asm;
pub unsafe extern "C" fn _hlt() -> ! { pub unsafe extern "C" fn _hlt() -> ! {
// CHECK-NOT: hint #34 // CHECK-NOT: hint #34
// CHECK: hlt #0x1 // CHECK: hlt #0x1
asm!("hlt #1", options(noreturn)) naked_asm!("hlt #1")
} }

View File

@ -5,7 +5,7 @@
#![crate_type = "lib"] #![crate_type = "lib"]
#![feature(naked_functions)] #![feature(naked_functions)]
use std::arch::asm; use std::arch::naked_asm;
// The problem at hand: Rust has adopted a fairly strict meaning for "naked functions", // The problem at hand: Rust has adopted a fairly strict meaning for "naked functions",
// meaning "no prologue whatsoever, no, really, not one instruction." // meaning "no prologue whatsoever, no, really, not one instruction."
@ -17,7 +17,7 @@ use std::arch::asm;
pub unsafe extern "sysv64" fn will_halt() -> ! { pub unsafe extern "sysv64" fn will_halt() -> ! {
// CHECK-NOT: endbr{{32|64}} // CHECK-NOT: endbr{{32|64}}
// CHECK: hlt // CHECK: hlt
asm!("hlt", options(noreturn)) naked_asm!("hlt")
} }
// what about aarch64? // what about aarch64?

View File

@ -12,8 +12,7 @@
pub unsafe extern "C" fn c_variadic(_: usize, _: ...) { pub unsafe extern "C" fn c_variadic(_: usize, _: ...) {
// CHECK-NOT: va_start // CHECK-NOT: va_start
// CHECK-NOT: alloca // CHECK-NOT: alloca
core::arch::asm! { core::arch::naked_asm! {
"ret", "ret",
options(noreturn),
} }
} }

View File

@ -14,7 +14,7 @@
#[no_mangle] #[no_mangle]
pub extern "x86-interrupt" fn page_fault_handler(_: u64, _: u64) { pub extern "x86-interrupt" fn page_fault_handler(_: u64, _: u64) {
unsafe { unsafe {
core::arch::asm!("ud2", options(noreturn)); core::arch::naked_asm!("ud2");
} }
} }

View File

@ -4,7 +4,7 @@
#![crate_type = "lib"] #![crate_type = "lib"]
#![feature(naked_functions, fn_align)] #![feature(naked_functions, fn_align)]
use std::arch::asm; use std::arch::naked_asm;
// CHECK: Function Attrs: naked // CHECK: Function Attrs: naked
// CHECK-NEXT: define{{.*}}void @naked_empty() // CHECK-NEXT: define{{.*}}void @naked_empty()
@ -16,5 +16,5 @@ pub unsafe extern "C" fn naked_empty() {
// CHECK-NEXT: start: // CHECK-NEXT: start:
// CHECK-NEXT: call void asm // CHECK-NEXT: call void asm
// CHECK-NEXT: unreachable // CHECK-NEXT: unreachable
asm!("ret", options(noreturn)); naked_asm!("ret");
} }

View File

@ -4,7 +4,7 @@
#![crate_type = "lib"] #![crate_type = "lib"]
#![feature(naked_functions)] #![feature(naked_functions)]
use std::arch::asm; use std::arch::naked_asm;
// CHECK: Function Attrs: naked // CHECK: Function Attrs: naked
// CHECK-NEXT: define{{.*}}void @naked_empty() // CHECK-NEXT: define{{.*}}void @naked_empty()
@ -14,7 +14,7 @@ pub unsafe extern "C" fn naked_empty() {
// CHECK-NEXT: {{.+}}: // CHECK-NEXT: {{.+}}:
// CHECK-NEXT: call void asm // CHECK-NEXT: call void asm
// CHECK-NEXT: unreachable // CHECK-NEXT: unreachable
asm!("ret", options(noreturn)); naked_asm!("ret");
} }
// CHECK: Function Attrs: naked // CHECK: Function Attrs: naked
@ -25,5 +25,5 @@ pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize
// CHECK-NEXT: {{.+}}: // CHECK-NEXT: {{.+}}:
// CHECK-NEXT: call void asm // CHECK-NEXT: call void asm
// CHECK-NEXT: unreachable // CHECK-NEXT: unreachable
asm!("lea rax, [rdi + rsi]", "ret", options(noreturn)); naked_asm!("lea rax, [rdi + rsi]", "ret");
} }

View File

@ -6,7 +6,7 @@
//@ compile-flags: -Cinstrument-coverage //@ compile-flags: -Cinstrument-coverage
#![crate_type = "lib"] #![crate_type = "lib"]
#![feature(naked_functions)] #![feature(naked_functions)]
use std::arch::asm; use std::arch::naked_asm;
#[naked] #[naked]
#[no_mangle] #[no_mangle]
@ -15,5 +15,5 @@ pub unsafe extern "C" fn f() {
// CHECK-NEXT: start: // CHECK-NEXT: start:
// CHECK-NEXT: call void asm // CHECK-NEXT: call void asm
// CHECK-NEXT: unreachable // CHECK-NEXT: unreachable
asm!("", options(noreturn)); naked_asm!("");
} }

View File

@ -5,7 +5,7 @@
#![crate_type = "lib"] #![crate_type = "lib"]
#![feature(naked_functions)] #![feature(naked_functions)]
use std::arch::asm; use std::arch::naked_asm;
#[naked] #[naked]
#[no_mangle] #[no_mangle]
@ -15,7 +15,7 @@ pub unsafe extern "C" fn f() {
// CHECK: define {{(dso_local )?}}void @f() unnamed_addr [[ATTR:#[0-9]+]] // CHECK: define {{(dso_local )?}}void @f() unnamed_addr [[ATTR:#[0-9]+]]
// CHECK-NEXT: start: // CHECK-NEXT: start:
// CHECK-NEXT: call void asm // CHECK-NEXT: call void asm
asm!("", options(noreturn)); naked_asm!("");
} }
#[no_mangle] #[no_mangle]

View File

@ -3,9 +3,9 @@
//@ only-x86_64 //@ only-x86_64
#![crate_type = "lib"] #![crate_type = "lib"]
#![feature(naked_functions)] #![feature(naked_functions)]
use std::arch::asm; use std::arch::naked_asm;
#[naked] #[naked]
pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
asm!("lea rax, [rdi + rsi]", "ret", options(noreturn)); naked_asm!("lea rax, [rdi + rsi]", "ret");
} }

View File

@ -1,7 +1,7 @@
#![feature(naked_functions, asm_const, linkage)] #![feature(naked_functions, asm_const, linkage)]
#![crate_type = "dylib"] #![crate_type = "dylib"]
use std::arch::asm; use std::arch::naked_asm;
pub trait TraitWithConst { pub trait TraitWithConst {
const COUNT: u32; const COUNT: u32;
@ -28,7 +28,7 @@ extern "C" fn private_vanilla() -> u32 {
#[naked] #[naked]
extern "C" fn private_naked() -> u32 { extern "C" fn private_naked() -> u32 {
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } unsafe { naked_asm!("mov rax, 42", "ret") }
} }
#[no_mangle] #[no_mangle]
@ -39,7 +39,7 @@ pub extern "C" fn public_vanilla() -> u32 {
#[naked] #[naked]
#[no_mangle] #[no_mangle]
pub extern "C" fn public_naked() -> u32 { pub extern "C" fn public_naked() -> u32 {
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } unsafe { naked_asm!("mov rax, 42", "ret") }
} }
pub extern "C" fn public_vanilla_generic<T: TraitWithConst>() -> u32 { pub extern "C" fn public_vanilla_generic<T: TraitWithConst>() -> u32 {
@ -48,7 +48,7 @@ pub extern "C" fn public_vanilla_generic<T: TraitWithConst>() -> u32 {
#[naked] #[naked]
pub extern "C" fn public_naked_generic<T: TraitWithConst>() -> u32 { pub extern "C" fn public_naked_generic<T: TraitWithConst>() -> u32 {
unsafe { asm!("mov rax, {}", "ret", const T::COUNT, options(noreturn)) } unsafe { naked_asm!("mov rax, {}", "ret", const T::COUNT) }
} }
#[linkage = "external"] #[linkage = "external"]
@ -59,7 +59,7 @@ extern "C" fn vanilla_external_linkage() -> u32 {
#[naked] #[naked]
#[linkage = "external"] #[linkage = "external"]
extern "C" fn naked_external_linkage() -> u32 { extern "C" fn naked_external_linkage() -> u32 {
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } unsafe { naked_asm!("mov rax, 42", "ret") }
} }
#[cfg(not(windows))] #[cfg(not(windows))]
@ -72,7 +72,7 @@ extern "C" fn vanilla_weak_linkage() -> u32 {
#[cfg(not(windows))] #[cfg(not(windows))]
#[linkage = "weak"] #[linkage = "weak"]
extern "C" fn naked_weak_linkage() -> u32 { extern "C" fn naked_weak_linkage() -> u32 {
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } unsafe { naked_asm!("mov rax, 42", "ret") }
} }
// functions that are declared in an `extern "C"` block are currently not exported // functions that are declared in an `extern "C"` block are currently not exported

View File

@ -3,13 +3,13 @@
#![feature(naked_functions)] #![feature(naked_functions)]
#![crate_type = "lib"] #![crate_type = "lib"]
use std::arch::asm; use std::arch::naked_asm;
#[naked] #[naked]
pub extern "C" fn naked(p: char) -> u128 { pub extern "C" fn naked(p: char) -> u128 {
//~^ WARN uses type `char` //~^ WARN uses type `char`
//~| WARN uses type `u128` //~| WARN uses type `u128`
unsafe { unsafe {
asm!("", options(noreturn)); naked_asm!("");
} }
} }

View File

@ -8,7 +8,7 @@
#![no_core] #![no_core]
#[rustc_builtin_macro] #[rustc_builtin_macro]
macro_rules! asm { macro_rules! naked_asm {
() => {}; () => {};
} }
@ -19,12 +19,12 @@ trait Sized {}
#[naked] #[naked]
#[instruction_set(arm::t32)] #[instruction_set(arm::t32)]
unsafe extern "C" fn test_thumb() { unsafe extern "C" fn test_thumb() {
asm!("bx lr", options(noreturn)); naked_asm!("bx lr");
} }
#[no_mangle] #[no_mangle]
#[naked] #[naked]
#[instruction_set(arm::t32)] #[instruction_set(arm::t32)]
unsafe extern "C" fn test_arm() { unsafe extern "C" fn test_arm() {
asm!("bx lr", options(noreturn)); naked_asm!("bx lr");
} }

View File

@ -6,13 +6,13 @@
#![feature(test)] #![feature(test)]
#![crate_type = "lib"] #![crate_type = "lib"]
use std::arch::asm; use std::arch::naked_asm;
#[test] #[test]
#[naked] #[naked]
//~^ ERROR [E0736] //~^ ERROR [E0736]
fn test_naked() { fn test_naked() {
unsafe { asm!("", options(noreturn)) }; unsafe { naked_asm!("") };
} }
#[should_panic] #[should_panic]
@ -20,7 +20,7 @@ fn test_naked() {
#[naked] #[naked]
//~^ ERROR [E0736] //~^ ERROR [E0736]
fn test_naked_should_panic() { fn test_naked_should_panic() {
unsafe { asm!("", options(noreturn)) }; unsafe { naked_asm!("") };
} }
#[ignore] #[ignore]
@ -28,12 +28,12 @@ fn test_naked_should_panic() {
#[naked] #[naked]
//~^ ERROR [E0736] //~^ ERROR [E0736]
fn test_naked_ignore() { fn test_naked_ignore() {
unsafe { asm!("", options(noreturn)) }; unsafe { naked_asm!("") };
} }
#[bench] #[bench]
#[naked] #[naked]
//~^ ERROR [E0736] //~^ ERROR [E0736]
fn bench_naked() { fn bench_naked() {
unsafe { asm!("", options(noreturn)) }; unsafe { naked_asm!("") };
} }

View File

@ -18,49 +18,49 @@ LL | pub extern "C" fn function(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b` | ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a` error: unused variable: `a`
--> $DIR/naked-functions-unused.rs:26:38 --> $DIR/naked-functions-unused.rs:28:38
| |
LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a` | ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b` error: unused variable: `b`
--> $DIR/naked-functions-unused.rs:26:48 --> $DIR/naked-functions-unused.rs:28:48
| |
LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b` | ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a` error: unused variable: `a`
--> $DIR/naked-functions-unused.rs:32:41 --> $DIR/naked-functions-unused.rs:36:41
| |
LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a` | ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b` error: unused variable: `b`
--> $DIR/naked-functions-unused.rs:32:51 --> $DIR/naked-functions-unused.rs:36:51
| |
LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b` | ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a` error: unused variable: `a`
--> $DIR/naked-functions-unused.rs:40:40 --> $DIR/naked-functions-unused.rs:46:40
| |
LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a` | ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b` error: unused variable: `b`
--> $DIR/naked-functions-unused.rs:40:50 --> $DIR/naked-functions-unused.rs:46:50
| |
LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b` | ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a` error: unused variable: `a`
--> $DIR/naked-functions-unused.rs:46:43 --> $DIR/naked-functions-unused.rs:54:43
| |
LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a` | ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b` error: unused variable: `b`
--> $DIR/naked-functions-unused.rs:46:53 --> $DIR/naked-functions-unused.rs:54:53
| |
LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b` | ^ help: if this is intentional, prefix it with an underscore: `_b`

View File

@ -17,7 +17,9 @@ pub mod normal {
pub extern "C" fn function(a: usize, b: usize) -> usize { pub extern "C" fn function(a: usize, b: usize) -> usize {
//~^ ERROR unused variable: `a` //~^ ERROR unused variable: `a`
//~| ERROR unused variable: `b` //~| ERROR unused variable: `b`
unsafe { asm!("", options(noreturn)); } unsafe {
asm!("", options(noreturn));
}
} }
pub struct Normal; pub struct Normal;
@ -26,13 +28,17 @@ pub mod normal {
pub extern "C" fn associated(a: usize, b: usize) -> usize { pub extern "C" fn associated(a: usize, b: usize) -> usize {
//~^ ERROR unused variable: `a` //~^ ERROR unused variable: `a`
//~| ERROR unused variable: `b` //~| ERROR unused variable: `b`
unsafe { asm!("", options(noreturn)); } unsafe {
asm!("", options(noreturn));
}
} }
pub extern "C" fn method(&self, a: usize, b: usize) -> usize { pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
//~^ ERROR unused variable: `a` //~^ ERROR unused variable: `a`
//~| ERROR unused variable: `b` //~| ERROR unused variable: `b`
unsafe { asm!("", options(noreturn)); } unsafe {
asm!("", options(noreturn));
}
} }
} }
@ -40,23 +46,29 @@ pub mod normal {
extern "C" fn trait_associated(a: usize, b: usize) -> usize { extern "C" fn trait_associated(a: usize, b: usize) -> usize {
//~^ ERROR unused variable: `a` //~^ ERROR unused variable: `a`
//~| ERROR unused variable: `b` //~| ERROR unused variable: `b`
unsafe { asm!("", options(noreturn)); } unsafe {
asm!("", options(noreturn));
}
} }
extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
//~^ ERROR unused variable: `a` //~^ ERROR unused variable: `a`
//~| ERROR unused variable: `b` //~| ERROR unused variable: `b`
unsafe { asm!("", options(noreturn)); } unsafe {
asm!("", options(noreturn));
}
} }
} }
} }
pub mod naked { pub mod naked {
use std::arch::asm; use std::arch::naked_asm;
#[naked] #[naked]
pub extern "C" fn function(a: usize, b: usize) -> usize { pub extern "C" fn function(a: usize, b: usize) -> usize {
unsafe { asm!("", options(noreturn)); } unsafe {
naked_asm!("");
}
} }
pub struct Naked; pub struct Naked;
@ -64,24 +76,32 @@ pub mod naked {
impl Naked { impl Naked {
#[naked] #[naked]
pub extern "C" fn associated(a: usize, b: usize) -> usize { pub extern "C" fn associated(a: usize, b: usize) -> usize {
unsafe { asm!("", options(noreturn)); } unsafe {
naked_asm!("");
}
} }
#[naked] #[naked]
pub extern "C" fn method(&self, a: usize, b: usize) -> usize { pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
unsafe { asm!("", options(noreturn)); } unsafe {
naked_asm!("");
}
} }
} }
impl super::Trait for Naked { impl super::Trait for Naked {
#[naked] #[naked]
extern "C" fn trait_associated(a: usize, b: usize) -> usize { extern "C" fn trait_associated(a: usize, b: usize) -> usize {
unsafe { asm!("", options(noreturn)); } unsafe {
naked_asm!("");
}
} }
#[naked] #[naked]
extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
unsafe { asm!("", options(noreturn)); } unsafe {
naked_asm!("");
}
} }
} }
} }

View File

@ -18,49 +18,49 @@ LL | pub extern "C" fn function(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b` | ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a` error: unused variable: `a`
--> $DIR/naked-functions-unused.rs:26:38 --> $DIR/naked-functions-unused.rs:28:38
| |
LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a` | ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b` error: unused variable: `b`
--> $DIR/naked-functions-unused.rs:26:48 --> $DIR/naked-functions-unused.rs:28:48
| |
LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b` | ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a` error: unused variable: `a`
--> $DIR/naked-functions-unused.rs:32:41 --> $DIR/naked-functions-unused.rs:36:41
| |
LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a` | ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b` error: unused variable: `b`
--> $DIR/naked-functions-unused.rs:32:51 --> $DIR/naked-functions-unused.rs:36:51
| |
LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b` | ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a` error: unused variable: `a`
--> $DIR/naked-functions-unused.rs:40:40 --> $DIR/naked-functions-unused.rs:46:40
| |
LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a` | ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b` error: unused variable: `b`
--> $DIR/naked-functions-unused.rs:40:50 --> $DIR/naked-functions-unused.rs:46:50
| |
LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b` | ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a` error: unused variable: `a`
--> $DIR/naked-functions-unused.rs:46:43 --> $DIR/naked-functions-unused.rs:54:43
| |
LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a` | ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b` error: unused variable: `b`
--> $DIR/naked-functions-unused.rs:46:53 --> $DIR/naked-functions-unused.rs:54:53
| |
LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b` | ^ help: if this is intentional, prefix it with an underscore: `_b`

View File

@ -6,7 +6,13 @@
#![feature(asm_unwind, linkage)] #![feature(asm_unwind, linkage)]
#![crate_type = "lib"] #![crate_type = "lib"]
use std::arch::asm; use std::arch::{asm, naked_asm};
#[naked]
pub unsafe extern "C" fn inline_asm_macro() {
asm!("", options(raw));
//~^ERROR the `asm!` macro is not allowed in naked functions
}
#[repr(C)] #[repr(C)]
pub struct P { pub struct P {
@ -25,12 +31,12 @@ pub unsafe extern "C" fn patterns(
P { x, y }: P, P { x, y }: P,
//~^ ERROR patterns not allowed in naked function parameters //~^ ERROR patterns not allowed in naked function parameters
) { ) {
asm!("", options(noreturn)) naked_asm!("")
} }
#[naked] #[naked]
pub unsafe extern "C" fn inc(a: u32) -> u32 { pub unsafe extern "C" fn inc(a: u32) -> u32 {
//~^ ERROR naked functions must contain a single asm block //~^ ERROR naked functions must contain a single `naked_asm!` invocation
a + 1 a + 1
//~^ ERROR referencing function parameters is not allowed in naked functions //~^ ERROR referencing function parameters is not allowed in naked functions
} }
@ -38,20 +44,19 @@ pub unsafe extern "C" fn inc(a: u32) -> u32 {
#[naked] #[naked]
#[allow(asm_sub_register)] #[allow(asm_sub_register)]
pub unsafe extern "C" fn inc_asm(a: u32) -> u32 { pub unsafe extern "C" fn inc_asm(a: u32) -> u32 {
asm!("/* {0} */", in(reg) a, options(noreturn)); naked_asm!("/* {0} */", in(reg) a)
//~^ ERROR referencing function parameters is not allowed in naked functions //~^ ERROR the `in` operand cannot be used with `naked_asm!`
//~| ERROR only `const` and `sym` operands are supported in naked functions
} }
#[naked] #[naked]
pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
//~^ ERROR naked functions must contain a single asm block //~^ ERROR naked functions must contain a single `naked_asm!` invocation
(|| a + 1)() (|| a + 1)()
} }
#[naked] #[naked]
pub unsafe extern "C" fn unsupported_operands() { pub unsafe extern "C" fn unsupported_operands() {
//~^ ERROR naked functions must contain a single asm block //~^ ERROR naked functions must contain a single `naked_asm!` invocation
let mut a = 0usize; let mut a = 0usize;
let mut b = 0usize; let mut b = 0usize;
let mut c = 0usize; let mut c = 0usize;
@ -59,10 +64,9 @@ pub unsafe extern "C" fn unsupported_operands() {
let mut e = 0usize; let mut e = 0usize;
const F: usize = 0usize; const F: usize = 0usize;
static G: usize = 0usize; static G: usize = 0usize;
asm!("/* {0} {1} {2} {3} {4} {5} {6} */", naked_asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
//~^ ERROR asm in naked functions must use `noreturn` option
in(reg) a, in(reg) a,
//~^ ERROR only `const` and `sym` operands are supported in naked functions //~^ ERROR the `in` operand cannot be used with `naked_asm!`
inlateout(reg) b, inlateout(reg) b,
inout(reg) c, inout(reg) c,
lateout(reg) d, lateout(reg) d,
@ -74,27 +78,23 @@ pub unsafe extern "C" fn unsupported_operands() {
#[naked] #[naked]
pub extern "C" fn missing_assembly() { pub extern "C" fn missing_assembly() {
//~^ ERROR naked functions must contain a single asm block //~^ ERROR naked functions must contain a single `naked_asm!` invocation
} }
#[naked] #[naked]
pub extern "C" fn too_many_asm_blocks() { pub extern "C" fn too_many_asm_blocks() {
//~^ ERROR naked functions must contain a single asm block //~^ ERROR naked functions must contain a single `naked_asm!` invocation
unsafe { unsafe {
asm!(""); naked_asm!("", options(noreturn));
//~^ ERROR asm in naked functions must use `noreturn` option //~^ ERROR the `noreturn` option cannot be used with `naked_asm!`
asm!(""); naked_asm!("");
//~^ ERROR asm in naked functions must use `noreturn` option
asm!("");
//~^ ERROR asm in naked functions must use `noreturn` option
asm!("", options(noreturn));
} }
} }
pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
#[naked] #[naked]
pub extern "C" fn inner(y: usize) -> usize { pub extern "C" fn inner(y: usize) -> usize {
//~^ ERROR naked functions must contain a single asm block //~^ ERROR naked functions must contain a single `naked_asm!` invocation
*&y *&y
//~^ ERROR referencing function parameters is not allowed in naked functions //~^ ERROR referencing function parameters is not allowed in naked functions
} }
@ -103,40 +103,41 @@ pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
#[naked] #[naked]
unsafe extern "C" fn invalid_options() { unsafe extern "C" fn invalid_options() {
asm!("", options(nomem, preserves_flags, noreturn)); naked_asm!("", options(nomem, preserves_flags));
//~^ ERROR asm options unsupported in naked functions: `nomem`, `preserves_flags` //~^ ERROR the `nomem` option cannot be used with `naked_asm!`
//~| ERROR the `preserves_flags` option cannot be used with `naked_asm!`
} }
#[naked] #[naked]
unsafe extern "C" fn invalid_options_continued() { unsafe extern "C" fn invalid_options_continued() {
asm!("", options(readonly, nostack), options(pure)); naked_asm!("", options(readonly, nostack), options(pure));
//~^ ERROR asm with the `pure` option must have at least one output //~^ ERROR the `readonly` option cannot be used with `naked_asm!`
//~| ERROR asm options unsupported in naked functions: `pure`, `readonly`, `nostack` //~| ERROR the `nostack` option cannot be used with `naked_asm!`
//~| ERROR asm in naked functions must use `noreturn` option //~| ERROR the `pure` option cannot be used with `naked_asm!`
} }
#[naked] #[naked]
unsafe extern "C" fn invalid_may_unwind() { unsafe extern "C" fn invalid_may_unwind() {
asm!("", options(noreturn, may_unwind)); naked_asm!("", options(may_unwind));
//~^ ERROR asm options unsupported in naked functions: `may_unwind` //~^ ERROR the `may_unwind` option cannot be used with `naked_asm!`
} }
#[naked] #[naked]
pub unsafe fn default_abi() { pub unsafe fn default_abi() {
//~^ WARN Rust ABI is unsupported in naked functions //~^ WARN Rust ABI is unsupported in naked functions
asm!("", options(noreturn)); naked_asm!("");
} }
#[naked] #[naked]
pub unsafe fn rust_abi() { pub unsafe fn rust_abi() {
//~^ WARN Rust ABI is unsupported in naked functions //~^ WARN Rust ABI is unsupported in naked functions
asm!("", options(noreturn)); naked_asm!("");
} }
#[naked] #[naked]
pub extern "C" fn valid_a<T>() -> T { pub extern "C" fn valid_a<T>() -> T {
unsafe { unsafe {
asm!("", options(noreturn)); naked_asm!("");
} }
} }
@ -145,7 +146,7 @@ pub extern "C" fn valid_b() {
unsafe { unsafe {
{ {
{ {
asm!("", options(noreturn)); naked_asm!("");
}; };
}; };
} }
@ -153,13 +154,13 @@ pub extern "C" fn valid_b() {
#[naked] #[naked]
pub unsafe extern "C" fn valid_c() { pub unsafe extern "C" fn valid_c() {
asm!("", options(noreturn)); naked_asm!("");
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
#[naked] #[naked]
pub unsafe extern "C" fn valid_att_syntax() { pub unsafe extern "C" fn valid_att_syntax() {
asm!("", options(noreturn, att_syntax)); naked_asm!("", options(att_syntax));
} }
#[naked] #[naked]
@ -173,12 +174,12 @@ pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 {
pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 { pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 {
compile_error!("this is a user specified error"); compile_error!("this is a user specified error");
//~^ ERROR this is a user specified error //~^ ERROR this is a user specified error
asm!("", options(noreturn)) naked_asm!("")
} }
#[naked] #[naked]
pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 {
asm!(invalid_syntax) naked_asm!(invalid_syntax)
//~^ ERROR asm template must be a string literal //~^ ERROR asm template must be a string literal
} }
@ -186,7 +187,7 @@ pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 {
#[cfg_attr(target_pointer_width = "64", no_mangle)] #[cfg_attr(target_pointer_width = "64", no_mangle)]
#[naked] #[naked]
pub unsafe extern "C" fn compatible_cfg_attributes() { pub unsafe extern "C" fn compatible_cfg_attributes() {
asm!("", options(noreturn, att_syntax)); naked_asm!("", options(att_syntax));
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -195,25 +196,24 @@ pub unsafe extern "C" fn compatible_cfg_attributes() {
#[forbid(dead_code)] #[forbid(dead_code)]
#[naked] #[naked]
pub unsafe extern "C" fn compatible_diagnostic_attributes() { pub unsafe extern "C" fn compatible_diagnostic_attributes() {
asm!("", options(noreturn, raw)); naked_asm!("", options(raw));
} }
#[deprecated = "test"] #[deprecated = "test"]
#[naked] #[naked]
pub unsafe extern "C" fn compatible_deprecated_attributes() { pub unsafe extern "C" fn compatible_deprecated_attributes() {
asm!("", options(noreturn, raw)); naked_asm!("", options(raw));
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
#[must_use] #[must_use]
#[naked] #[naked]
pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 {
asm!( naked_asm!(
" "
mov rax, 42 mov rax, 42
ret ret
", ",
options(noreturn)
) )
} }
@ -222,20 +222,20 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 {
#[no_mangle] #[no_mangle]
#[naked] #[naked]
pub unsafe extern "C" fn compatible_ffi_attributes_1() { pub unsafe extern "C" fn compatible_ffi_attributes_1() {
asm!("", options(noreturn, raw)); naked_asm!("", options(raw));
} }
#[cold] #[cold]
#[naked] #[naked]
pub unsafe extern "C" fn compatible_codegen_attributes() { pub unsafe extern "C" fn compatible_codegen_attributes() {
asm!("", options(noreturn, raw)); naked_asm!("", options(raw));
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
#[target_feature(enable = "sse2")] #[target_feature(enable = "sse2")]
#[naked] #[naked]
pub unsafe extern "C" fn compatible_target_feature() { pub unsafe extern "C" fn compatible_target_feature() {
asm!("", options(noreturn)); naked_asm!("");
} }
#[doc = "foo bar baz"] #[doc = "foo bar baz"]
@ -244,11 +244,11 @@ pub unsafe extern "C" fn compatible_target_feature() {
#[doc(alias = "ADocAlias")] #[doc(alias = "ADocAlias")]
#[naked] #[naked]
pub unsafe extern "C" fn compatible_doc_attributes() { pub unsafe extern "C" fn compatible_doc_attributes() {
asm!("", options(noreturn, raw)); naked_asm!("", options(raw));
} }
#[linkage = "external"] #[linkage = "external"]
#[naked] #[naked]
pub unsafe extern "C" fn compatible_linkage() { pub unsafe extern "C" fn compatible_linkage() {
asm!("", options(noreturn, raw)); naked_asm!("", options(raw));
} }

View File

@ -1,193 +1,162 @@
error: asm with the `pure` option must have at least one output error: the `in` operand cannot be used with `naked_asm!`
--> $DIR/naked-functions.rs:112:14 --> $DIR/naked-functions.rs:47:29
| |
LL | asm!("", options(readonly, nostack), options(pure)); LL | naked_asm!("/* {0} */", in(reg) a)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it
error: the `in` operand cannot be used with `naked_asm!`
--> $DIR/naked-functions.rs:68:10
|
LL | in(reg) a,
| ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it
error: the `noreturn` option cannot be used with `naked_asm!`
--> $DIR/naked-functions.rs:88:32
|
LL | naked_asm!("", options(noreturn));
| ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly
error: the `nomem` option cannot be used with `naked_asm!`
--> $DIR/naked-functions.rs:106:28
|
LL | naked_asm!("", options(nomem, preserves_flags));
| ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly
error: the `preserves_flags` option cannot be used with `naked_asm!`
--> $DIR/naked-functions.rs:106:35
|
LL | naked_asm!("", options(nomem, preserves_flags));
| ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly
error: the `readonly` option cannot be used with `naked_asm!`
--> $DIR/naked-functions.rs:113:28
|
LL | naked_asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly
error: the `nostack` option cannot be used with `naked_asm!`
--> $DIR/naked-functions.rs:113:38
|
LL | naked_asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly
error: the `pure` option cannot be used with `naked_asm!`
--> $DIR/naked-functions.rs:113:56
|
LL | naked_asm!("", options(readonly, nostack), options(pure));
| ^^^^ the `pure` option is not meaningful for global-scoped inline assembly
error: the `may_unwind` option cannot be used with `naked_asm!`
--> $DIR/naked-functions.rs:121:28
|
LL | naked_asm!("", options(may_unwind));
| ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly
error: this is a user specified error error: this is a user specified error
--> $DIR/naked-functions.rs:168:5 --> $DIR/naked-functions.rs:169:5
| |
LL | compile_error!("this is a user specified error") LL | compile_error!("this is a user specified error")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this is a user specified error error: this is a user specified error
--> $DIR/naked-functions.rs:174:5 --> $DIR/naked-functions.rs:175:5
| |
LL | compile_error!("this is a user specified error"); LL | compile_error!("this is a user specified error");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: asm template must be a string literal error: asm template must be a string literal
--> $DIR/naked-functions.rs:181:10 --> $DIR/naked-functions.rs:182:16
| |
LL | asm!(invalid_syntax) LL | naked_asm!(invalid_syntax)
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
error[E0787]: the `asm!` macro is not allowed in naked functions
--> $DIR/naked-functions.rs:13:5
|
LL | asm!("", options(raw));
| ^^^^^^^^^^^^^^^^^^^^^^ consider using the `naked_asm!` macro instead
error: patterns not allowed in naked function parameters error: patterns not allowed in naked function parameters
--> $DIR/naked-functions.rs:19:5 --> $DIR/naked-functions.rs:25:5
| |
LL | mut a: u32, LL | mut a: u32,
| ^^^^^ | ^^^^^
error: patterns not allowed in naked function parameters error: patterns not allowed in naked function parameters
--> $DIR/naked-functions.rs:21:5 --> $DIR/naked-functions.rs:27:5
| |
LL | &b: &i32, LL | &b: &i32,
| ^^ | ^^
error: patterns not allowed in naked function parameters error: patterns not allowed in naked function parameters
--> $DIR/naked-functions.rs:23:6 --> $DIR/naked-functions.rs:29:6
| |
LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>, LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>,
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters error: patterns not allowed in naked function parameters
--> $DIR/naked-functions.rs:25:5 --> $DIR/naked-functions.rs:31:5
| |
LL | P { x, y }: P, LL | P { x, y }: P,
| ^^^^^^^^^^ | ^^^^^^^^^^
error: referencing function parameters is not allowed in naked functions error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:34:5 --> $DIR/naked-functions.rs:40:5
| |
LL | a + 1 LL | a + 1
| ^ | ^
| |
= help: follow the calling convention in asm block to use parameters = help: follow the calling convention in asm block to use parameters
error[E0787]: naked functions must contain a single asm block error[E0787]: naked functions must contain a single `naked_asm!` invocation
--> $DIR/naked-functions.rs:32:1 --> $DIR/naked-functions.rs:38:1
| |
LL | pub unsafe extern "C" fn inc(a: u32) -> u32 { LL | pub unsafe extern "C" fn inc(a: u32) -> u32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | LL |
LL | a + 1 LL | a + 1
| ----- non-asm is unsupported in naked functions | ----- not allowed in naked functions
error: referencing function parameters is not allowed in naked functions error[E0787]: naked functions must contain a single `naked_asm!` invocation
--> $DIR/naked-functions.rs:41:31 --> $DIR/naked-functions.rs:52:1
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^
|
= help: follow the calling convention in asm block to use parameters
error[E0787]: only `const` and `sym` operands are supported in naked functions
--> $DIR/naked-functions.rs:41:23
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^^^^^^^^^
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:47:1
| |
LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | LL |
LL | (|| a + 1)() LL | (|| a + 1)()
| ------------ non-asm is unsupported in naked functions | ------------ not allowed in naked functions
error[E0787]: only `const` and `sym` operands are supported in naked functions error[E0787]: naked functions must contain a single `naked_asm!` invocation
--> $DIR/naked-functions.rs:64:10 --> $DIR/naked-functions.rs:58:1
|
LL | in(reg) a,
| ^^^^^^^^^
LL |
LL | inlateout(reg) b,
| ^^^^^^^^^^^^^^^^
LL | inout(reg) c,
| ^^^^^^^^^^^^
LL | lateout(reg) d,
| ^^^^^^^^^^^^^^
LL | out(reg) e,
| ^^^^^^^^^^
error[E0787]: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:62:5
|
LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
LL | |
LL | | in(reg) a,
LL | |
... |
LL | | sym G,
LL | | );
| |_____^
|
help: consider specifying that the asm block is responsible for returning from the function
|
LL | sym G, options(noreturn),
| +++++++++++++++++++
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:53:1
| |
LL | pub unsafe extern "C" fn unsupported_operands() { LL | pub unsafe extern "C" fn unsupported_operands() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | LL |
LL | let mut a = 0usize; LL | let mut a = 0usize;
| ------------------- non-asm is unsupported in naked functions | ------------------- not allowed in naked functions
LL | let mut b = 0usize; LL | let mut b = 0usize;
| ------------------- non-asm is unsupported in naked functions | ------------------- not allowed in naked functions
LL | let mut c = 0usize; LL | let mut c = 0usize;
| ------------------- non-asm is unsupported in naked functions | ------------------- not allowed in naked functions
LL | let mut d = 0usize; LL | let mut d = 0usize;
| ------------------- non-asm is unsupported in naked functions | ------------------- not allowed in naked functions
LL | let mut e = 0usize; LL | let mut e = 0usize;
| ------------------- non-asm is unsupported in naked functions | ------------------- not allowed in naked functions
error[E0787]: naked functions must contain a single asm block error[E0787]: naked functions must contain a single `naked_asm!` invocation
--> $DIR/naked-functions.rs:76:1 --> $DIR/naked-functions.rs:80:1
| |
LL | pub extern "C" fn missing_assembly() { LL | pub extern "C" fn missing_assembly() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0787]: asm in naked functions must use `noreturn` option error[E0787]: naked functions must contain a single `naked_asm!` invocation
--> $DIR/naked-functions.rs:84:9 --> $DIR/naked-functions.rs:85:1
|
LL | asm!("");
| ^^^^^^^^
|
help: consider specifying that the asm block is responsible for returning from the function
|
LL | asm!("", options(noreturn));
| +++++++++++++++++++
error[E0787]: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:86:9
|
LL | asm!("");
| ^^^^^^^^
|
help: consider specifying that the asm block is responsible for returning from the function
|
LL | asm!("", options(noreturn));
| +++++++++++++++++++
error[E0787]: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:88:9
|
LL | asm!("");
| ^^^^^^^^
|
help: consider specifying that the asm block is responsible for returning from the function
|
LL | asm!("", options(noreturn));
| +++++++++++++++++++
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:81:1
| |
LL | pub extern "C" fn too_many_asm_blocks() { LL | pub extern "C" fn too_many_asm_blocks() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
... ...
LL | asm!(""); LL | naked_asm!("");
| -------- multiple asm blocks are unsupported in naked functions | -------------- multiple `naked_asm!` invocations are not allowed in naked functions
LL |
LL | asm!("");
| -------- multiple asm blocks are unsupported in naked functions
LL |
LL | asm!("", options(noreturn));
| --------------------------- multiple asm blocks are unsupported in naked functions
error: referencing function parameters is not allowed in naked functions error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:98:11 --> $DIR/naked-functions.rs:98:11
@ -197,46 +166,17 @@ LL | *&y
| |
= help: follow the calling convention in asm block to use parameters = help: follow the calling convention in asm block to use parameters
error[E0787]: naked functions must contain a single asm block error[E0787]: naked functions must contain a single `naked_asm!` invocation
--> $DIR/naked-functions.rs:96:5 --> $DIR/naked-functions.rs:96:5
| |
LL | pub extern "C" fn inner(y: usize) -> usize { LL | pub extern "C" fn inner(y: usize) -> usize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | LL |
LL | *&y LL | *&y
| --- non-asm is unsupported in naked functions | --- not allowed in naked functions
error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags`
--> $DIR/naked-functions.rs:106:5
|
LL | asm!("", options(nomem, preserves_flags, noreturn));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0787]: asm options unsupported in naked functions: `pure`, `readonly`, `nostack`
--> $DIR/naked-functions.rs:112:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0787]: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:112:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider specifying that the asm block is responsible for returning from the function
|
LL | asm!("", options(noreturn), options(readonly, nostack), options(pure));
| +++++++++++++++++++
error[E0787]: asm options unsupported in naked functions: `may_unwind`
--> $DIR/naked-functions.rs:120:5
|
LL | asm!("", options(noreturn, may_unwind));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: Rust ABI is unsupported in naked functions warning: Rust ABI is unsupported in naked functions
--> $DIR/naked-functions.rs:125:1 --> $DIR/naked-functions.rs:126:1
| |
LL | pub unsafe fn default_abi() { LL | pub unsafe fn default_abi() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -244,11 +184,11 @@ LL | pub unsafe fn default_abi() {
= note: `#[warn(undefined_naked_function_abi)]` on by default = note: `#[warn(undefined_naked_function_abi)]` on by default
warning: Rust ABI is unsupported in naked functions warning: Rust ABI is unsupported in naked functions
--> $DIR/naked-functions.rs:131:1 --> $DIR/naked-functions.rs:132:1
| |
LL | pub unsafe fn rust_abi() { LL | pub unsafe fn rust_abi() {
| ^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 27 previous errors; 2 warnings emitted error: aborting due to 25 previous errors; 2 warnings emitted
For more information about this error, try `rustc --explain E0787`. For more information about this error, try `rustc --explain E0787`.

View File

@ -4,7 +4,7 @@
#![feature(naked_functions)] #![feature(naked_functions)]
#![naked] //~ ERROR should be applied to a function definition #![naked] //~ ERROR should be applied to a function definition
use std::arch::asm; use std::arch::naked_asm;
extern "C" { extern "C" {
#[naked] //~ ERROR should be applied to a function definition #[naked] //~ ERROR should be applied to a function definition
@ -26,27 +26,28 @@ trait Invoke {
impl Invoke for S { impl Invoke for S {
#[naked] #[naked]
extern "C" fn invoke(&self) { extern "C" fn invoke(&self) {
unsafe { asm!("", options(noreturn)) } unsafe { naked_asm!("") }
} }
} }
#[naked] #[naked]
extern "C" fn ok() { extern "C" fn ok() {
unsafe { asm!("", options(noreturn)) } unsafe { naked_asm!("") }
} }
impl S { impl S {
#[naked] #[naked]
extern "C" fn g() { extern "C" fn g() {
unsafe { asm!("", options(noreturn)) } unsafe { naked_asm!("") }
} }
#[naked] #[naked]
extern "C" fn h(&self) { extern "C" fn h(&self) {
unsafe { asm!("", options(noreturn)) } unsafe { naked_asm!("") }
} }
} }
fn main() { fn main() {
#[naked] || {}; //~ ERROR should be applied to a function definition #[naked] //~ ERROR should be applied to a function definition
|| {};
} }

View File

@ -13,8 +13,10 @@ LL | | }
error: attribute should be applied to a function definition error: attribute should be applied to a function definition
--> $DIR/naked-invalid-attr.rs:51:5 --> $DIR/naked-invalid-attr.rs:51:5
| |
LL | #[naked] || {}; LL | #[naked]
| ^^^^^^^^ ----- not a function definition | ^^^^^^^^
LL | || {};
| ----- not a function definition
error: attribute should be applied to a function definition error: attribute should be applied to a function definition
--> $DIR/naked-invalid-attr.rs:22:5 --> $DIR/naked-invalid-attr.rs:22:5

View File

@ -2,14 +2,14 @@
#![feature(naked_functions)] #![feature(naked_functions)]
#![feature(fn_align)] #![feature(fn_align)]
#![crate_type = "lib"] #![crate_type = "lib"]
use std::arch::asm; use std::arch::naked_asm;
#[repr(C)] #[repr(C)]
//~^ ERROR attribute should be applied to a struct, enum, or union [E0517] //~^ ERROR attribute should be applied to a struct, enum, or union [E0517]
#[naked] #[naked]
extern "C" fn example1() { extern "C" fn example1() {
//~^ NOTE not a struct, enum, or union //~^ NOTE not a struct, enum, or union
unsafe { asm!("", options(noreturn)) } unsafe { naked_asm!("") }
} }
#[repr(transparent)] #[repr(transparent)]
@ -17,7 +17,7 @@ extern "C" fn example1() {
#[naked] #[naked]
extern "C" fn example2() { extern "C" fn example2() {
//~^ NOTE not a struct, enum, or union //~^ NOTE not a struct, enum, or union
unsafe { asm!("", options(noreturn)) } unsafe { naked_asm!("") }
} }
#[repr(align(16), C)] #[repr(align(16), C)]
@ -25,7 +25,7 @@ extern "C" fn example2() {
#[naked] #[naked]
extern "C" fn example3() { extern "C" fn example3() {
//~^ NOTE not a struct, enum, or union //~^ NOTE not a struct, enum, or union
unsafe { asm!("", options(noreturn)) } unsafe { naked_asm!("") }
} }
// note: two errors because of packed and C // note: two errors because of packed and C
@ -36,7 +36,7 @@ extern "C" fn example3() {
extern "C" fn example4() { extern "C" fn example4() {
//~^ NOTE not a struct, enum, or union //~^ NOTE not a struct, enum, or union
//~| NOTE not a struct or union //~| NOTE not a struct or union
unsafe { asm!("", options(noreturn)) } unsafe { naked_asm!("") }
} }
#[repr(u8)] #[repr(u8)]
@ -44,5 +44,5 @@ extern "C" fn example4() {
#[naked] #[naked]
extern "C" fn example5() { extern "C" fn example5() {
//~^ NOTE not an enum //~^ NOTE not an enum
unsafe { asm!("", options(noreturn)) } unsafe { naked_asm!("") }
} }

View File

@ -6,7 +6,7 @@ LL | #[repr(C)]
... ...
LL | / extern "C" fn example1() { LL | / extern "C" fn example1() {
LL | | LL | |
LL | | unsafe { asm!("", options(noreturn)) } LL | | unsafe { naked_asm!("") }
LL | | } LL | | }
| |_- not a struct, enum, or union | |_- not a struct, enum, or union
@ -18,7 +18,7 @@ LL | #[repr(transparent)]
... ...
LL | / extern "C" fn example2() { LL | / extern "C" fn example2() {
LL | | LL | |
LL | | unsafe { asm!("", options(noreturn)) } LL | | unsafe { naked_asm!("") }
LL | | } LL | | }
| |_- not a struct, enum, or union | |_- not a struct, enum, or union
@ -30,7 +30,7 @@ LL | #[repr(align(16), C)]
... ...
LL | / extern "C" fn example3() { LL | / extern "C" fn example3() {
LL | | LL | |
LL | | unsafe { asm!("", options(noreturn)) } LL | | unsafe { naked_asm!("") }
LL | | } LL | | }
| |_- not a struct, enum, or union | |_- not a struct, enum, or union
@ -43,7 +43,7 @@ LL | #[repr(C, packed)]
LL | / extern "C" fn example4() { LL | / extern "C" fn example4() {
LL | | LL | |
LL | | LL | |
LL | | unsafe { asm!("", options(noreturn)) } LL | | unsafe { naked_asm!("") }
LL | | } LL | | }
| |_- not a struct, enum, or union | |_- not a struct, enum, or union
@ -56,7 +56,7 @@ LL | #[repr(C, packed)]
LL | / extern "C" fn example4() { LL | / extern "C" fn example4() {
LL | | LL | |
LL | | LL | |
LL | | unsafe { asm!("", options(noreturn)) } LL | | unsafe { naked_asm!("") }
LL | | } LL | | }
| |_- not a struct or union | |_- not a struct or union
@ -68,7 +68,7 @@ LL | #[repr(u8)]
... ...
LL | / extern "C" fn example5() { LL | / extern "C" fn example5() {
LL | | LL | |
LL | | unsafe { asm!("", options(noreturn)) } LL | | unsafe { naked_asm!("") }
LL | | } LL | | }
| |_- not an enum | |_- not an enum

View File

@ -12,7 +12,7 @@
#![feature(naked_functions)] #![feature(naked_functions)]
use std::arch::{asm, global_asm}; use std::arch::{asm, global_asm, naked_asm};
#[no_mangle] #[no_mangle]
pub static FOO: usize = 42; pub static FOO: usize = 42;
@ -177,7 +177,7 @@ fn main() {
// label or LTO can cause labels to break // label or LTO can cause labels to break
#[naked] #[naked]
pub extern "C" fn foo() -> i32 { pub extern "C" fn foo() -> i32 {
unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) }
//~^ ERROR avoid using named labels //~^ ERROR avoid using named labels
} }
@ -192,7 +192,7 @@ pub extern "C" fn bar() {
pub extern "C" fn aaa() { pub extern "C" fn aaa() {
fn _local() {} fn _local() {}
unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } //~ ERROR avoid using named labels unsafe { naked_asm!(".Laaa: nop; ret;") } //~ ERROR avoid using named labels
} }
pub fn normal() { pub fn normal() {
@ -202,7 +202,7 @@ pub fn normal() {
pub extern "C" fn bbb() { pub extern "C" fn bbb() {
fn _very_local() {} fn _very_local() {}
unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } //~ ERROR avoid using named labels unsafe { naked_asm!(".Lbbb: nop; ret;") } //~ ERROR avoid using named labels
} }
fn _local2() {} fn _local2() {}
@ -221,7 +221,7 @@ fn closures() {
|| { || {
#[naked] #[naked]
unsafe extern "C" fn _nested() { unsafe extern "C" fn _nested() {
asm!("ret;", options(noreturn)); naked_asm!("ret;");
} }
unsafe { unsafe {

View File

@ -475,10 +475,10 @@ LL | #[warn(named_asm_labels)]
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
error: avoid using named labels in inline assembly error: avoid using named labels in inline assembly
--> $DIR/named-asm-labels.rs:180:20 --> $DIR/named-asm-labels.rs:180:26
| |
LL | unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } LL | unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) }
| ^^^^^ | ^^^^^
| |
= help: only local labels of the form `<number>:` should be used in inline asm = help: only local labels of the form `<number>:` should be used in inline asm
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
@ -493,19 +493,19 @@ LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noret
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly error: avoid using named labels in inline assembly
--> $DIR/named-asm-labels.rs:195:20 --> $DIR/named-asm-labels.rs:195:26
| |
LL | unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } LL | unsafe { naked_asm!(".Laaa: nop; ret;") }
| ^^^^^ | ^^^^^
| |
= help: only local labels of the form `<number>:` should be used in inline asm = help: only local labels of the form `<number>:` should be used in inline asm
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly error: avoid using named labels in inline assembly
--> $DIR/named-asm-labels.rs:205:24 --> $DIR/named-asm-labels.rs:205:30
| |
LL | unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } LL | unsafe { naked_asm!(".Lbbb: nop; ret;") }
| ^^^^^ | ^^^^^
| |
= help: only local labels of the form `<number>:` should be used in inline asm = help: only local labels of the form `<number>:` should be used in inline asm
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information

View File

@ -1,19 +1,22 @@
//@ needs-asm-support //@ needs-asm-support
use std::arch::asm; use std::arch::naked_asm;
//~^ ERROR use of unstable library feature 'naked_functions'
#[naked] #[naked]
//~^ the `#[naked]` attribute is an experimental feature //~^ the `#[naked]` attribute is an experimental feature
extern "C" fn naked() { extern "C" fn naked() {
asm!("", options(noreturn)) naked_asm!("")
//~^ ERROR: requires unsafe //~^ ERROR use of unstable library feature 'naked_functions'
//~| ERROR: requires unsafe
} }
#[naked] #[naked]
//~^ the `#[naked]` attribute is an experimental feature //~^ the `#[naked]` attribute is an experimental feature
extern "C" fn naked_2() -> isize { extern "C" fn naked_2() -> isize {
asm!("", options(noreturn)) naked_asm!("")
//~^ ERROR: requires unsafe //~^ ERROR use of unstable library feature 'naked_functions'
//~| ERROR: requires unsafe
} }
fn main() {} fn main() {}

View File

@ -1,5 +1,25 @@
error[E0658]: use of unstable library feature 'naked_functions'
--> $DIR/feature-gate-naked_functions.rs:9:5
|
LL | naked_asm!("")
| ^^^^^^^^^
|
= note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information
= help: add `#![feature(naked_functions)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: use of unstable library feature 'naked_functions'
--> $DIR/feature-gate-naked_functions.rs:17:5
|
LL | naked_asm!("")
| ^^^^^^^^^
|
= note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information
= help: add `#![feature(naked_functions)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: the `#[naked]` attribute is an experimental feature error[E0658]: the `#[naked]` attribute is an experimental feature
--> $DIR/feature-gate-naked_functions.rs:5:1 --> $DIR/feature-gate-naked_functions.rs:6:1
| |
LL | #[naked] LL | #[naked]
| ^^^^^^^^ | ^^^^^^^^
@ -9,7 +29,7 @@ LL | #[naked]
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: the `#[naked]` attribute is an experimental feature error[E0658]: the `#[naked]` attribute is an experimental feature
--> $DIR/feature-gate-naked_functions.rs:12:1 --> $DIR/feature-gate-naked_functions.rs:14:1
| |
LL | #[naked] LL | #[naked]
| ^^^^^^^^ | ^^^^^^^^
@ -18,23 +38,33 @@ LL | #[naked]
= help: add `#![feature(naked_functions)]` to the crate attributes to enable = help: add `#![feature(naked_functions)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0133]: use of inline assembly is unsafe and requires unsafe function or block error[E0658]: use of unstable library feature 'naked_functions'
--> $DIR/feature-gate-naked_functions.rs:8:5 --> $DIR/feature-gate-naked_functions.rs:3:5
| |
LL | asm!("", options(noreturn)) LL | use std::arch::naked_asm;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of inline assembly | ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information
= help: add `#![feature(naked_functions)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
--> $DIR/feature-gate-naked_functions.rs:9:5
|
LL | naked_asm!("")
| ^^^^^^^^^^^^^^ use of inline assembly
| |
= note: inline assembly is entirely unchecked and can cause undefined behavior = note: inline assembly is entirely unchecked and can cause undefined behavior
error[E0133]: use of inline assembly is unsafe and requires unsafe function or block error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
--> $DIR/feature-gate-naked_functions.rs:15:5 --> $DIR/feature-gate-naked_functions.rs:17:5
| |
LL | asm!("", options(noreturn)) LL | naked_asm!("")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of inline assembly | ^^^^^^^^^^^^^^ use of inline assembly
| |
= note: inline assembly is entirely unchecked and can cause undefined behavior = note: inline assembly is entirely unchecked and can cause undefined behavior
error: aborting due to 4 previous errors error: aborting due to 7 previous errors
Some errors have detailed explanations: E0133, E0658. Some errors have detailed explanations: E0133, E0658.
For more information about an error, try `rustc --explain E0133`. For more information about an error, try `rustc --explain E0133`.

View File

@ -1,14 +1,14 @@
//@ needs-asm-support //@ needs-asm-support
#![feature(naked_functions)] #![feature(naked_functions)]
use std::arch::asm; use std::arch::naked_asm;
#[track_caller] //~ ERROR [E0736] #[track_caller] //~ ERROR [E0736]
//~^ ERROR `#[track_caller]` requires Rust ABI //~^ ERROR `#[track_caller]` requires Rust ABI
#[naked] #[naked]
extern "C" fn f() { extern "C" fn f() {
unsafe { unsafe {
asm!("", options(noreturn)); naked_asm!("");
} }
} }
@ -20,7 +20,7 @@ impl S {
#[naked] #[naked]
extern "C" fn g() { extern "C" fn g() {
unsafe { unsafe {
asm!("", options(noreturn)); naked_asm!("");
} }
} }
} }