migrate naked_functions.rs to translateable diagnostics
This commit is contained in:
parent
69766e4f16
commit
96f92eab68
3 changed files with 129 additions and 59 deletions
|
|
@ -467,3 +467,31 @@ passes_unlabeled_in_labeled_block =
|
|||
passes_unlabeled_cf_in_while_condition =
|
||||
`break` or `continue` with no label in the condition of a `while` loop
|
||||
.label = unlabeled `{$cf_type}` in the condition of a `while` loop
|
||||
|
||||
passes_cannot_inline_naked_function =
|
||||
naked functions cannot be inlined
|
||||
|
||||
passes_undefined_naked_function_abi =
|
||||
Rust ABI is unsupported in naked functions
|
||||
|
||||
passes_no_patterns =
|
||||
patterns not allowed in naked function parameters
|
||||
|
||||
passes_params_not_allowed =
|
||||
referencing function parameters is not allowed in naked functions
|
||||
.help = follow the calling convention in asm block to use parameters
|
||||
|
||||
passes_naked_functions_asm_block =
|
||||
naked functions must contain a single asm block
|
||||
.label_multiple_asm = multiple asm blocks are unsupported in naked functions
|
||||
.label_non_asm = non-asm is unsupported in naked functions
|
||||
|
||||
passes_naked_functions_operands =
|
||||
only `const` and `sym` operands are supported in naked functions
|
||||
|
||||
passes_naked_functions_asm_options =
|
||||
asm options unsupported in naked functions: {$unsupported_options}
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -987,3 +987,79 @@ pub struct UnlabeledCfInWhileCondition<'a> {
|
|||
pub span: Span,
|
||||
pub cf_type: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes::cannot_inline_naked_function)]
|
||||
pub struct CannotInlineNakedFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes::undefined_naked_function_abi)]
|
||||
pub struct UndefinedNakedFunctionAbi;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes::no_patterns)]
|
||||
pub struct NoPatterns {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes::params_not_allowed)]
|
||||
#[help]
|
||||
pub struct ParamsNotAllowed {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
pub struct NakedFunctionsAsmBlock {
|
||||
pub span: Span,
|
||||
pub multiple_asms: Vec<Span>,
|
||||
pub non_asms: Vec<Span>,
|
||||
}
|
||||
|
||||
impl IntoDiagnostic<'_> for NakedFunctionsAsmBlock {
|
||||
fn into_diagnostic(
|
||||
self,
|
||||
handler: &rustc_errors::Handler,
|
||||
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||
let mut diag = handler.struct_span_err_with_code(
|
||||
self.span,
|
||||
rustc_errors::fluent::passes::naked_functions_asm_block,
|
||||
error_code!(E0787),
|
||||
);
|
||||
for span in self.multiple_asms.iter() {
|
||||
diag.span_label(*span, rustc_errors::fluent::passes::label_multiple_asm);
|
||||
}
|
||||
for span in self.non_asms.iter() {
|
||||
diag.span_label(*span, rustc_errors::fluent::passes::label_non_asm);
|
||||
}
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes::naked_functions_operands, code = "E0787")]
|
||||
pub struct NakedFunctionsOperands {
|
||||
#[primary_span]
|
||||
pub unsupported_operands: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes::naked_functions_asm_options, code = "E0787")]
|
||||
pub struct NakedFunctionsAsmOptions {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub unsupported_options: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes::naked_functions_must_use_noreturn, code = "E0787")]
|
||||
pub struct NakedFunctionsMustUseNoreturn {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = ", options(noreturn)", applicability = "machine-applicable")]
|
||||
pub last_span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
//! Checks validity of naked functions.
|
||||
|
||||
use rustc_ast::InlineAsmOptions;
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
|
|
@ -14,6 +13,12 @@ use rustc_span::symbol::sym;
|
|||
use rustc_span::Span;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::errors::{
|
||||
CannotInlineNakedFunction, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions,
|
||||
NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed,
|
||||
UndefinedNakedFunctionAbi,
|
||||
};
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { check_mod_naked_functions, ..*providers };
|
||||
}
|
||||
|
|
@ -56,7 +61,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
|||
fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline);
|
||||
for attr in attrs {
|
||||
tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
|
||||
tcx.sess.emit_err(CannotInlineNakedFunction { span: attr.span });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,12 +70,11 @@ fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) {
|
|||
if abi == Abi::Rust {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let span = tcx.def_span(def_id);
|
||||
tcx.struct_span_lint_hir(
|
||||
tcx.emit_spanned_lint(
|
||||
UNDEFINED_NAKED_FUNCTION_ABI,
|
||||
hir_id,
|
||||
span,
|
||||
"Rust ABI is unsupported in naked functions",
|
||||
|lint| lint,
|
||||
UndefinedNakedFunctionAbi,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -82,12 +86,7 @@ fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
|
|||
hir::PatKind::Wild
|
||||
| hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, _, None) => {}
|
||||
_ => {
|
||||
tcx.sess
|
||||
.struct_span_err(
|
||||
param.pat.span,
|
||||
"patterns not allowed in naked function parameters",
|
||||
)
|
||||
.emit();
|
||||
tcx.sess.emit_err(NoPatterns { span: param.pat.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -117,14 +116,7 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
|
|||
)) = expr.kind
|
||||
{
|
||||
if self.params.contains(var_hir_id) {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
expr.span,
|
||||
"referencing function parameters is not allowed in naked functions",
|
||||
)
|
||||
.help("follow the calling convention in asm block to use parameters")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(ParamsNotAllowed { span: expr.span });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -139,26 +131,21 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<
|
|||
if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
|
||||
// Ok.
|
||||
} else {
|
||||
let mut diag = struct_span_err!(
|
||||
tcx.sess,
|
||||
tcx.def_span(def_id),
|
||||
E0787,
|
||||
"naked functions must contain a single asm block"
|
||||
);
|
||||
|
||||
let mut must_show_error = false;
|
||||
let mut has_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 => {
|
||||
must_show_error = true;
|
||||
diag.span_label(span, "multiple asm blocks are unsupported in naked functions");
|
||||
multiple_asms.push(span);
|
||||
}
|
||||
ItemKind::Asm => has_asm = true,
|
||||
ItemKind::NonAsm => {
|
||||
must_show_error = true;
|
||||
diag.span_label(span, "non-asm is unsupported in naked functions");
|
||||
non_asms.push(span);
|
||||
}
|
||||
ItemKind::Err => has_err = true,
|
||||
}
|
||||
|
|
@ -168,9 +155,11 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<
|
|||
// errors, then don't show an additional error. This allows for appending/prepending
|
||||
// `compile_error!("...")` statements and reduces error noise.
|
||||
if must_show_error || !has_err {
|
||||
diag.emit();
|
||||
} else {
|
||||
diag.cancel();
|
||||
tcx.sess.emit_err(NakedFunctionsAsmBlock {
|
||||
span: tcx.def_span(def_id),
|
||||
multiple_asms,
|
||||
non_asms,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -251,13 +240,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
|
|||
})
|
||||
.collect();
|
||||
if !unsupported_operands.is_empty() {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
unsupported_operands,
|
||||
E0787,
|
||||
"only `const` and `sym` operands are supported in naked functions",
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(NakedFunctionsOperands { unsupported_operands });
|
||||
}
|
||||
|
||||
let unsupported_options: Vec<&'static str> = [
|
||||
|
|
@ -273,14 +256,10 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
|
|||
.collect();
|
||||
|
||||
if !unsupported_options.is_empty() {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
self.tcx.sess.emit_err(NakedFunctionsAsmOptions {
|
||||
span,
|
||||
E0787,
|
||||
"asm options unsupported in naked functions: {}",
|
||||
unsupported_options.join(", ")
|
||||
)
|
||||
.emit();
|
||||
unsupported_options: unsupported_options.join(", "),
|
||||
});
|
||||
}
|
||||
|
||||
if !asm.options.contains(InlineAsmOptions::NORETURN) {
|
||||
|
|
@ -290,20 +269,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
|
|||
.map_or_else(|| asm.template_strs.last().unwrap().2, |op| op.1)
|
||||
.shrink_to_hi();
|
||||
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0787,
|
||||
"asm in naked functions must use `noreturn` option"
|
||||
)
|
||||
.span_suggestion(
|
||||
last_span,
|
||||
"consider specifying that the asm block is responsible \
|
||||
for returning from the function",
|
||||
", options(noreturn)",
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(NakedFunctionsMustUseNoreturn { span, last_span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue