Skip to content

Commit 96f92ea

Browse files
committed
migrate naked_functions.rs to translateable diagnostics
1 parent 69766e4 commit 96f92ea

File tree

3 files changed

+129
-59
lines changed

3 files changed

+129
-59
lines changed

compiler/rustc_error_messages/locales/en-US/passes.ftl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,3 +467,31 @@ passes_unlabeled_in_labeled_block =
467467
passes_unlabeled_cf_in_while_condition =
468468
`break` or `continue` with no label in the condition of a `while` loop
469469
.label = unlabeled `{$cf_type}` in the condition of a `while` loop
470+
471+
passes_cannot_inline_naked_function =
472+
naked functions cannot be inlined
473+
474+
passes_undefined_naked_function_abi =
475+
Rust ABI is unsupported in naked functions
476+
477+
passes_no_patterns =
478+
patterns not allowed in naked function parameters
479+
480+
passes_params_not_allowed =
481+
referencing function parameters is not allowed in naked functions
482+
.help = follow the calling convention in asm block to use parameters
483+
484+
passes_naked_functions_asm_block =
485+
naked functions must contain a single asm block
486+
.label_multiple_asm = multiple asm blocks are unsupported in naked functions
487+
.label_non_asm = non-asm is unsupported in naked functions
488+
489+
passes_naked_functions_operands =
490+
only `const` and `sym` operands are supported in naked functions
491+
492+
passes_naked_functions_asm_options =
493+
asm options unsupported in naked functions: {$unsupported_options}
494+
495+
passes_naked_functions_must_use_noreturn =
496+
asm in naked functions must use `noreturn` option
497+
.suggestion = consider specifying that the asm block is responsible for returning from the function

compiler/rustc_passes/src/errors.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -987,3 +987,79 @@ pub struct UnlabeledCfInWhileCondition<'a> {
987987
pub span: Span,
988988
pub cf_type: &'a str,
989989
}
990+
991+
#[derive(Diagnostic)]
992+
#[diag(passes::cannot_inline_naked_function)]
993+
pub struct CannotInlineNakedFunction {
994+
#[primary_span]
995+
pub span: Span,
996+
}
997+
998+
#[derive(LintDiagnostic)]
999+
#[diag(passes::undefined_naked_function_abi)]
1000+
pub struct UndefinedNakedFunctionAbi;
1001+
1002+
#[derive(Diagnostic)]
1003+
#[diag(passes::no_patterns)]
1004+
pub struct NoPatterns {
1005+
#[primary_span]
1006+
pub span: Span,
1007+
}
1008+
1009+
#[derive(Diagnostic)]
1010+
#[diag(passes::params_not_allowed)]
1011+
#[help]
1012+
pub struct ParamsNotAllowed {
1013+
#[primary_span]
1014+
pub span: Span,
1015+
}
1016+
1017+
pub struct NakedFunctionsAsmBlock {
1018+
pub span: Span,
1019+
pub multiple_asms: Vec<Span>,
1020+
pub non_asms: Vec<Span>,
1021+
}
1022+
1023+
impl IntoDiagnostic<'_> for NakedFunctionsAsmBlock {
1024+
fn into_diagnostic(
1025+
self,
1026+
handler: &rustc_errors::Handler,
1027+
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
1028+
let mut diag = handler.struct_span_err_with_code(
1029+
self.span,
1030+
rustc_errors::fluent::passes::naked_functions_asm_block,
1031+
error_code!(E0787),
1032+
);
1033+
for span in self.multiple_asms.iter() {
1034+
diag.span_label(*span, rustc_errors::fluent::passes::label_multiple_asm);
1035+
}
1036+
for span in self.non_asms.iter() {
1037+
diag.span_label(*span, rustc_errors::fluent::passes::label_non_asm);
1038+
}
1039+
diag
1040+
}
1041+
}
1042+
1043+
#[derive(Diagnostic)]
1044+
#[diag(passes::naked_functions_operands, code = "E0787")]
1045+
pub struct NakedFunctionsOperands {
1046+
#[primary_span]
1047+
pub unsupported_operands: Vec<Span>,
1048+
}
1049+
1050+
#[derive(Diagnostic)]
1051+
#[diag(passes::naked_functions_asm_options, code = "E0787")]
1052+
pub struct NakedFunctionsAsmOptions {
1053+
#[primary_span]
1054+
pub span: Span,
1055+
pub unsupported_options: String,
1056+
}
1057+
1058+
#[derive(Diagnostic)]
1059+
#[diag(passes::naked_functions_must_use_noreturn, code = "E0787")]
1060+
pub struct NakedFunctionsMustUseNoreturn {
1061+
#[primary_span]
1062+
pub span: Span,
1063+
#[suggestion(code = ", options(noreturn)", applicability = "machine-applicable")]
1064+
pub last_span: Span,
1065+
}

compiler/rustc_passes/src/naked_functions.rs

Lines changed: 25 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! Checks validity of naked functions.
22
33
use rustc_ast::InlineAsmOptions;
4-
use rustc_errors::{struct_span_err, Applicability};
54
use rustc_hir as hir;
65
use rustc_hir::def::DefKind;
76
use rustc_hir::def_id::LocalDefId;
@@ -14,6 +13,12 @@ use rustc_span::symbol::sym;
1413
use rustc_span::Span;
1514
use rustc_target::spec::abi::Abi;
1615

16+
use crate::errors::{
17+
CannotInlineNakedFunction, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions,
18+
NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed,
19+
UndefinedNakedFunctionAbi,
20+
};
21+
1722
pub(crate) fn provide(providers: &mut Providers) {
1823
*providers = Providers { check_mod_naked_functions, ..*providers };
1924
}
@@ -56,7 +61,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
5661
fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) {
5762
let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline);
5863
for attr in attrs {
59-
tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
64+
tcx.sess.emit_err(CannotInlineNakedFunction { span: attr.span });
6065
}
6166
}
6267

@@ -65,12 +70,11 @@ fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) {
6570
if abi == Abi::Rust {
6671
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
6772
let span = tcx.def_span(def_id);
68-
tcx.struct_span_lint_hir(
73+
tcx.emit_spanned_lint(
6974
UNDEFINED_NAKED_FUNCTION_ABI,
7075
hir_id,
7176
span,
72-
"Rust ABI is unsupported in naked functions",
73-
|lint| lint,
77+
UndefinedNakedFunctionAbi,
7478
);
7579
}
7680
}
@@ -82,12 +86,7 @@ fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
8286
hir::PatKind::Wild
8387
| hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, _, None) => {}
8488
_ => {
85-
tcx.sess
86-
.struct_span_err(
87-
param.pat.span,
88-
"patterns not allowed in naked function parameters",
89-
)
90-
.emit();
89+
tcx.sess.emit_err(NoPatterns { span: param.pat.span });
9190
}
9291
}
9392
}
@@ -117,14 +116,7 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
117116
)) = expr.kind
118117
{
119118
if self.params.contains(var_hir_id) {
120-
self.tcx
121-
.sess
122-
.struct_span_err(
123-
expr.span,
124-
"referencing function parameters is not allowed in naked functions",
125-
)
126-
.help("follow the calling convention in asm block to use parameters")
127-
.emit();
119+
self.tcx.sess.emit_err(ParamsNotAllowed { span: expr.span });
128120
return;
129121
}
130122
}
@@ -139,26 +131,21 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<
139131
if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
140132
// Ok.
141133
} else {
142-
let mut diag = struct_span_err!(
143-
tcx.sess,
144-
tcx.def_span(def_id),
145-
E0787,
146-
"naked functions must contain a single asm block"
147-
);
148-
149134
let mut must_show_error = false;
150135
let mut has_asm = false;
151136
let mut has_err = false;
137+
let mut multiple_asms = vec![];
138+
let mut non_asms = vec![];
152139
for &(kind, span) in &this.items {
153140
match kind {
154141
ItemKind::Asm if has_asm => {
155142
must_show_error = true;
156-
diag.span_label(span, "multiple asm blocks are unsupported in naked functions");
143+
multiple_asms.push(span);
157144
}
158145
ItemKind::Asm => has_asm = true,
159146
ItemKind::NonAsm => {
160147
must_show_error = true;
161-
diag.span_label(span, "non-asm is unsupported in naked functions");
148+
non_asms.push(span);
162149
}
163150
ItemKind::Err => has_err = true,
164151
}
@@ -168,9 +155,11 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<
168155
// errors, then don't show an additional error. This allows for appending/prepending
169156
// `compile_error!("...")` statements and reduces error noise.
170157
if must_show_error || !has_err {
171-
diag.emit();
172-
} else {
173-
diag.cancel();
158+
tcx.sess.emit_err(NakedFunctionsAsmBlock {
159+
span: tcx.def_span(def_id),
160+
multiple_asms,
161+
non_asms,
162+
});
174163
}
175164
}
176165
}
@@ -251,13 +240,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
251240
})
252241
.collect();
253242
if !unsupported_operands.is_empty() {
254-
struct_span_err!(
255-
self.tcx.sess,
256-
unsupported_operands,
257-
E0787,
258-
"only `const` and `sym` operands are supported in naked functions",
259-
)
260-
.emit();
243+
self.tcx.sess.emit_err(NakedFunctionsOperands { unsupported_operands });
261244
}
262245

263246
let unsupported_options: Vec<&'static str> = [
@@ -273,14 +256,10 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
273256
.collect();
274257

275258
if !unsupported_options.is_empty() {
276-
struct_span_err!(
277-
self.tcx.sess,
259+
self.tcx.sess.emit_err(NakedFunctionsAsmOptions {
278260
span,
279-
E0787,
280-
"asm options unsupported in naked functions: {}",
281-
unsupported_options.join(", ")
282-
)
283-
.emit();
261+
unsupported_options: unsupported_options.join(", "),
262+
});
284263
}
285264

286265
if !asm.options.contains(InlineAsmOptions::NORETURN) {
@@ -290,20 +269,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
290269
.map_or_else(|| asm.template_strs.last().unwrap().2, |op| op.1)
291270
.shrink_to_hi();
292271

293-
struct_span_err!(
294-
self.tcx.sess,
295-
span,
296-
E0787,
297-
"asm in naked functions must use `noreturn` option"
298-
)
299-
.span_suggestion(
300-
last_span,
301-
"consider specifying that the asm block is responsible \
302-
for returning from the function",
303-
", options(noreturn)",
304-
Applicability::MachineApplicable,
305-
)
306-
.emit();
272+
self.tcx.sess.emit_err(NakedFunctionsMustUseNoreturn { span, last_span });
307273
}
308274
}
309275
}

0 commit comments

Comments
 (0)