Refactor rustc lint API

This commit is contained in:
Maybe Waffle 2022-09-16 11:01:02 +04:00
parent 65445a571c
commit a8f7e244b7
64 changed files with 1760 additions and 1555 deletions

View file

@ -1,4 +1,4 @@
use rustc_errors::{DiagnosticBuilder, LintDiagnosticBuilder};
use rustc_errors::{DiagnosticBuilder, DiagnosticMessage};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
@ -63,7 +63,10 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
place: &Place<'tcx>,
const_item: DefId,
location: Location,
decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b, ()>) -> DiagnosticBuilder<'b, ()>,
msg: impl Into<DiagnosticMessage>,
decorate: impl for<'a, 'b> FnOnce(
&'a mut DiagnosticBuilder<'b, ()>,
) -> &'a mut DiagnosticBuilder<'b, ()>,
) {
// Don't lint on borrowing/assigning when a dereference is involved.
// If we 'leave' the temporary via a dereference, we must
@ -84,10 +87,10 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
CONST_ITEM_MUTATION,
lint_root,
source_info.span,
msg,
|lint| {
decorate(lint)
.span_note(self.tcx.def_span(const_item), "`const` item defined here")
.emit();
},
);
}
@ -102,10 +105,8 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
// so emitting a lint would be redundant.
if !lhs.projection.is_empty() {
if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
self.lint_const_item_usage(&lhs, def_id, loc, |lint| {
let mut lint = lint.build("attempting to modify a `const` item");
lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified");
lint
self.lint_const_item_usage(&lhs, def_id, loc, "attempting to modify a `const` item",|lint| {
lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified")
})
}
}
@ -137,8 +138,7 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
});
let lint_loc =
if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
self.lint_const_item_usage(place, def_id, lint_loc, |lint| {
let mut lint = lint.build("taking a mutable reference to a `const` item");
self.lint_const_item_usage(place, def_id, lint_loc, "taking a mutable reference to a `const` item", |lint| {
lint
.note("each usage of a `const` item creates a new temporary")
.note("the mutable reference will refer to this temporary, not the original `const` item");

View file

@ -33,21 +33,27 @@ struct PackedRefChecker<'a, 'tcx> {
fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
tcx.struct_span_lint_hir(UNALIGNED_REFERENCES, lint_hir_id, tcx.def_span(def_id), |lint| {
// FIXME: when we make this a hard error, this should have its
// own error code.
let extra = if tcx.generics_of(def_id).own_requires_monomorphization() {
"with type or const parameters"
} else {
"that does not derive `Copy`"
};
let message = format!(
"`{}` can't be derived on this `#[repr(packed)]` struct {}",
tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")),
extra
);
lint.build(message).emit();
});
// FIXME: when we make this a hard error, this should have its
// own error code.
let extra = if tcx.generics_of(def_id).own_requires_monomorphization() {
"with type or const parameters"
} else {
"that does not derive `Copy`"
};
let message = format!(
"`{}` can't be derived on this `#[repr(packed)]` struct {}",
tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")),
extra
);
tcx.struct_span_lint_hir(
UNALIGNED_REFERENCES,
lint_hir_id,
tcx.def_span(def_id),
message,
|lint| lint,
);
}
impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
@ -86,8 +92,9 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
UNALIGNED_REFERENCES,
lint_root,
source_info.span,
"reference to packed field is unaligned",
|lint| {
lint.build("reference to packed field is unaligned")
lint
.note(
"fields of packed structs are not properly aligned, and creating \
a misaligned reference is undefined behavior (even if that \
@ -98,7 +105,6 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
reference with a raw pointer and use `read_unaligned`/`write_unaligned` \
(loads and stores via `*p` must be properly aligned even when using raw pointers)"
)
.emit();
},
);
}

View file

@ -489,21 +489,20 @@ fn unsafety_check_result<'tcx>(
fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, |lint| {
let msg = "unnecessary `unsafe` block";
let mut db = lint.build(msg);
db.span_label(span, msg);
let msg = "unnecessary `unsafe` block";
tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, msg, |lint| {
lint.span_label(span, msg);
match kind {
UnusedUnsafe::Unused => {}
UnusedUnsafe::InUnsafeBlock(id) => {
db.span_label(
lint.span_label(
tcx.sess.source_map().guess_head_span(tcx.hir().span(id)),
"because it's nested under this `unsafe` block",
);
}
}
db.emit();
lint
});
}
@ -543,15 +542,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
UNSAFE_OP_IN_UNSAFE_FN,
lint_root,
source_info.span,
|lint| {
lint.build(&format!(
"{} is unsafe and requires unsafe block (error E0133)",
description,
))
.span_label(source_info.span, description)
.note(note)
.emit();
},
format!("{} is unsafe and requires unsafe block (error E0133)", description,),
|lint| lint.span_label(source_info.span, description).note(note),
),
}
}

View file

@ -347,10 +347,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
panic: AssertKind<impl std::fmt::Debug>,
) {
if let Some(lint_root) = self.lint_root(source_info) {
self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| {
let mut err = lint.build(message);
err.span_label(source_info.span, format!("{:?}", panic));
err.emit();
self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, message, |lint| {
lint.span_label(source_info.span, format!("{:?}", panic))
});
}
}

View file

@ -106,14 +106,12 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
.lint_root;
let span = terminator.source_info.span;
tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, |lint| {
let msg = match fn_def_id {
Some(_) => "call to foreign function with FFI-unwind ABI",
None => "call to function pointer with FFI-unwind ABI",
};
let mut db = lint.build(msg);
db.span_label(span, msg);
db.emit();
let msg = match fn_def_id {
Some(_) => "call to foreign function with FFI-unwind ABI",
None => "call to function pointer with FFI-unwind ABI",
};
tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, msg, |lint| {
lint.span_label(span, msg)
});
tainted = true;

View file

@ -179,11 +179,15 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder();
let variadic = if fn_sig.c_variadic() { ", ..." } else { "" };
let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };
self.tcx.struct_span_lint_hir(FUNCTION_ITEM_REFERENCES, lint_root, span, |lint| {
lint.build("taking a reference to a function item does not give a function pointer")
.span_suggestion(
self.tcx.struct_span_lint_hir(
FUNCTION_ITEM_REFERENCES,
lint_root,
span,
"taking a reference to a function item does not give a function pointer",
|lint| {
lint.span_suggestion(
span,
&format!("cast `{}` to obtain a function pointer", ident),
format!("cast `{}` to obtain a function pointer", ident),
format!(
"{} as {}{}fn({}{}){}",
if params.is_empty() { ident } else { format!("{}::<{}>", ident, params) },
@ -195,7 +199,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
),
Applicability::Unspecified,
)
.emit();
});
},
);
}
}