disallow asm!
in #[naked]
functions
also disallow the `noreturn` option, and infer `naked_asm!` as `!`
This commit is contained in:
parent
1a9c1cbf36
commit
562ec5a6fb
27 changed files with 223 additions and 298 deletions
|
@ -488,9 +488,9 @@ passes_naked_asm_outside_naked_fn =
|
|||
the `naked_asm!` macro can only be used in functions marked with `#[naked]`
|
||||
|
||||
passes_naked_functions_asm_block =
|
||||
naked functions must contain a single asm block
|
||||
.label_multiple_asm = multiple asm blocks are unsupported in naked functions
|
||||
.label_non_asm = non-asm is unsupported in naked functions
|
||||
naked functions must contain a single `naked_asm!` invocation
|
||||
.label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions
|
||||
.label_non_asm = not allowed in naked functions
|
||||
|
||||
passes_naked_functions_asm_options =
|
||||
asm options unsupported in naked functions: {$unsupported_options}
|
||||
|
@ -500,9 +500,9 @@ passes_naked_functions_incompatible_attribute =
|
|||
.label = the `{$attr}` attribute is incompatible with `#[naked]`
|
||||
.naked_attribute = function marked with `#[naked]` here
|
||||
|
||||
passes_naked_functions_must_use_noreturn =
|
||||
asm in naked functions must use `noreturn` option
|
||||
.suggestion = consider specifying that the asm block is responsible for returning from the function
|
||||
passes_naked_functions_must_naked_asm =
|
||||
the `asm!` macro is not allowed in naked functions
|
||||
.suggestion = consider using the `naked_asm!` macro instead
|
||||
|
||||
passes_naked_functions_operands =
|
||||
only `const` and `sym` operands are supported in naked functions
|
||||
|
|
|
@ -1202,12 +1202,12 @@ pub(crate) struct NakedFunctionsAsmOptions {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_naked_functions_must_use_noreturn, code = E0787)]
|
||||
pub(crate) struct NakedFunctionsMustUseNoreturn {
|
||||
#[diag(passes_naked_functions_must_naked_asm, code = E0787)]
|
||||
pub(crate) struct NakedFunctionsMustNakedAsm {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = ", options(noreturn)", applicability = "machine-applicable")]
|
||||
pub last_span: Span,
|
||||
#[suggestion(code = "naked_asm!", applicability = "machine-applicable")]
|
||||
pub macro_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
@ -10,13 +10,13 @@ use rustc_middle::hir::nested_filter::OnlyBodies;
|
|||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{BytePos, Span};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::errors::{
|
||||
NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions,
|
||||
NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed,
|
||||
NakedFunctionsMustNakedAsm, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed,
|
||||
UndefinedNakedFunctionAbi,
|
||||
};
|
||||
|
||||
|
@ -121,21 +121,29 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
|
|||
fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) {
|
||||
let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
|
||||
this.visit_body(body);
|
||||
if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
|
||||
if let [(ItemKind::NakedAsm | ItemKind::Err, _)] = this.items[..] {
|
||||
// Ok.
|
||||
} else {
|
||||
let mut must_show_error = false;
|
||||
let mut has_asm = false;
|
||||
let mut has_naked_asm = false;
|
||||
let mut has_err = false;
|
||||
let mut multiple_asms = vec![];
|
||||
let mut non_asms = vec![];
|
||||
for &(kind, span) in &this.items {
|
||||
match kind {
|
||||
ItemKind::Asm if has_asm => {
|
||||
ItemKind::NakedAsm if has_naked_asm => {
|
||||
must_show_error = true;
|
||||
multiple_asms.push(span);
|
||||
}
|
||||
ItemKind::Asm => has_asm = true,
|
||||
ItemKind::NakedAsm => has_naked_asm = true,
|
||||
ItemKind::InlineAsm => {
|
||||
has_err = true;
|
||||
|
||||
// the span that contains the `asm!` call,
|
||||
// so tooling can replace it with `naked_asm!`
|
||||
let macro_span = span.with_hi(span.lo() + BytePos("asm!".len() as u32));
|
||||
tcx.dcx().emit_err(NakedFunctionsMustNakedAsm { span, macro_span });
|
||||
}
|
||||
ItemKind::NonAsm => {
|
||||
must_show_error = true;
|
||||
non_asms.push(span);
|
||||
|
@ -164,7 +172,8 @@ struct CheckInlineAssembly<'tcx> {
|
|||
|
||||
#[derive(Copy, Clone)]
|
||||
enum ItemKind {
|
||||
Asm,
|
||||
NakedAsm,
|
||||
InlineAsm,
|
||||
NonAsm,
|
||||
Err,
|
||||
}
|
||||
|
@ -205,8 +214,18 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
|
|||
}
|
||||
|
||||
ExprKind::InlineAsm(asm) => {
|
||||
self.items.push((ItemKind::Asm, span));
|
||||
self.check_inline_asm(asm, span);
|
||||
match asm.asm_macro {
|
||||
rustc_ast::AsmMacro::Asm => {
|
||||
self.items.push((ItemKind::InlineAsm, span));
|
||||
}
|
||||
rustc_ast::AsmMacro::NakedAsm => {
|
||||
self.items.push((ItemKind::NakedAsm, span));
|
||||
self.check_inline_asm(asm, span);
|
||||
}
|
||||
rustc_ast::AsmMacro::GlobalAsm => {
|
||||
// not allowed in this position
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExprKind::DropTemps(..) | ExprKind::Block(..) => {
|
||||
|
@ -250,16 +269,6 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
|
|||
.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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue