mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
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:
commit
1b3b8e7b02
@ -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");`.
|
||||||
|
@ -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: _,
|
||||||
|
@ -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: _,
|
||||||
|
@ -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
|
||||||
|
@ -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,15 +309,18 @@ 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 => {
|
||||||
|
let err = dcx.create_err(errors::AsmUnsupportedClobberAbi {
|
||||||
spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
|
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);
|
||||||
}
|
}
|
||||||
|
AsmMacro::Asm => {
|
||||||
if !regclass_outputs.is_empty() {
|
if !regclass_outputs.is_empty() {
|
||||||
dcx.emit_err(errors::AsmClobberNoReg {
|
dcx.emit_err(errors::AsmClobberNoReg {
|
||||||
spans: regclass_outputs,
|
spans: regclass_outputs,
|
||||||
@ -317,6 +328,8 @@ pub fn parse_asm_args<'a>(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(args)
|
Ok(args)
|
||||||
}
|
}
|
||||||
@ -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.
|
|
||||||
//
|
|
||||||
// When we turn `asm!` into `naked_asm!` with this implementation, we can drop
|
|
||||||
// the `options(noreturn)`, which makes the upgrade smooth when `naked_asm!`
|
|
||||||
// starts disallowing the `noreturn` option in the future
|
|
||||||
inline_asm.options |= ast::InlineAsmOptions::NORETURN;
|
|
||||||
|
|
||||||
P(ast::Expr {
|
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
|
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
|
||||||
span: sp,
|
span: sp,
|
||||||
attrs: ast::AttrVec::new(),
|
attrs: ast::AttrVec::new(),
|
||||||
tokens: None,
|
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 {
|
||||||
|
@ -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)]
|
||||||
|
@ -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"]
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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],
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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!(""); }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -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());
|
||||||
|
@ -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
|
||||||
|
@ -666,6 +666,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||||||
},
|
},
|
||||||
|
|
||||||
InlineAsm {
|
InlineAsm {
|
||||||
|
asm_macro: _,
|
||||||
template: _,
|
template: _,
|
||||||
ref operands,
|
ref operands,
|
||||||
options: _,
|
options: _,
|
||||||
|
@ -576,6 +576,7 @@ macro_rules! make_mir_visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::InlineAsm {
|
TerminatorKind::InlineAsm {
|
||||||
|
asm_macro: _,
|
||||||
template: _,
|
template: _,
|
||||||
operands,
|
operands,
|
||||||
options: _,
|
options: _,
|
||||||
|
@ -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,
|
||||||
|
@ -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 {
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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: _,
|
||||||
|
@ -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
|
||||||
|
@ -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)]
|
||||||
|
@ -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(..) => {}
|
||||||
|
@ -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,
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -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?
|
||||||
|
@ -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),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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!("");
|
||||||
}
|
}
|
||||||
|
@ -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]
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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!("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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!("") };
|
||||||
}
|
}
|
||||||
|
@ -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`
|
||||||
|
@ -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!("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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`
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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`.
|
||||||
|
@ -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
|
||||||
|
|| {};
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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!("") }
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -475,9 +475,9 @@ 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
|
||||||
@ -493,18 +493,18 @@ 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
|
||||||
|
@ -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() {}
|
||||||
|
@ -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`.
|
||||||
|
@ -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!("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user