Make type validation buffer errors.
This commit is contained in:
parent
030589d488
commit
2ef2ac0b51
@ -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:?}"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user