Make type validation buffer errors.

This commit is contained in:
Camille GILLOT 2023-07-19 10:44:00 +00:00
parent 030589d488
commit 2ef2ac0b51

View File

@ -72,8 +72,9 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
cfg_checker.visit_body(body); cfg_checker.visit_body(body);
cfg_checker.check_cleanup_control_flow(); cfg_checker.check_cleanup_control_flow();
let mut type_checker = TypeChecker { when: &self.when, body, tcx, param_env, mir_phase }; for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body) {
type_checker.visit_body(body); cfg_checker.fail(location, msg);
}
if let MirPhase::Runtime(_) = body.phase { if let MirPhase::Runtime(_) = body.phase {
if let ty::InstanceDef::Item(_) = body.source.instance { if let ty::InstanceDef::Item(_) = body.source.instance {
@ -498,30 +499,28 @@ fn visit_source_scope(&mut self, scope: SourceScope) {
} }
} }
fn validate_types<'tcx>(
tcx: TyCtxt<'tcx>,
mir_phase: MirPhase,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
) -> Vec<(Location, String)> {
let mut type_checker = TypeChecker { body, tcx, param_env, mir_phase, failures: Vec::new() };
type_checker.visit_body(body);
type_checker.failures
}
struct TypeChecker<'a, 'tcx> { struct TypeChecker<'a, 'tcx> {
when: &'a str,
body: &'a Body<'tcx>, body: &'a Body<'tcx>,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>, param_env: ParamEnv<'tcx>,
mir_phase: MirPhase, mir_phase: MirPhase,
failures: Vec<(Location, String)>,
} }
impl<'a, 'tcx> TypeChecker<'a, 'tcx> { impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
#[track_caller] fn fail(&mut self, location: Location, msg: impl Into<String>) {
fn fail(&self, location: Location, msg: impl AsRef<str>) { self.failures.push((location, msg.into()));
let span = self.body.source_info(location).span;
// We use `delay_span_bug` as we might see broken MIR when other errors have already
// occurred.
self.tcx.sess.diagnostic().delay_span_bug(
span,
format!(
"broken MIR in {:?} ({}) at {:?}:\n{}",
self.body.source.instance,
self.when,
location,
msg.as_ref()
),
);
} }
/// Check if src can be assigned into dest. /// Check if src can be assigned into dest.
@ -593,10 +592,10 @@ fn visit_projection_elem(
} }
ProjectionElem::Field(f, ty) => { ProjectionElem::Field(f, ty) => {
let parent_ty = place_ref.ty(&self.body.local_decls, self.tcx); let parent_ty = place_ref.ty(&self.body.local_decls, self.tcx);
let fail_out_of_bounds = |this: &Self, location| { let fail_out_of_bounds = |this: &mut Self, location| {
this.fail(location, format!("Out of bounds field {:?} for {:?}", f, parent_ty)); this.fail(location, format!("Out of bounds field {:?} for {:?}", f, parent_ty));
}; };
let check_equal = |this: &Self, location, f_ty| { let check_equal = |this: &mut Self, location, f_ty| {
if !this.mir_assign_valid_types(ty, f_ty) { if !this.mir_assign_valid_types(ty, f_ty) {
this.fail( this.fail(
location, location,
@ -691,9 +690,9 @@ fn visit_projection_elem(
} }
fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) { fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {
let check_place = |place: Place<'_>| { let check_place = |this: &mut Self, place: Place<'_>| {
if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) { if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) {
self.fail( this.fail(
START_BLOCK.start_location(), START_BLOCK.start_location(),
format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name), format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name),
); );
@ -702,7 +701,7 @@ fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {
match debuginfo.value { match debuginfo.value {
VarDebugInfoContents::Const(_) => {} VarDebugInfoContents::Const(_) => {}
VarDebugInfoContents::Place(place) => { VarDebugInfoContents::Place(place) => {
check_place(place); check_place(self, place);
if debuginfo.references != 0 && place.projection.last() == Some(&PlaceElem::Deref) { if debuginfo.references != 0 && place.projection.last() == Some(&PlaceElem::Deref) {
self.fail( self.fail(
START_BLOCK.start_location(), START_BLOCK.start_location(),
@ -712,7 +711,7 @@ fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {
} }
VarDebugInfoContents::Composite { ty, ref fragments } => { VarDebugInfoContents::Composite { ty, ref fragments } => {
for f in fragments { for f in fragments {
check_place(f.contents); check_place(self, f.contents);
if ty.is_union() || ty.is_enum() { if ty.is_union() || ty.is_enum() {
self.fail( self.fail(
START_BLOCK.start_location(), START_BLOCK.start_location(),
@ -969,7 +968,7 @@ macro_rules! check_kinds {
} }
} }
Rvalue::NullaryOp(NullOp::OffsetOf(fields), container) => { Rvalue::NullaryOp(NullOp::OffsetOf(fields), container) => {
let fail_out_of_bounds = |this: &Self, location, field, ty| { let fail_out_of_bounds = |this: &mut Self, location, field, ty| {
this.fail(location, format!("Out of bounds field {field:?} for {ty:?}")); this.fail(location, format!("Out of bounds field {field:?} for {ty:?}"));
}; };