1
Fork 0

disallow asm! in #[naked] functions

also disallow the `noreturn` option, and infer `naked_asm!` as `!`
This commit is contained in:
Folkert de Vries 2024-09-05 13:45:26 +02:00
parent 1a9c1cbf36
commit 562ec5a6fb
27 changed files with 223 additions and 298 deletions

View file

@ -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

View file

@ -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)]

View file

@ -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 });
}
}
}