Don't run MIR passes on constructor shims
This commit is contained in:
parent
8b36867093
commit
6c9a018b60
@ -91,34 +91,6 @@ fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> BorrowC
|
||||
let input_mir = tcx.mir_validated(def_id);
|
||||
debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id));
|
||||
|
||||
// We are not borrow checking the automatically generated struct/variant constructors
|
||||
// because we want to accept structs such as this (taken from the `linked-hash-map`
|
||||
// crate):
|
||||
// ```rust
|
||||
// struct Qey<Q: ?Sized>(Q);
|
||||
// ```
|
||||
// MIR of this struct constructor looks something like this:
|
||||
// ```rust
|
||||
// fn Qey(_1: Q) -> Qey<Q>{
|
||||
// let mut _0: Qey<Q>; // return place
|
||||
//
|
||||
// bb0: {
|
||||
// (_0.0: Q) = move _1; // bb0[0]: scope 0 at src/main.rs:1:1: 1:26
|
||||
// return; // bb0[1]: scope 0 at src/main.rs:1:1: 1:26
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
// The problem here is that `(_0.0: Q) = move _1;` is valid only if `Q` is
|
||||
// of statically known size, which is not known to be true because of the
|
||||
// `Q: ?Sized` constraint. However, it is true because the constructor can be
|
||||
// called only when `Q` is of statically known size.
|
||||
if tcx.is_constructor(def_id) {
|
||||
return BorrowCheckResult {
|
||||
closure_requirements: None,
|
||||
used_mut_upvars: SmallVec::new(),
|
||||
};
|
||||
}
|
||||
|
||||
let opt_closure_req = tcx.infer_ctxt().enter(|infcx| {
|
||||
let input_mir: &Body<'_> = &input_mir.borrow();
|
||||
do_mir_borrowck(&infcx, input_mir, def_id)
|
||||
|
@ -2,7 +2,6 @@ use crate::build;
|
||||
use crate::build::scope::DropKind;
|
||||
use crate::hair::cx::Cx;
|
||||
use crate::hair::{LintLevel, BindingMode, PatternKind};
|
||||
use crate::shim;
|
||||
use crate::transform::MirSource;
|
||||
use crate::util as mir_util;
|
||||
use rustc::hir;
|
||||
@ -31,8 +30,6 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Body<'
|
||||
|
||||
// Figure out what primary body this item has.
|
||||
let (body_id, return_ty_span) = match tcx.hir().get_by_hir_id(id) {
|
||||
Node::Ctor(ctor) => return create_constructor_shim(tcx, id, ctor),
|
||||
|
||||
Node::Expr(hir::Expr { node: hir::ExprKind::Closure(_, decl, body_id, _, _), .. })
|
||||
| Node::Item(hir::Item { node: hir::ItemKind::Fn(decl, _, _, body_id), .. })
|
||||
| Node::ImplItem(
|
||||
@ -234,38 +231,6 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
ctor_id: hir::HirId,
|
||||
v: &'tcx hir::VariantData)
|
||||
-> Body<'tcx>
|
||||
{
|
||||
let span = tcx.hir().span_by_hir_id(ctor_id);
|
||||
if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut mir = shim::build_adt_ctor(&infcx, ctor_id, fields, span);
|
||||
|
||||
// Convert the `mir::Body` to global types.
|
||||
let tcx = infcx.tcx.global_tcx();
|
||||
let mut globalizer = GlobalizeMir {
|
||||
tcx,
|
||||
span: mir.span
|
||||
};
|
||||
globalizer.visit_body(&mut mir);
|
||||
let mir = unsafe {
|
||||
mem::transmute::<Body<'_>, Body<'tcx>>(mir)
|
||||
};
|
||||
|
||||
mir_util::dump_mir(tcx, None, "mir_map", &0,
|
||||
MirSource::item(tcx.hir().local_def_id_from_hir_id(ctor_id)),
|
||||
&mir, |_, _| Ok(()) );
|
||||
|
||||
mir
|
||||
})
|
||||
} else {
|
||||
span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// BuildMir -- walks a crate, looking for fn items and methods to build MIR from
|
||||
|
||||
|
@ -22,6 +22,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
||||
#![feature(unicode_internals)]
|
||||
#![feature(step_trait)]
|
||||
#![feature(slice_concat_ext)]
|
||||
#![feature(trusted_len)]
|
||||
#![feature(try_blocks)]
|
||||
|
||||
#![recursion_limit="256"]
|
||||
|
@ -1,6 +1,5 @@
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer;
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::layout::VariantIdx;
|
||||
@ -21,6 +20,7 @@ use crate::transform::{
|
||||
};
|
||||
use crate::util::elaborate_drops::{self, DropElaborator, DropStyle, DropFlagMode};
|
||||
use crate::util::patch::MirPatch;
|
||||
use crate::util::expand_aggregate;
|
||||
|
||||
pub fn provide(providers: &mut Providers<'_>) {
|
||||
providers.mir_shims = make_shim;
|
||||
@ -842,29 +842,26 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
mir
|
||||
}
|
||||
|
||||
pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
|
||||
ctor_id: hir::HirId,
|
||||
fields: &[hir::StructField],
|
||||
span: Span)
|
||||
-> Body<'tcx>
|
||||
{
|
||||
let tcx = infcx.tcx;
|
||||
let gcx = tcx.global_tcx();
|
||||
let def_id = tcx.hir().local_def_id_from_hir_id(ctor_id);
|
||||
let param_env = gcx.param_env(def_id);
|
||||
pub fn build_adt_ctor<'gcx>(tcx: TyCtxt<'_, 'gcx, 'gcx>, ctor_id: DefId) -> &'gcx Body<'gcx> {
|
||||
debug_assert!(tcx.is_constructor(ctor_id));
|
||||
|
||||
let span = tcx.hir().span_if_local(ctor_id)
|
||||
.unwrap_or_else(|| bug!("no span for ctor {:?}", ctor_id));
|
||||
|
||||
let param_env = tcx.param_env(ctor_id);
|
||||
|
||||
// Normalize the sig.
|
||||
let sig = gcx.fn_sig(def_id)
|
||||
let sig = tcx.fn_sig(ctor_id)
|
||||
.no_bound_vars()
|
||||
.expect("LBR in ADT constructor signature");
|
||||
let sig = gcx.normalize_erasing_regions(param_env, sig);
|
||||
let sig = tcx.normalize_erasing_regions(param_env, sig);
|
||||
|
||||
let (adt_def, substs) = match sig.output().sty {
|
||||
ty::Adt(adt_def, substs) => (adt_def, substs),
|
||||
_ => bug!("unexpected type for ADT ctor {:?}", sig.output())
|
||||
};
|
||||
|
||||
debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields);
|
||||
debug!("build_ctor: ctor_id={:?} sig={:?}", ctor_id, sig);
|
||||
|
||||
let local_decls = local_decls_for_sig(&sig, span);
|
||||
|
||||
@ -873,26 +870,37 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
|
||||
scope: OUTERMOST_SOURCE_SCOPE
|
||||
};
|
||||
|
||||
let variant_no = if adt_def.is_enum() {
|
||||
adt_def.variant_index_with_ctor_id(def_id)
|
||||
let variant_index = if adt_def.is_enum() {
|
||||
adt_def.variant_index_with_ctor_id(ctor_id)
|
||||
} else {
|
||||
VariantIdx::new(0)
|
||||
};
|
||||
|
||||
// return = ADT(arg0, arg1, ...); return
|
||||
// Generate the following MIR:
|
||||
//
|
||||
// (return as Variant).field0 = arg0;
|
||||
// (return as Variant).field1 = arg1;
|
||||
//
|
||||
// return;
|
||||
debug!("build_ctor: variant_index={:?}", variant_index);
|
||||
|
||||
let statements = expand_aggregate(
|
||||
Place::RETURN_PLACE,
|
||||
adt_def
|
||||
.variants[variant_index]
|
||||
.fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, field_def)| (
|
||||
Operand::Move(Place::Base(PlaceBase::Local(Local::new(idx + 1)))),
|
||||
field_def.ty(tcx, substs),
|
||||
)),
|
||||
AggregateKind::Adt(adt_def, variant_index, substs, None, None),
|
||||
source_info,
|
||||
).collect();
|
||||
|
||||
let start_block = BasicBlockData {
|
||||
statements: vec![Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(
|
||||
Place::RETURN_PLACE,
|
||||
box Rvalue::Aggregate(
|
||||
box AggregateKind::Adt(adt_def, variant_no, substs, None, None),
|
||||
(1..sig.inputs().len()+1).map(|i| {
|
||||
Operand::Move(Place::Base(PlaceBase::Local(Local::new(i))))
|
||||
}).collect()
|
||||
)
|
||||
)
|
||||
}],
|
||||
statements,
|
||||
terminator: Some(Terminator {
|
||||
source_info,
|
||||
kind: TerminatorKind::Return,
|
||||
@ -900,7 +908,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
|
||||
is_cleanup: false
|
||||
};
|
||||
|
||||
Body::new(
|
||||
let body = Body::new(
|
||||
IndexVec::from_elem_n(start_block, 1),
|
||||
IndexVec::from_elem_n(
|
||||
SourceScopeData { span: span, parent_scope: None }, 1
|
||||
@ -914,5 +922,17 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
|
||||
vec![],
|
||||
span,
|
||||
vec![],
|
||||
)
|
||||
);
|
||||
|
||||
crate::util::dump_mir(
|
||||
tcx,
|
||||
None,
|
||||
"mir_map",
|
||||
&0,
|
||||
crate::transform::MirSource::item(ctor_id),
|
||||
&body,
|
||||
|_, _| Ok(()),
|
||||
);
|
||||
|
||||
tcx.arena.alloc(body)
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::ty::layout::VariantIdx;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use crate::transform::{MirPass, MirSource};
|
||||
use crate::util::expand_aggregate;
|
||||
|
||||
pub struct Deaggregator;
|
||||
|
||||
@ -31,7 +30,7 @@ impl MirPass for Deaggregator {
|
||||
|
||||
let stmt = stmt.replace_nop();
|
||||
let source_info = stmt.source_info;
|
||||
let (mut lhs, kind, operands) = match stmt.kind {
|
||||
let (lhs, kind, operands) = match stmt.kind {
|
||||
StatementKind::Assign(lhs, box rvalue) => {
|
||||
match rvalue {
|
||||
Rvalue::Aggregate(kind, operands) => (lhs, kind, operands),
|
||||
@ -41,62 +40,15 @@ impl MirPass for Deaggregator {
|
||||
_ => bug!()
|
||||
};
|
||||
|
||||
let mut set_discriminant = None;
|
||||
let active_field_index = match *kind {
|
||||
AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
|
||||
if adt_def.is_enum() {
|
||||
set_discriminant = Some(Statement {
|
||||
kind: StatementKind::SetDiscriminant {
|
||||
place: lhs.clone(),
|
||||
variant_index,
|
||||
},
|
||||
source_info,
|
||||
});
|
||||
lhs = lhs.downcast(adt_def, variant_index);
|
||||
}
|
||||
active_field_index
|
||||
}
|
||||
AggregateKind::Generator(..) => {
|
||||
// Right now we only support initializing generators to
|
||||
// variant 0 (Unresumed).
|
||||
let variant_index = VariantIdx::new(0);
|
||||
set_discriminant = Some(Statement {
|
||||
kind: StatementKind::SetDiscriminant {
|
||||
place: lhs.clone(),
|
||||
variant_index,
|
||||
},
|
||||
source_info,
|
||||
});
|
||||
|
||||
// Operands are upvars stored on the base place, so no
|
||||
// downcast is necessary.
|
||||
|
||||
None
|
||||
}
|
||||
_ => None
|
||||
};
|
||||
|
||||
Some(operands.into_iter().enumerate().map(move |(i, op)| {
|
||||
let lhs_field = if let AggregateKind::Array(_) = *kind {
|
||||
// FIXME(eddyb) `offset` should be u64.
|
||||
let offset = i as u32;
|
||||
assert_eq!(offset as usize, i);
|
||||
lhs.clone().elem(ProjectionElem::ConstantIndex {
|
||||
offset,
|
||||
// FIXME(eddyb) `min_length` doesn't appear to be used.
|
||||
min_length: offset + 1,
|
||||
from_end: false
|
||||
})
|
||||
} else {
|
||||
Some(expand_aggregate(
|
||||
lhs,
|
||||
operands.into_iter().map(|op| {
|
||||
let ty = op.ty(local_decls, tcx);
|
||||
let field = Field::new(active_field_index.unwrap_or(i));
|
||||
lhs.clone().field(field, ty)
|
||||
};
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)),
|
||||
}
|
||||
}).chain(set_discriminant))
|
||||
(op, ty)
|
||||
}),
|
||||
*kind,
|
||||
source_info,
|
||||
))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::build;
|
||||
use crate::{build, shim};
|
||||
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use rustc::mir::{Body, MirPhase, Promoted};
|
||||
use rustc::ty::{TyCtxt, InstanceDef};
|
||||
@ -228,7 +228,15 @@ fn mir_validated<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
|
||||
}
|
||||
|
||||
fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Body<'tcx> {
|
||||
// `mir_borrowck` uses `mir_validated`, so we have to force it to
|
||||
if tcx.is_constructor(def_id) {
|
||||
// There's no reason to run all of the MIR passes on constructors when
|
||||
// we can just output the MIR we want directly. This also saves const
|
||||
// qualification and borrow checking the trouble of special casing
|
||||
// constructors.
|
||||
return shim::build_adt_ctor(tcx, def_id);
|
||||
}
|
||||
|
||||
// (Mir-)Borrowck uses `mir_validated`, so we have to force it to
|
||||
// execute before we can steal.
|
||||
tcx.ensure().mir_borrowck(def_id);
|
||||
|
||||
|
76
src/librustc_mir/util/aggregate.rs
Normal file
76
src/librustc_mir/util/aggregate.rs
Normal file
@ -0,0 +1,76 @@
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::Ty;
|
||||
use rustc::ty::layout::VariantIdx;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
use std::iter::TrustedLen;
|
||||
|
||||
/// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields.
|
||||
///
|
||||
/// Produces something like
|
||||
///
|
||||
/// (lhs as Variant).field0 = arg0; // We only have a downcast if this is an enum
|
||||
/// (lhs as Variant).field1 = arg1;
|
||||
/// discriminant(lhs) = variant_index; // If lhs is an enum or generator.
|
||||
pub fn expand_aggregate<'tcx>(
|
||||
mut lhs: Place<'tcx>,
|
||||
operands: impl Iterator<Item=(Operand<'tcx>, Ty<'tcx>)> + TrustedLen,
|
||||
kind: AggregateKind<'tcx>,
|
||||
source_info: SourceInfo,
|
||||
) -> impl Iterator<Item=Statement<'tcx>> + TrustedLen {
|
||||
let mut set_discriminant = None;
|
||||
let active_field_index = match kind {
|
||||
AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
|
||||
if adt_def.is_enum() {
|
||||
set_discriminant = Some(Statement {
|
||||
kind: StatementKind::SetDiscriminant {
|
||||
place: lhs.clone(),
|
||||
variant_index,
|
||||
},
|
||||
source_info,
|
||||
});
|
||||
lhs = lhs.downcast(adt_def, variant_index);
|
||||
}
|
||||
active_field_index
|
||||
}
|
||||
AggregateKind::Generator(..) => {
|
||||
// Right now we only support initializing generators to
|
||||
// variant 0 (Unresumed).
|
||||
let variant_index = VariantIdx::new(0);
|
||||
set_discriminant = Some(Statement {
|
||||
kind: StatementKind::SetDiscriminant {
|
||||
place: lhs.clone(),
|
||||
variant_index,
|
||||
},
|
||||
source_info,
|
||||
});
|
||||
|
||||
// Operands are upvars stored on the base place, so no
|
||||
// downcast is necessary.
|
||||
|
||||
None
|
||||
}
|
||||
_ => None
|
||||
};
|
||||
|
||||
operands.into_iter().enumerate().map(move |(i, (op, ty))| {
|
||||
let lhs_field = if let AggregateKind::Array(_) = kind {
|
||||
// FIXME(eddyb) `offset` should be u64.
|
||||
let offset = i as u32;
|
||||
assert_eq!(offset as usize, i);
|
||||
lhs.clone().elem(ProjectionElem::ConstantIndex {
|
||||
offset,
|
||||
// FIXME(eddyb) `min_length` doesn't appear to be used.
|
||||
min_length: offset + 1,
|
||||
from_end: false
|
||||
})
|
||||
} else {
|
||||
let field = Field::new(active_field_index.unwrap_or(i));
|
||||
lhs.clone().field(field, ty)
|
||||
};
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)),
|
||||
}
|
||||
}).chain(set_discriminant)
|
||||
}
|
@ -2,6 +2,7 @@ use core::unicode::property::Pattern_White_Space;
|
||||
use rustc::ty::TyCtxt;
|
||||
use syntax_pos::Span;
|
||||
|
||||
pub mod aggregate;
|
||||
pub mod borrowck_errors;
|
||||
pub mod elaborate_drops;
|
||||
pub mod def_use;
|
||||
@ -13,6 +14,7 @@ pub(crate) mod pretty;
|
||||
pub mod liveness;
|
||||
pub mod collect_writes;
|
||||
|
||||
pub use self::aggregate::expand_aggregate;
|
||||
pub use self::alignment::is_disaligned;
|
||||
pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere};
|
||||
pub use self::graphviz::{graphviz_safe_def_name, write_mir_graphviz};
|
||||
|
@ -78,7 +78,8 @@ fn main() {
|
||||
// let mut _0: Test;
|
||||
//
|
||||
// bb0: {
|
||||
// _0 = Test::X(move _1,);
|
||||
// ((_0 as X).0: usize) = move _1;
|
||||
// discriminant(_0) = 0;
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
Loading…
x
Reference in New Issue
Block a user