Skip to content

Commit 055ce62

Browse files
committed
perf: Delay formatting of lint messages until they are know to be used
Found `check` builts in one of my crates spent 5% of the time just formatting types for the sake of the `BoxPointers` lint, only for the strings to get thrown away immediately since it is an `allow` lint. This does the bare minimum to instead pass a `fmt::Display` instance to the lint so that `msg` may only be created if it is needed. Unsure if this is the desired way to solve this problem so I didn't go through the lint system throughly to see if there were more places that should take/pass `format_args!` instances instead of using `format!`.
1 parent 580ac0b commit 055ce62

File tree

5 files changed

+62
-36
lines changed

5 files changed

+62
-36
lines changed

src/librustc/lint/context.rs

+21-11
Original file line numberDiff line numberDiff line change
@@ -497,8 +497,13 @@ pub trait LintContext: Sized {
497497
fn sess(&self) -> &Session;
498498
fn lints(&self) -> &LintStore;
499499

500-
fn lookup_and_emit<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: Option<S>, msg: &str) {
501-
self.lookup(lint, span, msg).emit();
500+
fn lookup_and_emit<S: Into<MultiSpan>>(
501+
&self,
502+
lint: &'static Lint,
503+
span: Option<S>,
504+
msg: impl std::fmt::Display,
505+
) {
506+
self.lookup(lint, span, &msg).emit();
502507
}
503508

504509
fn lookup_and_emit_with_diagnostics<S: Into<MultiSpan>>(
@@ -508,7 +513,7 @@ pub trait LintContext: Sized {
508513
msg: &str,
509514
diagnostic: BuiltinLintDiagnostics,
510515
) {
511-
let mut db = self.lookup(lint, span, msg);
516+
let mut db = self.lookup(lint, span, &msg);
512517
diagnostic.run(self.sess(), &mut db);
513518
db.emit();
514519
}
@@ -517,21 +522,26 @@ pub trait LintContext: Sized {
517522
&self,
518523
lint: &'static Lint,
519524
span: Option<S>,
520-
msg: &str,
525+
msg: impl std::fmt::Display,
521526
) -> DiagnosticBuilder<'_>;
522527

523528
/// Emit a lint at the appropriate level, for a particular span.
524-
fn span_lint<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: S, msg: &str) {
529+
fn span_lint<S: Into<MultiSpan>>(
530+
&self,
531+
lint: &'static Lint,
532+
span: S,
533+
msg: impl std::fmt::Display,
534+
) {
525535
self.lookup_and_emit(lint, Some(span), msg);
526536
}
527537

528538
fn struct_span_lint<S: Into<MultiSpan>>(
529539
&self,
530540
lint: &'static Lint,
531541
span: S,
532-
msg: &str,
542+
msg: impl std::fmt::Display,
533543
) -> DiagnosticBuilder<'_> {
534-
self.lookup(lint, Some(span), msg)
544+
self.lookup(lint, Some(span), &msg)
535545
}
536546

537547
/// Emit a lint and note at the appropriate level, for a particular span.
@@ -543,7 +553,7 @@ pub trait LintContext: Sized {
543553
note_span: Span,
544554
note: &str,
545555
) {
546-
let mut err = self.lookup(lint, Some(span), msg);
556+
let mut err = self.lookup(lint, Some(span), &msg);
547557
if note_span == span {
548558
err.note(note);
549559
} else {
@@ -554,7 +564,7 @@ pub trait LintContext: Sized {
554564

555565
/// Emit a lint and help at the appropriate level, for a particular span.
556566
fn span_lint_help(&self, lint: &'static Lint, span: Span, msg: &str, help: &str) {
557-
let mut err = self.lookup(lint, Some(span), msg);
567+
let mut err = self.lookup(lint, Some(span), &msg);
558568
self.span_lint(lint, span, msg);
559569
err.span_help(span, help);
560570
err.emit();
@@ -646,7 +656,7 @@ impl LintContext for LateContext<'_, '_> {
646656
&self,
647657
lint: &'static Lint,
648658
span: Option<S>,
649-
msg: &str,
659+
msg: impl std::fmt::Display,
650660
) -> DiagnosticBuilder<'_> {
651661
let hir_id = self.last_node_with_lint_attrs;
652662

@@ -673,7 +683,7 @@ impl LintContext for EarlyContext<'_> {
673683
&self,
674684
lint: &'static Lint,
675685
span: Option<S>,
676-
msg: &str,
686+
msg: impl std::fmt::Display,
677687
) -> DiagnosticBuilder<'_> {
678688
self.builder.struct_lint(lint, span.map(|s| s.into()), msg)
679689
}

src/librustc/lint/levels.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ impl<'a> LintLevelsBuilder<'a> {
471471
&self,
472472
lint: &'static Lint,
473473
span: Option<MultiSpan>,
474-
msg: &str,
474+
msg: impl std::fmt::Display,
475475
) -> DiagnosticBuilder<'a> {
476476
let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess);
477477
lint::struct_lint_level(self.sess, lint, level, src, span, msg)

src/librustc/lint/mod.rs

+19-6
Original file line numberDiff line numberDiff line change
@@ -437,14 +437,27 @@ pub fn struct_lint_level<'a>(
437437
level: Level,
438438
src: LintSource,
439439
span: Option<MultiSpan>,
440-
msg: &str,
440+
msg: impl std::fmt::Display,
441+
) -> DiagnosticBuilder<'a> {
442+
struct_lint_level_(sess, lint, level, src, span, &msg)
443+
}
444+
445+
fn struct_lint_level_<'a>(
446+
sess: &'a Session,
447+
lint: &'static Lint,
448+
level: Level,
449+
src: LintSource,
450+
span: Option<MultiSpan>,
451+
msg: &dyn std::fmt::Display,
441452
) -> DiagnosticBuilder<'a> {
442453
let mut err = match (level, span) {
443454
(Level::Allow, _) => return sess.diagnostic().struct_dummy(),
444-
(Level::Warn, Some(span)) => sess.struct_span_warn(span, msg),
445-
(Level::Warn, None) => sess.struct_warn(msg),
446-
(Level::Deny, Some(span)) | (Level::Forbid, Some(span)) => sess.struct_span_err(span, msg),
447-
(Level::Deny, None) | (Level::Forbid, None) => sess.struct_err(msg),
455+
(Level::Warn, Some(span)) => sess.struct_span_warn(span, &msg.to_string()),
456+
(Level::Warn, None) => sess.struct_warn(&msg.to_string()),
457+
(Level::Deny, Some(span)) | (Level::Forbid, Some(span)) => {
458+
sess.struct_span_err(span, &msg.to_string())
459+
}
460+
(Level::Deny, None) | (Level::Forbid, None) => sess.struct_err(&msg.to_string()),
448461
};
449462

450463
// Check for future incompatibility lints and issue a stronger warning.
@@ -536,7 +549,7 @@ pub fn struct_lint_level<'a>(
536549

537550
if let Some(future_incompatible) = future_incompatible {
538551
const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \
539-
it will become a hard error";
552+
it will become a hard error";
540553

541554
let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) {
542555
"once this method is added to the standard library, \

src/librustc/ty/context.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ fn validate_hir_id_for_typeck_tables(
211211
ty::tls::with(|tcx| {
212212
bug!(
213213
"node {} with HirId::owner {:?} cannot be placed in \
214-
TypeckTables with local_id_root {:?}",
214+
TypeckTables with local_id_root {:?}",
215215
tcx.hir().node_to_string(hir_id),
216216
DefId::local(hir_id.owner),
217217
local_id_root
@@ -2553,7 +2553,7 @@ impl<'tcx> TyCtxt<'tcx> {
25532553
lint: &'static Lint,
25542554
hir_id: HirId,
25552555
span: S,
2556-
msg: &str,
2556+
msg: impl std::fmt::Display,
25572557
) {
25582558
self.struct_span_lint_hir(lint, hir_id, span.into(), msg).emit()
25592559
}
@@ -2563,7 +2563,7 @@ impl<'tcx> TyCtxt<'tcx> {
25632563
lint: &'static Lint,
25642564
hir_id: HirId,
25652565
span: S,
2566-
msg: &str,
2566+
msg: impl std::fmt::Display,
25672567
note: &str,
25682568
) {
25692569
let mut err = self.struct_span_lint_hir(lint, hir_id, span.into(), msg);
@@ -2576,7 +2576,7 @@ impl<'tcx> TyCtxt<'tcx> {
25762576
lint: &'static Lint,
25772577
id: hir::HirId,
25782578
span: S,
2579-
msg: &str,
2579+
msg: impl std::fmt::Display,
25802580
note: &str,
25812581
) {
25822582
let mut err = self.struct_span_lint_hir(lint, id, span.into(), msg);
@@ -2629,7 +2629,7 @@ impl<'tcx> TyCtxt<'tcx> {
26292629
lint: &'static Lint,
26302630
hir_id: HirId,
26312631
span: S,
2632-
msg: &str,
2632+
msg: impl std::fmt::Display,
26332633
) -> DiagnosticBuilder<'tcx> {
26342634
let (level, src) = self.lint_level_at_node(lint, hir_id);
26352635
lint::struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg)
@@ -2639,7 +2639,7 @@ impl<'tcx> TyCtxt<'tcx> {
26392639
self,
26402640
lint: &'static Lint,
26412641
id: HirId,
2642-
msg: &str,
2642+
msg: impl std::fmt::Display,
26432643
) -> DiagnosticBuilder<'tcx> {
26442644
let (level, src) = self.lint_level_at_node(lint, id);
26452645
lint::struct_lint_level(self.sess, lint, level, src, None, msg)

src/librustc_lint/builtin.rs

+15-12
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,11 @@ impl BoxPointers {
109109
fn check_heap_type(&self, cx: &LateContext<'_, '_>, span: Span, ty: Ty<'_>) {
110110
for leaf_ty in ty.walk() {
111111
if leaf_ty.is_box() {
112-
let m = format!("type uses owned (Box type) pointers: {}", ty);
113-
cx.span_lint(BOX_POINTERS, span, &m);
112+
cx.span_lint(
113+
BOX_POINTERS,
114+
span,
115+
format_args!("type uses owned (Box type) pointers: {}", ty),
116+
);
114117
}
115118
}
116119
}
@@ -235,8 +238,8 @@ impl EarlyLintPass for UnsafeCode {
235238
cx,
236239
attr.span,
237240
"`allow_internal_unsafe` allows defining \
238-
macros using unsafe without triggering \
239-
the `unsafe_code` lint at their call site",
241+
macros using unsafe without triggering \
242+
the `unsafe_code` lint at their call site",
240243
);
241244
}
242245
}
@@ -379,7 +382,7 @@ impl MissingDoc {
379382
cx.span_lint(
380383
MISSING_DOCS,
381384
cx.tcx.sess.source_map().def_span(sp),
382-
&format!("missing documentation for {}", desc),
385+
format_args!("missing documentation for {}", desc),
383386
);
384387
}
385388
}
@@ -563,7 +566,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
563566
MISSING_COPY_IMPLEMENTATIONS,
564567
item.span,
565568
"type could implement `Copy`; consider adding `impl \
566-
Copy`",
569+
Copy`",
567570
)
568571
}
569572
}
@@ -617,7 +620,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations {
617620
MISSING_DEBUG_IMPLEMENTATIONS,
618621
item.span,
619622
"type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` \
620-
or a manual implementation",
623+
or a manual implementation",
621624
)
622625
}
623626
}
@@ -663,7 +666,7 @@ impl EarlyLintPass for AnonymousParameters {
663666
.span_suggestion(
664667
arg.pat.span,
665668
"Try naming the parameter or explicitly \
666-
ignoring it",
669+
ignoring it",
667670
format!("_: {}", ty_snip),
668671
appl,
669672
)
@@ -783,7 +786,7 @@ impl UnusedDocComment {
783786
if is_macro_expansion {
784787
err.help(
785788
"to document an item produced by a macro, \
786-
the macro must produce the documentation as part of its expansion",
789+
the macro must produce the documentation as part of its expansion",
787790
);
788791
}
789792

@@ -1249,7 +1252,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
12491252
span,
12501253
&format!(
12511254
"{} bound {} does not depend on any type \
1252-
or lifetime parameters",
1255+
or lifetime parameters",
12531256
predicate_kind_name, predicate
12541257
),
12551258
);
@@ -1473,7 +1476,7 @@ impl KeywordIdents {
14731476
let mut lint = cx.struct_span_lint(
14741477
KEYWORD_IDENTS,
14751478
ident.span,
1476-
&format!("`{}` is a keyword in the {} edition", ident, next_edition),
1479+
format_args!("`{}` is a keyword in the {} edition", ident, next_edition),
14771480
);
14781481
lint.span_suggestion(
14791482
ident.span,
@@ -2033,7 +2036,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
20332036
err.span_label(
20342037
expr.span,
20352038
"help: use `MaybeUninit<T>` instead, \
2036-
and only call `assume_init` after initialization is done",
2039+
and only call `assume_init` after initialization is done",
20372040
);
20382041
if let Some(span) = span {
20392042
err.span_note(span, &msg);

0 commit comments

Comments
 (0)