thread location info through mir typeck (but do not use)
This commit is contained in:
parent
15a2dfa324
commit
6d672961fb
@ -555,6 +555,15 @@ pub struct UpvarDecl {
|
||||
|
||||
newtype_index!(BasicBlock { DEBUG_FORMAT = "bb{}" });
|
||||
|
||||
impl BasicBlock {
|
||||
pub fn start_location(self) -> Location {
|
||||
Location {
|
||||
block: self,
|
||||
statement_index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// BasicBlockData and Terminator
|
||||
|
||||
@ -638,7 +647,32 @@ pub enum TerminatorKind<'tcx> {
|
||||
unwind: Option<BasicBlock>
|
||||
},
|
||||
|
||||
/// Drop the Lvalue and assign the new value over it
|
||||
/// Drop the Lvalue and assign the new value over it. This ensures
|
||||
/// that the assignment to LV occurs *even if* the destructor for
|
||||
/// lvalue unwinds. Its semantics are best explained by by the
|
||||
/// elaboration:
|
||||
///
|
||||
/// ```
|
||||
/// BB0 {
|
||||
/// DropAndReplace(LV <- RV, goto BB1, unwind BB2)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// becomes
|
||||
///
|
||||
/// ```
|
||||
/// BB0 {
|
||||
/// Drop(LV, goto BB1, unwind BB2)
|
||||
/// }
|
||||
/// BB1 {
|
||||
/// // LV is now unitialized
|
||||
/// LV <- RV
|
||||
/// }
|
||||
/// BB2 {
|
||||
/// // LV is now unitialized -- its dtor panicked
|
||||
/// LV <- RV
|
||||
/// }
|
||||
/// ```
|
||||
DropAndReplace {
|
||||
location: Lvalue<'tcx>,
|
||||
value: Operand<'tcx>,
|
||||
|
@ -139,8 +139,8 @@ fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> Lval
|
||||
Lvalue::Static(box Static { def_id, ty: sty }) => {
|
||||
let sty = self.sanitize_type(lvalue, sty);
|
||||
let ty = self.tcx().type_of(def_id);
|
||||
let ty = self.cx.normalize(&ty);
|
||||
if let Err(terr) = self.cx.eq_types(self.last_span, ty, sty) {
|
||||
let ty = self.cx.normalize(&ty, location);
|
||||
if let Err(terr) = self.cx.eq_types(self.last_span, ty, sty, location) {
|
||||
span_mirbug!(
|
||||
self, lvalue, "bad static type ({:?}: {:?}): {:?}",
|
||||
ty, sty, terr);
|
||||
@ -165,7 +165,7 @@ fn sanitize_projection(&mut self,
|
||||
base: LvalueTy<'tcx>,
|
||||
pi: &LvalueElem<'tcx>,
|
||||
lvalue: &Lvalue<'tcx>,
|
||||
_: Location)
|
||||
location: Location)
|
||||
-> LvalueTy<'tcx> {
|
||||
debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, lvalue);
|
||||
let tcx = self.tcx();
|
||||
@ -254,9 +254,9 @@ fn sanitize_projection(&mut self,
|
||||
},
|
||||
ProjectionElem::Field(field, fty) => {
|
||||
let fty = self.sanitize_type(lvalue, fty);
|
||||
match self.field_ty(lvalue, base, field) {
|
||||
match self.field_ty(lvalue, base, field, location) {
|
||||
Ok(ty) => {
|
||||
if let Err(terr) = self.cx.eq_types(span, ty, fty) {
|
||||
if let Err(terr) = self.cx.eq_types(span, ty, fty, location) {
|
||||
span_mirbug!(
|
||||
self, lvalue, "bad field access ({:?}: {:?}): {:?}",
|
||||
ty, fty, terr);
|
||||
@ -281,7 +281,8 @@ fn error(&mut self) -> Ty<'tcx> {
|
||||
fn field_ty(&mut self,
|
||||
parent: &fmt::Debug,
|
||||
base_ty: LvalueTy<'tcx>,
|
||||
field: Field)
|
||||
field: Field,
|
||||
location: Location)
|
||||
-> Result<Ty<'tcx>, FieldAccessError>
|
||||
{
|
||||
let tcx = self.tcx();
|
||||
@ -329,7 +330,7 @@ fn field_ty(&mut self,
|
||||
};
|
||||
|
||||
if let Some(field) = variant.fields.get(field.index()) {
|
||||
Ok(self.cx.normalize(&field.ty(tcx, substs)))
|
||||
Ok(self.cx.normalize(&field.ty(tcx, substs), location))
|
||||
} else {
|
||||
Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() })
|
||||
}
|
||||
@ -371,7 +372,7 @@ pub fn register_infer_ok_obligations<T>(&mut self, infer_ok: InferOk<'tcx, T>) -
|
||||
infer_ok.value
|
||||
}
|
||||
|
||||
fn sub_types(&mut self, sub: Ty<'tcx>, sup: Ty<'tcx>)
|
||||
fn sub_types(&mut self, sub: Ty<'tcx>, sup: Ty<'tcx>, _at_location: Location)
|
||||
-> infer::UnitResult<'tcx>
|
||||
{
|
||||
self.infcx.at(&self.misc(self.last_span), self.param_env)
|
||||
@ -379,7 +380,7 @@ fn sub_types(&mut self, sub: Ty<'tcx>, sup: Ty<'tcx>)
|
||||
.map(|ok| self.register_infer_ok_obligations(ok))
|
||||
}
|
||||
|
||||
fn eq_types(&mut self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>)
|
||||
fn eq_types(&mut self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>, _at_location: Location)
|
||||
-> infer::UnitResult<'tcx>
|
||||
{
|
||||
self.infcx.at(&self.misc(span), self.param_env)
|
||||
@ -391,14 +392,17 @@ fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>) {
|
||||
fn check_stmt(&mut self,
|
||||
mir: &Mir<'tcx>,
|
||||
stmt: &Statement<'tcx>,
|
||||
location: Location) {
|
||||
debug!("check_stmt: {:?}", stmt);
|
||||
let tcx = self.tcx();
|
||||
match stmt.kind {
|
||||
StatementKind::Assign(ref lv, ref rv) => {
|
||||
let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
|
||||
let rv_ty = rv.ty(mir, tcx);
|
||||
if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
|
||||
if let Err(terr) = self.sub_types(rv_ty, lv_ty, location.successor_within_block()) {
|
||||
span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
|
||||
lv_ty, rv_ty, terr);
|
||||
}
|
||||
@ -432,7 +436,8 @@ fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>) {
|
||||
|
||||
fn check_terminator(&mut self,
|
||||
mir: &Mir<'tcx>,
|
||||
term: &Terminator<'tcx>) {
|
||||
term: &Terminator<'tcx>,
|
||||
location: Location) {
|
||||
debug!("check_terminator: {:?}", term);
|
||||
let tcx = self.tcx();
|
||||
match term.kind {
|
||||
@ -450,18 +455,30 @@ fn check_terminator(&mut self,
|
||||
TerminatorKind::DropAndReplace {
|
||||
ref location,
|
||||
ref value,
|
||||
..
|
||||
target,
|
||||
unwind,
|
||||
} => {
|
||||
let lv_ty = location.ty(mir, tcx).to_ty(tcx);
|
||||
let rv_ty = value.ty(mir, tcx);
|
||||
if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
|
||||
|
||||
if let Err(terr) = self.sub_types(rv_ty, lv_ty, target.start_location()) {
|
||||
span_mirbug!(self, term, "bad DropAndReplace ({:?} = {:?}): {:?}",
|
||||
lv_ty, rv_ty, terr);
|
||||
}
|
||||
|
||||
// Subtle: this assignment occurs at the start of
|
||||
// *both* blocks, so we need to ensure that it holds
|
||||
// at both locations.
|
||||
if let Some(unwind) = unwind {
|
||||
if let Err(terr) = self.sub_types(rv_ty, lv_ty, unwind.start_location()) {
|
||||
span_mirbug!(self, term, "bad DropAndReplace ({:?} = {:?}): {:?}",
|
||||
lv_ty, rv_ty, terr);
|
||||
}
|
||||
}
|
||||
}
|
||||
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
|
||||
let discr_ty = discr.ty(mir, tcx);
|
||||
if let Err(terr) = self.sub_types(discr_ty, switch_ty) {
|
||||
if let Err(terr) = self.sub_types(discr_ty, switch_ty, location) {
|
||||
span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}",
|
||||
switch_ty, discr_ty, terr);
|
||||
}
|
||||
@ -483,13 +500,13 @@ fn check_terminator(&mut self,
|
||||
}
|
||||
};
|
||||
let sig = tcx.erase_late_bound_regions(&sig);
|
||||
let sig = self.normalize(&sig);
|
||||
let sig = self.normalize(&sig, location);
|
||||
self.check_call_dest(mir, term, &sig, destination);
|
||||
|
||||
if self.is_box_free(func) {
|
||||
self.check_box_free_inputs(mir, term, &sig, args);
|
||||
self.check_box_free_inputs(mir, term, &sig, args, location);
|
||||
} else {
|
||||
self.check_call_inputs(mir, term, &sig, args);
|
||||
self.check_call_inputs(mir, term, &sig, args, location);
|
||||
}
|
||||
}
|
||||
TerminatorKind::Assert { ref cond, ref msg, .. } => {
|
||||
@ -512,7 +529,7 @@ fn check_terminator(&mut self,
|
||||
match mir.yield_ty {
|
||||
None => span_mirbug!(self, term, "yield in non-generator"),
|
||||
Some(ty) => {
|
||||
if let Err(terr) = self.sub_types(value_ty, ty) {
|
||||
if let Err(terr) = self.sub_types(value_ty, ty, location) {
|
||||
span_mirbug!(self,
|
||||
term,
|
||||
"type of yield value is {:?}, but the yield type is {:?}: {:?}",
|
||||
@ -533,9 +550,11 @@ fn check_call_dest(&mut self,
|
||||
destination: &Option<(Lvalue<'tcx>, BasicBlock)>) {
|
||||
let tcx = self.tcx();
|
||||
match *destination {
|
||||
Some((ref dest, _)) => {
|
||||
Some((ref dest, target_block)) => {
|
||||
let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
|
||||
if let Err(terr) = self.sub_types(sig.output(), dest_ty) {
|
||||
if let Err(terr) = self.sub_types(sig.output(),
|
||||
dest_ty,
|
||||
target_block.start_location()) {
|
||||
span_mirbug!(self, term,
|
||||
"call dest mismatch ({:?} <- {:?}): {:?}",
|
||||
dest_ty, sig.output(), terr);
|
||||
@ -554,7 +573,8 @@ fn check_call_inputs(&mut self,
|
||||
mir: &Mir<'tcx>,
|
||||
term: &Terminator<'tcx>,
|
||||
sig: &ty::FnSig<'tcx>,
|
||||
args: &[Operand<'tcx>])
|
||||
args: &[Operand<'tcx>],
|
||||
location: Location)
|
||||
{
|
||||
debug!("check_call_inputs({:?}, {:?})", sig, args);
|
||||
if args.len() < sig.inputs().len() ||
|
||||
@ -563,7 +583,7 @@ fn check_call_inputs(&mut self,
|
||||
}
|
||||
for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() {
|
||||
let op_arg_ty = op_arg.ty(mir, self.tcx());
|
||||
if let Err(terr) = self.sub_types(op_arg_ty, fn_arg) {
|
||||
if let Err(terr) = self.sub_types(op_arg_ty, fn_arg, location) {
|
||||
span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}",
|
||||
n, fn_arg, op_arg_ty, terr);
|
||||
}
|
||||
@ -587,7 +607,8 @@ fn check_box_free_inputs(&mut self,
|
||||
mir: &Mir<'tcx>,
|
||||
term: &Terminator<'tcx>,
|
||||
sig: &ty::FnSig<'tcx>,
|
||||
args: &[Operand<'tcx>])
|
||||
args: &[Operand<'tcx>],
|
||||
location: Location)
|
||||
{
|
||||
debug!("check_box_free_inputs");
|
||||
|
||||
@ -621,69 +642,69 @@ fn check_box_free_inputs(&mut self,
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(terr) = self.sub_types(arg_ty, pointee_ty) {
|
||||
if let Err(terr) = self.sub_types(arg_ty, pointee_ty, location) {
|
||||
span_mirbug!(self, term, "bad box_free arg ({:?} <- {:?}): {:?}",
|
||||
pointee_ty, arg_ty, terr);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block: &BasicBlockData<'tcx>)
|
||||
fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block_data: &BasicBlockData<'tcx>)
|
||||
{
|
||||
let is_cleanup = block.is_cleanup;
|
||||
self.last_span = block.terminator().source_info.span;
|
||||
match block.terminator().kind {
|
||||
let is_cleanup = block_data.is_cleanup;
|
||||
self.last_span = block_data.terminator().source_info.span;
|
||||
match block_data.terminator().kind {
|
||||
TerminatorKind::Goto { target } =>
|
||||
self.assert_iscleanup(mir, block, target, is_cleanup),
|
||||
self.assert_iscleanup(mir, block_data, target, is_cleanup),
|
||||
TerminatorKind::SwitchInt { ref targets, .. } => {
|
||||
for target in targets {
|
||||
self.assert_iscleanup(mir, block, *target, is_cleanup);
|
||||
self.assert_iscleanup(mir, block_data, *target, is_cleanup);
|
||||
}
|
||||
}
|
||||
TerminatorKind::Resume => {
|
||||
if !is_cleanup {
|
||||
span_mirbug!(self, block, "resume on non-cleanup block!")
|
||||
span_mirbug!(self, block_data, "resume on non-cleanup block!")
|
||||
}
|
||||
}
|
||||
TerminatorKind::Return => {
|
||||
if is_cleanup {
|
||||
span_mirbug!(self, block, "return on cleanup block")
|
||||
span_mirbug!(self, block_data, "return on cleanup block")
|
||||
}
|
||||
}
|
||||
TerminatorKind::GeneratorDrop { .. } => {
|
||||
if is_cleanup {
|
||||
span_mirbug!(self, block, "generator_drop in cleanup block")
|
||||
span_mirbug!(self, block_data, "generator_drop in cleanup block")
|
||||
}
|
||||
}
|
||||
TerminatorKind::Yield { resume, drop, .. } => {
|
||||
if is_cleanup {
|
||||
span_mirbug!(self, block, "yield in cleanup block")
|
||||
span_mirbug!(self, block_data, "yield in cleanup block")
|
||||
}
|
||||
self.assert_iscleanup(mir, block, resume, is_cleanup);
|
||||
self.assert_iscleanup(mir, block_data, resume, is_cleanup);
|
||||
if let Some(drop) = drop {
|
||||
self.assert_iscleanup(mir, block, drop, is_cleanup);
|
||||
self.assert_iscleanup(mir, block_data, drop, is_cleanup);
|
||||
}
|
||||
}
|
||||
TerminatorKind::Unreachable => {}
|
||||
TerminatorKind::Drop { target, unwind, .. } |
|
||||
TerminatorKind::DropAndReplace { target, unwind, .. } |
|
||||
TerminatorKind::Assert { target, cleanup: unwind, .. } => {
|
||||
self.assert_iscleanup(mir, block, target, is_cleanup);
|
||||
self.assert_iscleanup(mir, block_data, target, is_cleanup);
|
||||
if let Some(unwind) = unwind {
|
||||
if is_cleanup {
|
||||
span_mirbug!(self, block, "unwind on cleanup block")
|
||||
span_mirbug!(self, block_data, "unwind on cleanup block")
|
||||
}
|
||||
self.assert_iscleanup(mir, block, unwind, true);
|
||||
self.assert_iscleanup(mir, block_data, unwind, true);
|
||||
}
|
||||
}
|
||||
TerminatorKind::Call { ref destination, cleanup, .. } => {
|
||||
if let &Some((_, target)) = destination {
|
||||
self.assert_iscleanup(mir, block, target, is_cleanup);
|
||||
self.assert_iscleanup(mir, block_data, target, is_cleanup);
|
||||
}
|
||||
if let Some(cleanup) = cleanup {
|
||||
if is_cleanup {
|
||||
span_mirbug!(self, block, "cleanup on cleanup block")
|
||||
span_mirbug!(self, block_data, "cleanup on cleanup block")
|
||||
}
|
||||
self.assert_iscleanup(mir, block, cleanup, true);
|
||||
self.assert_iscleanup(mir, block_data, cleanup, true);
|
||||
}
|
||||
}
|
||||
TerminatorKind::FalseEdges { real_target, ref imaginary_targets } => {
|
||||
@ -744,21 +765,23 @@ fn typeck_mir(&mut self, mir: &Mir<'gcx>) {
|
||||
self.check_local(mir, local, local_decl);
|
||||
}
|
||||
|
||||
for block in mir.basic_blocks() {
|
||||
for stmt in &block.statements {
|
||||
for (block, block_data) in mir.basic_blocks().iter_enumerated() {
|
||||
let mut location = Location { block, statement_index: 0 };
|
||||
for stmt in &block_data.statements {
|
||||
if stmt.source_info.span != DUMMY_SP {
|
||||
self.last_span = stmt.source_info.span;
|
||||
}
|
||||
self.check_stmt(mir, stmt);
|
||||
self.check_stmt(mir, stmt, location);
|
||||
location.statement_index += 1;
|
||||
}
|
||||
|
||||
self.check_terminator(mir, block.terminator());
|
||||
self.check_iscleanup(mir, block);
|
||||
self.check_terminator(mir, block_data.terminator(), location);
|
||||
self.check_iscleanup(mir, block_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn normalize<T>(&mut self, value: &T) -> T
|
||||
fn normalize<T>(&mut self, value: &T, _location: Location) -> T
|
||||
where T: fmt::Debug + TypeFoldable<'tcx>
|
||||
{
|
||||
let mut selcx = traits::SelectionContext::new(self.infcx);
|
||||
|
Loading…
Reference in New Issue
Block a user