Skip to content

Commit 309496c

Browse files
authored
Rollup merge of #108760 - clubby789:autolintstuff, r=wesleywiser
Add lint to deny diagnostics composed of static strings r? ghost I'm hoping to have a lint that semi-automatically converts simple diagnostics such as `struct_span_err(span, "msg").help("msg").span_note(span2, "msg").emit()` to typed session diagnostics. It's quite hacky and not entirely working because of problems with `x fix` but should hopefully help reduce some of the work. I'm going to start trying to apply what I can from this, but opening this as a draft in case anyone wants to develop on it. cc #100717
2 parents 8763965 + 0138513 commit 309496c

37 files changed

+578
-201
lines changed

compiler/rustc_builtin_macros/messages.ftl

+19
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,25 @@ builtin_macros_format_pos_mismatch = {$n} positional {$n ->
149149
[one] argument
150150
*[more] arguments
151151
} in format string, but {$desc}
152+
152153
builtin_macros_offset_of_expected_field = expected field
153154
154155
builtin_macros_offset_of_expected_two_args = expected 2 arguments
156+
157+
builtin_macros_test_case_non_item = `#[test_case]` attribute is only allowed on items
158+
159+
builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests
160+
.label = `{$kind}` because of this
161+
162+
builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names
163+
164+
builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive
165+
166+
builtin_macros_asm_pure_combine = the `pure` option must be combined with either `nomem` or `readonly`
167+
168+
builtin_macros_asm_pure_no_output = asm with the `pure` option must have at least one output
169+
170+
builtin_macros_asm_modifier_invalid = asm template modifier must be a single character
171+
172+
builtin_macros_test_runner_invalid = `test_runner` argument must be a path
173+
builtin_macros_test_runner_nargs = `#![test_runner(..)]` accepts exactly 1 argument

compiler/rustc_builtin_macros/src/asm.rs

+8-20
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use rustc_span::{InnerSpan, Span};
1515
use rustc_target::asm::InlineAsmArch;
1616
use smallvec::smallvec;
1717

18+
use crate::errors;
19+
1820
pub struct AsmArgs {
1921
pub templates: Vec<P<ast::Expr>>,
2022
pub operands: Vec<(ast::InlineAsmOperand, Span)>,
@@ -205,7 +207,7 @@ pub fn parse_asm_args<'a>(
205207
// of the argument available.
206208
if explicit_reg {
207209
if name.is_some() {
208-
diag.struct_span_err(span, "explicit register arguments cannot have names").emit();
210+
diag.emit_err(errors::AsmExplicitRegisterName { span });
209211
}
210212
args.reg_args.insert(slot);
211213
} else if let Some(name) = name {
@@ -240,25 +242,19 @@ pub fn parse_asm_args<'a>(
240242
&& args.options.contains(ast::InlineAsmOptions::READONLY)
241243
{
242244
let spans = args.options_spans.clone();
243-
diag.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive")
244-
.emit();
245+
diag.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "nomem", opt2: "readonly" });
245246
}
246247
if args.options.contains(ast::InlineAsmOptions::PURE)
247248
&& args.options.contains(ast::InlineAsmOptions::NORETURN)
248249
{
249250
let spans = args.options_spans.clone();
250-
diag.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive")
251-
.emit();
251+
diag.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "pure", opt2: "noreturn" });
252252
}
253253
if args.options.contains(ast::InlineAsmOptions::PURE)
254254
&& !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
255255
{
256256
let spans = args.options_spans.clone();
257-
diag.struct_span_err(
258-
spans,
259-
"the `pure` option must be combined with either `nomem` or `readonly`",
260-
)
261-
.emit();
257+
diag.emit_err(errors::AsmPureCombine { spans });
262258
}
263259

264260
let mut have_real_output = false;
@@ -285,11 +281,7 @@ pub fn parse_asm_args<'a>(
285281
}
286282
}
287283
if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
288-
diag.struct_span_err(
289-
args.options_spans.clone(),
290-
"asm with the `pure` option must have at least one output",
291-
)
292-
.emit();
284+
diag.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() });
293285
}
294286
if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() {
295287
let err = diag
@@ -705,11 +697,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
705697
.ty_span
706698
.map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end)))
707699
.unwrap_or(template_sp);
708-
ecx.struct_span_err(
709-
span,
710-
"asm template modifier must be a single character",
711-
)
712-
.emit();
700+
ecx.emit_err(errors::AsmModifierInvalid { span });
713701
modifier = None;
714702
}
715703

compiler/rustc_builtin_macros/src/errors.rs

+68
Original file line numberDiff line numberDiff line change
@@ -551,3 +551,71 @@ pub(crate) struct FormatPositionalMismatch {
551551
#[subdiagnostic]
552552
pub(crate) highlight: SingleLabelManySpans,
553553
}
554+
555+
#[derive(Diagnostic)]
556+
#[diag(builtin_macros_test_case_non_item)]
557+
pub(crate) struct TestCaseNonItem {
558+
#[primary_span]
559+
pub(crate) span: Span,
560+
}
561+
562+
#[derive(Diagnostic)]
563+
#[diag(builtin_macros_test_bad_fn)]
564+
pub(crate) struct TestBadFn {
565+
#[primary_span]
566+
pub(crate) span: Span,
567+
#[label]
568+
pub(crate) cause: Span,
569+
pub(crate) kind: &'static str,
570+
}
571+
572+
#[derive(Diagnostic)]
573+
#[diag(builtin_macros_asm_explicit_register_name)]
574+
pub(crate) struct AsmExplicitRegisterName {
575+
#[primary_span]
576+
pub(crate) span: Span,
577+
}
578+
579+
#[derive(Diagnostic)]
580+
#[diag(builtin_macros_asm_mutually_exclusive)]
581+
pub(crate) struct AsmMutuallyExclusive {
582+
#[primary_span]
583+
pub(crate) spans: Vec<Span>,
584+
pub(crate) opt1: &'static str,
585+
pub(crate) opt2: &'static str,
586+
}
587+
588+
#[derive(Diagnostic)]
589+
#[diag(builtin_macros_asm_pure_combine)]
590+
pub(crate) struct AsmPureCombine {
591+
#[primary_span]
592+
pub(crate) spans: Vec<Span>,
593+
}
594+
595+
#[derive(Diagnostic)]
596+
#[diag(builtin_macros_asm_pure_no_output)]
597+
pub(crate) struct AsmPureNoOutput {
598+
#[primary_span]
599+
pub(crate) spans: Vec<Span>,
600+
}
601+
602+
#[derive(Diagnostic)]
603+
#[diag(builtin_macros_asm_modifier_invalid)]
604+
pub(crate) struct AsmModifierInvalid {
605+
#[primary_span]
606+
pub(crate) span: Span,
607+
}
608+
609+
#[derive(Diagnostic)]
610+
#[diag(builtin_macros_test_runner_invalid)]
611+
pub(crate) struct TestRunnerInvalid {
612+
#[primary_span]
613+
pub(crate) span: Span,
614+
}
615+
616+
#[derive(Diagnostic)]
617+
#[diag(builtin_macros_test_runner_nargs)]
618+
pub(crate) struct TestRunnerNargs {
619+
#[primary_span]
620+
pub(crate) span: Span,
621+
}

compiler/rustc_builtin_macros/src/test.rs

+4-12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::errors;
12
/// The expansion from a test function to the appropriate test struct for libtest
23
/// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
34
use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
@@ -40,12 +41,7 @@ pub fn expand_test_case(
4041
unreachable!()
4142
},
4243
_ => {
43-
ecx.struct_span_err(
44-
anno_item.span(),
45-
"`#[test_case]` attribute is only allowed on items",
46-
)
47-
.emit();
48-
44+
ecx.emit_err(errors::TestCaseNonItem { span: anno_item.span() });
4945
return vec![];
5046
}
5147
};
@@ -533,15 +529,11 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
533529
match &i.kind {
534530
ast::ItemKind::Fn(box ast::Fn { sig, generics, .. }) => {
535531
if let ast::Unsafe::Yes(span) = sig.header.unsafety {
536-
sd.struct_span_err(i.span, "unsafe functions cannot be used for tests")
537-
.span_label(span, "`unsafe` because of this")
538-
.emit();
532+
sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" });
539533
return false;
540534
}
541535
if let ast::Async::Yes { span, .. } = sig.header.asyncness {
542-
sd.struct_span_err(i.span, "async functions cannot be used for tests")
543-
.span_label(span, "`async` because of this")
544-
.emit();
536+
sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "async" });
545537
return false;
546538
}
547539

compiler/rustc_builtin_macros/src/test_harness.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ use tracing::debug;
1919

2020
use std::{iter, mem};
2121

22+
use crate::errors;
23+
2224
#[derive(Clone)]
2325
struct Test {
2426
span: Span,
@@ -385,11 +387,11 @@ fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast
385387
[single] => match single.meta_item() {
386388
Some(meta_item) if meta_item.is_word() => return Some(meta_item.path.clone()),
387389
_ => {
388-
sd.struct_span_err(span, "`test_runner` argument must be a path").emit();
390+
sd.emit_err(errors::TestRunnerInvalid { span });
389391
}
390392
},
391393
_ => {
392-
sd.struct_span_err(span, "`#![test_runner(..)]` accepts exactly 1 argument").emit();
394+
sd.emit_err(errors::TestRunnerNargs { span });
393395
}
394396
}
395397
None

compiler/rustc_codegen_ssa/messages.ftl

+13
Original file line numberDiff line numberDiff line change
@@ -291,3 +291,16 @@ codegen_ssa_invalid_monomorphization_unsupported_cast = invalid monomorphization
291291
codegen_ssa_invalid_monomorphization_unsupported_operation = invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}`
292292
293293
codegen_ssa_invalid_monomorphization_expected_vector_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of vector type `{$vector_type}` to be a signed or unsigned integer type
294+
295+
codegen_ssa_invalid_no_sanitize = invalid argument for `no_sanitize`
296+
.note = expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
297+
298+
codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]`
299+
.note = the attribute requires exactly one argument
300+
301+
codegen_ssa_illegal_link_ordinal_format = illegal ordinal format in `link_ordinal`
302+
.note = an unsuffixed integer value, e.g., `1`, is expected
303+
304+
codegen_ssa_target_feature_safe_trait = `#[target_feature(..)]` cannot be applied to safe trait method
305+
.label = cannot be applied to safe trait method
306+
.label_def = not an `unsafe` function

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

+4-12
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use rustc_span::symbol::Ident;
1414
use rustc_span::{sym, Span};
1515
use rustc_target::spec::{abi, SanitizerSet};
1616

17+
use crate::errors;
1718
use crate::target_features::from_target_feature;
1819
use crate::{errors::ExpectedUsedSymbol, target_features::check_target_feature_trait_unsafe};
1920

@@ -334,10 +335,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
334335
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS
335336
}
336337
_ => {
337-
tcx.sess
338-
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
339-
.note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
340-
.emit();
338+
tcx.sess.emit_err(errors::InvalidNoSanitize { span: item.span() });
341339
}
342340
}
343341
}
@@ -608,10 +606,7 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
608606
let sole_meta_list = match meta_item_list {
609607
Some([item]) => item.lit(),
610608
Some(_) => {
611-
tcx.sess
612-
.struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`")
613-
.note("the attribute requires exactly one argument")
614-
.emit();
609+
tcx.sess.emit_err(errors::InvalidLinkOrdinalNargs { span: attr.span });
615610
return None;
616611
}
617612
_ => None,
@@ -642,10 +637,7 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
642637
None
643638
}
644639
} else {
645-
tcx.sess
646-
.struct_span_err(attr.span, "illegal ordinal format in `link_ordinal`")
647-
.note("an unsuffixed integer value, e.g., `1`, is expected")
648-
.emit();
640+
tcx.sess.emit_err(errors::InvalidLinkOrdinalFormat { span: attr.span });
649641
None
650642
}
651643
}

compiler/rustc_codegen_ssa/src/errors.rs

+34
Original file line numberDiff line numberDiff line change
@@ -981,3 +981,37 @@ impl IntoDiagnosticArg for ExpectedPointerMutability {
981981
}
982982
}
983983
}
984+
985+
#[derive(Diagnostic)]
986+
#[diag(codegen_ssa_invalid_no_sanitize)]
987+
#[note]
988+
pub struct InvalidNoSanitize {
989+
#[primary_span]
990+
pub span: Span,
991+
}
992+
993+
#[derive(Diagnostic)]
994+
#[diag(codegen_ssa_invalid_link_ordinal_nargs)]
995+
#[note]
996+
pub struct InvalidLinkOrdinalNargs {
997+
#[primary_span]
998+
pub span: Span,
999+
}
1000+
1001+
#[derive(Diagnostic)]
1002+
#[diag(codegen_ssa_illegal_link_ordinal_format)]
1003+
#[note]
1004+
pub struct InvalidLinkOrdinalFormat {
1005+
#[primary_span]
1006+
pub span: Span,
1007+
}
1008+
1009+
#[derive(Diagnostic)]
1010+
#[diag(codegen_ssa_target_feature_safe_trait)]
1011+
pub struct TargetFeatureSafeTrait {
1012+
#[primary_span]
1013+
#[label]
1014+
pub span: Span,
1015+
#[label(codegen_ssa_label_def)]
1016+
pub def: Span,
1017+
}

compiler/rustc_codegen_ssa/src/target_features.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::errors;
12
use rustc_ast::ast;
23
use rustc_attr::InstructionSetAttr;
34
use rustc_data_structures::fx::FxHashMap;
@@ -443,14 +444,10 @@ pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_s
443444
if let DefKind::AssocFn = tcx.def_kind(id) {
444445
let parent_id = tcx.local_parent(id);
445446
if let DefKind::Trait | DefKind::Impl { of_trait: true } = tcx.def_kind(parent_id) {
446-
tcx.sess
447-
.struct_span_err(
448-
attr_span,
449-
"`#[target_feature(..)]` cannot be applied to safe trait method",
450-
)
451-
.span_label(attr_span, "cannot be applied to safe trait method")
452-
.span_label(tcx.def_span(id), "not an `unsafe` function")
453-
.emit();
447+
tcx.sess.emit_err(errors::TargetFeatureSafeTrait {
448+
span: attr_span,
449+
def: tcx.def_span(id),
450+
});
454451
}
455452
}
456453
}

compiler/rustc_expand/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,7 @@ expand_proc_macro_panicked =
136136
137137
expand_proc_macro_derive_tokens =
138138
proc-macro derive produced unparsable tokens
139+
140+
expand_duplicate_matcher_binding = duplicate matcher binding
141+
.label = duplicate binding
142+
.label2 = previous binding

compiler/rustc_expand/src/errors.rs

+10
Original file line numberDiff line numberDiff line change
@@ -397,3 +397,13 @@ pub struct ProcMacroDeriveTokens {
397397
#[primary_span]
398398
pub span: Span,
399399
}
400+
401+
#[derive(Diagnostic)]
402+
#[diag(expand_duplicate_matcher_binding)]
403+
pub struct DuplicateMatcherBinding {
404+
#[primary_span]
405+
#[label]
406+
pub span: Span,
407+
#[label(expand_label2)]
408+
pub prev: Span,
409+
}

compiler/rustc_expand/src/mbe/macro_check.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
//! Kleene operators under which a meta-variable is repeating is the concatenation of the stacks
105105
//! stored when entering a macro definition starting from the state in which the meta-variable is
106106
//! bound.
107+
use crate::errors;
107108
use crate::mbe::{KleeneToken, TokenTree};
108109

109110
use rustc_ast::token::{Delimiter, Token, TokenKind};
@@ -281,10 +282,7 @@ fn check_binders(
281282
// Duplicate binders at the top-level macro definition are errors. The lint is only
282283
// for nested macro definitions.
283284
sess.span_diagnostic
284-
.struct_span_err(span, "duplicate matcher binding")
285-
.span_label(span, "duplicate binding")
286-
.span_label(prev_info.span, "previous binding")
287-
.emit();
285+
.emit_err(errors::DuplicateMatcherBinding { span, prev: prev_info.span });
288286
*valid = false;
289287
} else {
290288
binders.insert(name, BinderInfo { span, ops: ops.into() });

0 commit comments

Comments
 (0)