Skip to content

[MIR] A pass to type-check MIR #31474

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Feb 20, 2016
5 changes: 3 additions & 2 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -721,10 +721,11 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
if let Some(adjustment) = adj {
match adjustment {
adjustment::AdjustReifyFnPointer |
adjustment::AdjustUnsafeFnPointer => {
adjustment::AdjustUnsafeFnPointer |
adjustment::AdjustMutToConstPointer => {
// Creating a closure/fn-pointer or unsizing consumes
// the input and stores it into the resulting rvalue.
debug!("walk_adjustment(AdjustReifyFnPointer|AdjustUnsafeFnPointer)");
debug!("walk_adjustment: trivial adjustment");
let cmt_unadjusted =
return_if_err!(self.mc.cat_expr_unadjusted(expr));
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {

adjustment::AdjustReifyFnPointer |
adjustment::AdjustUnsafeFnPointer |
adjustment::AdjustMutToConstPointer |
adjustment::AdjustDerefRef(_) => {
debug!("cat_expr({:?}): {:?}",
adjustment,
Expand Down
31 changes: 24 additions & 7 deletions src/librustc/middle/ty/adjustment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ use rustc_front::hir;

#[derive(Copy, Clone)]
pub enum AutoAdjustment<'tcx> {
AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type
AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer
AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type
AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer
AdjustMutToConstPointer, // go from a mut raw pointer to a const raw pointer
AdjustDerefRef(AutoDerefRef<'tcx>),
}

Expand Down Expand Up @@ -106,7 +107,8 @@ impl<'tcx> AutoAdjustment<'tcx> {
pub fn is_identity(&self) -> bool {
match *self {
AdjustReifyFnPointer |
AdjustUnsafeFnPointer => false,
AdjustUnsafeFnPointer |
AdjustMutToConstPointer => false,
AdjustDerefRef(ref r) => r.is_identity(),
}
}
Expand Down Expand Up @@ -151,7 +153,7 @@ impl<'tcx> ty::TyS<'tcx> {
return match adjustment {
Some(adjustment) => {
match *adjustment {
AdjustReifyFnPointer => {
AdjustReifyFnPointer => {
match self.sty {
ty::TyBareFn(Some(_), b) => {
cx.mk_fn(None, b)
Expand All @@ -164,17 +166,32 @@ impl<'tcx> ty::TyS<'tcx> {
}
}

AdjustUnsafeFnPointer => {
AdjustUnsafeFnPointer => {
match self.sty {
ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b),
ref b => {
cx.sess.bug(
&format!("AdjustReifyFnPointer adjustment on non-fn-item: \
&format!("AdjustUnsafeFnPointer adjustment on non-fn-ptr: \
{:?}",
b));
}
}
}
}

AdjustMutToConstPointer => {
match self.sty {
ty::TyRawPtr(mt) => cx.mk_ptr(ty::TypeAndMut {
ty: mt.ty,
mutbl: hir::MutImmutable
}),
ref b => {
cx.sess.bug(
&format!("AdjustMutToConstPointer on non-raw-ptr: \
{:?}",
b));
}
}
}

AdjustDerefRef(ref adj) => {
let mut adjusted_ty = self;
Expand Down
7 changes: 7 additions & 0 deletions src/librustc/middle/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ pub struct Tables<'tcx> {
/// equivalents. This table is not used in trans (since regions
/// are erased there) and hence is not serialized to metadata.
pub liberated_fn_sigs: NodeMap<ty::FnSig<'tcx>>,

/// For each FRU expression, record the normalized types of the fields
/// of the struct - this is needed because it is non-trivial to
/// normalize while preserving regions. This table is used only in
/// MIR construction and hence is not serialized to metadata.
pub fru_field_types: NodeMap<Vec<Ty<'tcx>>>
}

impl<'tcx> Tables<'tcx> {
Expand All @@ -144,6 +150,7 @@ impl<'tcx> Tables<'tcx> {
closure_tys: DefIdMap(),
closure_kinds: DefIdMap(),
liberated_fn_sigs: NodeMap(),
fru_field_types: NodeMap()
}
}

Expand Down
14 changes: 12 additions & 2 deletions src/librustc/mir/mir_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,30 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use dep_graph::DepNode;
use util::nodemap::NodeMap;
use mir::repr::Mir;
use mir::transform::MirPass;
use middle::ty;
use middle::infer;

pub struct MirMap<'tcx> {
pub map: NodeMap<Mir<'tcx>>,
}

impl<'tcx> MirMap<'tcx> {
pub fn run_passes(&mut self, passes: &mut [Box<MirPass>], tcx: &ty::ctxt<'tcx>) {
for (_, ref mut mir) in &mut self.map {
if passes.is_empty() { return; }

for (&id, mir) in &mut self.map {
let did = tcx.map.local_def_id(id);
let _task = tcx.dep_graph.in_task(DepNode::MirMapConstruction(did));

let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env));

for pass in &mut *passes {
pass.run_on_mir(mir, tcx)
pass.run_on_mir(mir, &infcx)
}
}
}
Expand Down
19 changes: 11 additions & 8 deletions src/librustc/mir/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ pub struct Mir<'tcx> {
/// values in that it is possible to borrow them and mutate them
/// through the resulting reference.
pub temp_decls: Vec<TempDecl<'tcx>>,

/// A span representing this MIR, for error reporting
pub span: Span,
}

/// where execution begins
Expand Down Expand Up @@ -145,7 +148,7 @@ pub enum BorrowKind {

/// A "variable" is a binding declared by the user as part of the fn
/// decl, a let, etc.
#[derive(Clone, RustcEncodable, RustcDecodable)]
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct VarDecl<'tcx> {
pub mutability: Mutability,
pub name: Name,
Expand All @@ -154,7 +157,7 @@ pub struct VarDecl<'tcx> {

/// A "temp" is a temporary that we place on the stack. They are
/// anonymous, always mutable, and have only a type.
#[derive(Clone, RustcEncodable, RustcDecodable)]
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct TempDecl<'tcx> {
pub ty: Ty<'tcx>,
}
Expand All @@ -170,7 +173,7 @@ pub struct TempDecl<'tcx> {
///
/// there is only one argument, of type `(i32, u32)`, but two bindings
/// (`x` and `y`).
#[derive(Clone, RustcEncodable, RustcDecodable)]
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ArgDecl<'tcx> {
pub ty: Ty<'tcx>,
}
Expand Down Expand Up @@ -499,7 +502,7 @@ pub struct Projection<'tcx, B, V> {
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum ProjectionElem<'tcx, V> {
Deref,
Field(Field),
Field(Field, Ty<'tcx>),
Index(V),

/// These indices are generated by slice patterns. Easiest to explain
Expand Down Expand Up @@ -550,8 +553,8 @@ impl Field {
}

impl<'tcx> Lvalue<'tcx> {
pub fn field(self, f: Field) -> Lvalue<'tcx> {
self.elem(ProjectionElem::Field(f))
pub fn field(self, f: Field, ty: Ty<'tcx>) -> Lvalue<'tcx> {
self.elem(ProjectionElem::Field(f, ty))
}

pub fn deref(self) -> Lvalue<'tcx> {
Expand Down Expand Up @@ -591,8 +594,8 @@ impl<'tcx> Debug for Lvalue<'tcx> {
write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].name),
ProjectionElem::Deref =>
write!(fmt, "(*{:?})", data.base),
ProjectionElem::Field(field) =>
write!(fmt, "{:?}.{:?}", data.base, field.index()),
ProjectionElem::Field(field, ty) =>
write!(fmt, "({:?}.{:?}: {:?})", data.base, field.index(), ty),
ProjectionElem::Index(ref index) =>
write!(fmt, "{:?}[{:?}]", data.base, index),
ProjectionElem::ConstantIndex { offset, min_length, from_end: false } =>
Expand Down
88 changes: 70 additions & 18 deletions src/librustc/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
*/

use mir::repr::*;
use middle::subst::Substs;
use middle::const_eval::ConstVal;
use middle::subst::{Subst, Substs};
use middle::ty::{self, AdtDef, Ty};
use rustc_front::hir;

Expand Down Expand Up @@ -72,23 +73,7 @@ impl<'tcx> LvalueTy<'tcx> {
tcx.sess.bug(&format!("cannot downcast non-enum type: `{:?}`", self))
}
},
ProjectionElem::Field(field) => {
let field_ty = match self {
LvalueTy::Ty { ty } => match ty.sty {
ty::TyStruct(adt_def, substs) =>
adt_def.struct_variant().fields[field.index()].ty(tcx, substs),
ty::TyTuple(ref tys) =>
tys[field.index()],
ty::TyClosure(_, ref closure_substs) =>
closure_substs.upvar_tys[field.index()],
_ =>
tcx.sess.bug(&format!("cannot get field of type: `{:?}`", ty)),
},
LvalueTy::Downcast { adt_def, substs, variant_index } =>
adt_def.variants[variant_index].fields[field.index()].ty(tcx, substs),
};
LvalueTy::Ty { ty: field_ty }
}
ProjectionElem::Field(_, fty) => LvalueTy::Ty { ty: fty }
}
}
}
Expand Down Expand Up @@ -150,6 +135,73 @@ impl<'tcx> Mir<'tcx> {
self.lvalue_ty(tcx, &proj.base).projection_ty(tcx, &proj.elem)
}
}

pub fn rvalue_ty(&self,
tcx: &ty::ctxt<'tcx>,
rvalue: &Rvalue<'tcx>)
-> Option<Ty<'tcx>>
{
match *rvalue {
Rvalue::Use(ref operand) => Some(self.operand_ty(tcx, operand)),
Rvalue::Repeat(ref operand, ref count) => {
if let ConstVal::Uint(u) = count.value {
let op_ty = self.operand_ty(tcx, operand);
Some(tcx.mk_array(op_ty, u as usize))
} else {
None
}
}
Rvalue::Ref(reg, bk, ref lv) => {
let lv_ty = self.lvalue_ty(tcx, lv).to_ty(tcx);
Some(tcx.mk_ref(
tcx.mk_region(reg),
ty::TypeAndMut {
ty: lv_ty,
mutbl: bk.to_mutbl_lossy()
}
))
}
Rvalue::Len(..) => Some(tcx.types.usize),
Rvalue::Cast(_, _, ty) => Some(ty),
Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
let lhs_ty = self.operand_ty(tcx, lhs);
let rhs_ty = self.operand_ty(tcx, rhs);
Some(self.binop_ty(tcx, op, lhs_ty, rhs_ty))
}
Rvalue::UnaryOp(_, ref operand) => {
Some(self.operand_ty(tcx, operand))
}
Rvalue::Box(t) => {
Some(tcx.mk_box(t))
}
Rvalue::Aggregate(ref ak, ref ops) => {
match *ak {
AggregateKind::Vec => {
if let Some(operand) = ops.get(0) {
let ty = self.operand_ty(tcx, operand);
Some(tcx.mk_array(ty, ops.len()))
} else {
None
}
}
AggregateKind::Tuple => {
Some(tcx.mk_tup(
ops.iter().map(|op| self.operand_ty(tcx, op)).collect()
))
}
AggregateKind::Adt(def, _, substs) => {
Some(def.type_scheme(tcx).ty.subst(tcx, substs))
}
AggregateKind::Closure(did, substs) => {
Some(tcx.mk_closure_from_closure_substs(
did, Box::new(substs.clone())))
}
}
}
Rvalue::Slice { .. } => None,
Rvalue::InlineAsm(..) => None
}
}
}

impl BorrowKind {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/mir/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
// except according to those terms.

use mir::repr::Mir;
use middle::ty::ctxt;
use middle::infer::InferCtxt;

pub trait MirPass {
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ctxt<'tcx>);
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, infcx: &InferCtxt<'a, 'tcx>);
}
6 changes: 6 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ pub struct Options {
pub no_trans: bool,
pub error_format: ErrorOutputType,
pub treat_err_as_bug: bool,
pub mir_opt_level: usize,

/// if true, build up the dep-graph
pub build_dep_graph: bool,
Expand Down Expand Up @@ -254,6 +255,7 @@ pub fn basic_options() -> Options {
parse_only: false,
no_trans: false,
treat_err_as_bug: false,
mir_opt_level: 1,
build_dep_graph: false,
dump_dep_graph: false,
no_analysis: false,
Expand Down Expand Up @@ -655,6 +657,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"show spans for compiler debugging (expr|pat|ty)"),
print_trans_items: Option<String> = (None, parse_opt_string,
"print the result of the translation item collection pass"),
mir_opt_level: Option<usize> = (None, parse_opt_uint,
"set the MIR optimization level (0-3)"),
}

pub fn default_lib_output() -> CrateType {
Expand Down Expand Up @@ -988,6 +992,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let parse_only = debugging_opts.parse_only;
let no_trans = debugging_opts.no_trans;
let treat_err_as_bug = debugging_opts.treat_err_as_bug;
let mir_opt_level = debugging_opts.mir_opt_level.unwrap_or(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was considering a default of 1 + -C opt-level. This way the level of MIR “optimisations” would automatically get attached to the -O and -C opt-level flags as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First make opt-levels greater than 1 do something, then we can talk.

let incremental_compilation = debugging_opts.incr_comp;
let dump_dep_graph = debugging_opts.dump_dep_graph;
let no_analysis = debugging_opts.no_analysis;
Expand Down Expand Up @@ -1166,6 +1171,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
parse_only: parse_only,
no_trans: no_trans,
treat_err_as_bug: treat_err_as_bug,
mir_opt_level: mir_opt_level,
build_dep_graph: incremental_compilation || dump_dep_graph,
dump_dep_graph: dump_dep_graph,
no_analysis: no_analysis,
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/util/ppaux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,9 @@ impl<'tcx> fmt::Debug for ty::adjustment::AutoAdjustment<'tcx> {
ty::adjustment::AdjustUnsafeFnPointer => {
write!(f, "AdjustUnsafeFnPointer")
}
ty::adjustment::AdjustMutToConstPointer => {
write!(f, "AdjustMutToConstPointer")
}
ty::adjustment::AdjustDerefRef(ref data) => {
write!(f, "{:?}", data)
}
Expand Down
Loading