mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-05 11:33:04 +00:00
Auto merge of #31474 - arielb1:mir-typeck, r=nikomatsakis
This should stop broken MIR from annoying us when we try to implement things
This commit is contained in:
commit
6c751e0456
@ -721,10 +721,11 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
|
|||||||
if let Some(adjustment) = adj {
|
if let Some(adjustment) = adj {
|
||||||
match adjustment {
|
match adjustment {
|
||||||
adjustment::AdjustReifyFnPointer |
|
adjustment::AdjustReifyFnPointer |
|
||||||
adjustment::AdjustUnsafeFnPointer => {
|
adjustment::AdjustUnsafeFnPointer |
|
||||||
|
adjustment::AdjustMutToConstPointer => {
|
||||||
// Creating a closure/fn-pointer or unsizing consumes
|
// Creating a closure/fn-pointer or unsizing consumes
|
||||||
// the input and stores it into the resulting rvalue.
|
// the input and stores it into the resulting rvalue.
|
||||||
debug!("walk_adjustment(AdjustReifyFnPointer|AdjustUnsafeFnPointer)");
|
debug!("walk_adjustment: trivial adjustment");
|
||||||
let cmt_unadjusted =
|
let cmt_unadjusted =
|
||||||
return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
||||||
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
|
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
|
||||||
|
@ -430,6 +430,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
|
|||||||
|
|
||||||
adjustment::AdjustReifyFnPointer |
|
adjustment::AdjustReifyFnPointer |
|
||||||
adjustment::AdjustUnsafeFnPointer |
|
adjustment::AdjustUnsafeFnPointer |
|
||||||
|
adjustment::AdjustMutToConstPointer |
|
||||||
adjustment::AdjustDerefRef(_) => {
|
adjustment::AdjustDerefRef(_) => {
|
||||||
debug!("cat_expr({:?}): {:?}",
|
debug!("cat_expr({:?}): {:?}",
|
||||||
adjustment,
|
adjustment,
|
||||||
|
@ -23,6 +23,7 @@ use rustc_front::hir;
|
|||||||
pub enum AutoAdjustment<'tcx> {
|
pub enum AutoAdjustment<'tcx> {
|
||||||
AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type
|
AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type
|
||||||
AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer
|
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>),
|
AdjustDerefRef(AutoDerefRef<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +107,8 @@ impl<'tcx> AutoAdjustment<'tcx> {
|
|||||||
pub fn is_identity(&self) -> bool {
|
pub fn is_identity(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
AdjustReifyFnPointer |
|
AdjustReifyFnPointer |
|
||||||
AdjustUnsafeFnPointer => false,
|
AdjustUnsafeFnPointer |
|
||||||
|
AdjustMutToConstPointer => false,
|
||||||
AdjustDerefRef(ref r) => r.is_identity(),
|
AdjustDerefRef(ref r) => r.is_identity(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,7 +171,22 @@ impl<'tcx> ty::TyS<'tcx> {
|
|||||||
ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b),
|
ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b),
|
||||||
ref b => {
|
ref b => {
|
||||||
cx.sess.bug(
|
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));
|
b));
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,12 @@ pub struct Tables<'tcx> {
|
|||||||
/// equivalents. This table is not used in trans (since regions
|
/// equivalents. This table is not used in trans (since regions
|
||||||
/// are erased there) and hence is not serialized to metadata.
|
/// are erased there) and hence is not serialized to metadata.
|
||||||
pub liberated_fn_sigs: NodeMap<ty::FnSig<'tcx>>,
|
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> {
|
impl<'tcx> Tables<'tcx> {
|
||||||
@ -144,6 +150,7 @@ impl<'tcx> Tables<'tcx> {
|
|||||||
closure_tys: DefIdMap(),
|
closure_tys: DefIdMap(),
|
||||||
closure_kinds: DefIdMap(),
|
closure_kinds: DefIdMap(),
|
||||||
liberated_fn_sigs: NodeMap(),
|
liberated_fn_sigs: NodeMap(),
|
||||||
|
fru_field_types: NodeMap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,10 +8,12 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use dep_graph::DepNode;
|
||||||
use util::nodemap::NodeMap;
|
use util::nodemap::NodeMap;
|
||||||
use mir::repr::Mir;
|
use mir::repr::Mir;
|
||||||
use mir::transform::MirPass;
|
use mir::transform::MirPass;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
|
use middle::infer;
|
||||||
|
|
||||||
pub struct MirMap<'tcx> {
|
pub struct MirMap<'tcx> {
|
||||||
pub map: NodeMap<Mir<'tcx>>,
|
pub map: NodeMap<Mir<'tcx>>,
|
||||||
@ -19,9 +21,17 @@ pub struct MirMap<'tcx> {
|
|||||||
|
|
||||||
impl<'tcx> MirMap<'tcx> {
|
impl<'tcx> MirMap<'tcx> {
|
||||||
pub fn run_passes(&mut self, passes: &mut [Box<MirPass>], tcx: &ty::ctxt<'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 {
|
for pass in &mut *passes {
|
||||||
pass.run_on_mir(mir, tcx)
|
pass.run_on_mir(mir, &infcx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,9 @@ pub struct Mir<'tcx> {
|
|||||||
/// values in that it is possible to borrow them and mutate them
|
/// values in that it is possible to borrow them and mutate them
|
||||||
/// through the resulting reference.
|
/// through the resulting reference.
|
||||||
pub temp_decls: Vec<TempDecl<'tcx>>,
|
pub temp_decls: Vec<TempDecl<'tcx>>,
|
||||||
|
|
||||||
|
/// A span representing this MIR, for error reporting
|
||||||
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// where execution begins
|
/// where execution begins
|
||||||
@ -145,7 +148,7 @@ pub enum BorrowKind {
|
|||||||
|
|
||||||
/// A "variable" is a binding declared by the user as part of the fn
|
/// A "variable" is a binding declared by the user as part of the fn
|
||||||
/// decl, a let, etc.
|
/// decl, a let, etc.
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||||
pub struct VarDecl<'tcx> {
|
pub struct VarDecl<'tcx> {
|
||||||
pub mutability: Mutability,
|
pub mutability: Mutability,
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
@ -154,7 +157,7 @@ pub struct VarDecl<'tcx> {
|
|||||||
|
|
||||||
/// A "temp" is a temporary that we place on the stack. They are
|
/// A "temp" is a temporary that we place on the stack. They are
|
||||||
/// anonymous, always mutable, and have only a type.
|
/// anonymous, always mutable, and have only a type.
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||||
pub struct TempDecl<'tcx> {
|
pub struct TempDecl<'tcx> {
|
||||||
pub ty: Ty<'tcx>,
|
pub ty: Ty<'tcx>,
|
||||||
}
|
}
|
||||||
@ -170,7 +173,7 @@ pub struct TempDecl<'tcx> {
|
|||||||
///
|
///
|
||||||
/// there is only one argument, of type `(i32, u32)`, but two bindings
|
/// there is only one argument, of type `(i32, u32)`, but two bindings
|
||||||
/// (`x` and `y`).
|
/// (`x` and `y`).
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||||
pub struct ArgDecl<'tcx> {
|
pub struct ArgDecl<'tcx> {
|
||||||
pub ty: Ty<'tcx>,
|
pub ty: Ty<'tcx>,
|
||||||
}
|
}
|
||||||
@ -499,7 +502,7 @@ pub struct Projection<'tcx, B, V> {
|
|||||||
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
|
||||||
pub enum ProjectionElem<'tcx, V> {
|
pub enum ProjectionElem<'tcx, V> {
|
||||||
Deref,
|
Deref,
|
||||||
Field(Field),
|
Field(Field, Ty<'tcx>),
|
||||||
Index(V),
|
Index(V),
|
||||||
|
|
||||||
/// These indices are generated by slice patterns. Easiest to explain
|
/// These indices are generated by slice patterns. Easiest to explain
|
||||||
@ -550,8 +553,8 @@ impl Field {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Lvalue<'tcx> {
|
impl<'tcx> Lvalue<'tcx> {
|
||||||
pub fn field(self, f: Field) -> Lvalue<'tcx> {
|
pub fn field(self, f: Field, ty: Ty<'tcx>) -> Lvalue<'tcx> {
|
||||||
self.elem(ProjectionElem::Field(f))
|
self.elem(ProjectionElem::Field(f, ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deref(self) -> Lvalue<'tcx> {
|
pub fn deref(self) -> Lvalue<'tcx> {
|
||||||
@ -591,8 +594,8 @@ impl<'tcx> Debug for Lvalue<'tcx> {
|
|||||||
write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].name),
|
write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].name),
|
||||||
ProjectionElem::Deref =>
|
ProjectionElem::Deref =>
|
||||||
write!(fmt, "(*{:?})", data.base),
|
write!(fmt, "(*{:?})", data.base),
|
||||||
ProjectionElem::Field(field) =>
|
ProjectionElem::Field(field, ty) =>
|
||||||
write!(fmt, "{:?}.{:?}", data.base, field.index()),
|
write!(fmt, "({:?}.{:?}: {:?})", data.base, field.index(), ty),
|
||||||
ProjectionElem::Index(ref index) =>
|
ProjectionElem::Index(ref index) =>
|
||||||
write!(fmt, "{:?}[{:?}]", data.base, index),
|
write!(fmt, "{:?}[{:?}]", data.base, index),
|
||||||
ProjectionElem::ConstantIndex { offset, min_length, from_end: false } =>
|
ProjectionElem::ConstantIndex { offset, min_length, from_end: false } =>
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use mir::repr::*;
|
use mir::repr::*;
|
||||||
use middle::subst::Substs;
|
use middle::const_eval::ConstVal;
|
||||||
|
use middle::subst::{Subst, Substs};
|
||||||
use middle::ty::{self, AdtDef, Ty};
|
use middle::ty::{self, AdtDef, Ty};
|
||||||
use rustc_front::hir;
|
use rustc_front::hir;
|
||||||
|
|
||||||
@ -72,23 +73,7 @@ impl<'tcx> LvalueTy<'tcx> {
|
|||||||
tcx.sess.bug(&format!("cannot downcast non-enum type: `{:?}`", self))
|
tcx.sess.bug(&format!("cannot downcast non-enum type: `{:?}`", self))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ProjectionElem::Field(field) => {
|
ProjectionElem::Field(_, fty) => LvalueTy::Ty { ty: fty }
|
||||||
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 }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,6 +135,73 @@ impl<'tcx> Mir<'tcx> {
|
|||||||
self.lvalue_ty(tcx, &proj.base).projection_ty(tcx, &proj.elem)
|
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 {
|
impl BorrowKind {
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use mir::repr::Mir;
|
use mir::repr::Mir;
|
||||||
use middle::ty::ctxt;
|
use middle::infer::InferCtxt;
|
||||||
|
|
||||||
pub trait MirPass {
|
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>);
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,7 @@ pub struct Options {
|
|||||||
pub no_trans: bool,
|
pub no_trans: bool,
|
||||||
pub error_format: ErrorOutputType,
|
pub error_format: ErrorOutputType,
|
||||||
pub treat_err_as_bug: bool,
|
pub treat_err_as_bug: bool,
|
||||||
|
pub mir_opt_level: usize,
|
||||||
|
|
||||||
/// if true, build up the dep-graph
|
/// if true, build up the dep-graph
|
||||||
pub build_dep_graph: bool,
|
pub build_dep_graph: bool,
|
||||||
@ -254,6 +255,7 @@ pub fn basic_options() -> Options {
|
|||||||
parse_only: false,
|
parse_only: false,
|
||||||
no_trans: false,
|
no_trans: false,
|
||||||
treat_err_as_bug: false,
|
treat_err_as_bug: false,
|
||||||
|
mir_opt_level: 1,
|
||||||
build_dep_graph: false,
|
build_dep_graph: false,
|
||||||
dump_dep_graph: false,
|
dump_dep_graph: false,
|
||||||
no_analysis: false,
|
no_analysis: false,
|
||||||
@ -655,6 +657,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||||||
"show spans for compiler debugging (expr|pat|ty)"),
|
"show spans for compiler debugging (expr|pat|ty)"),
|
||||||
print_trans_items: Option<String> = (None, parse_opt_string,
|
print_trans_items: Option<String> = (None, parse_opt_string,
|
||||||
"print the result of the translation item collection pass"),
|
"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 {
|
pub fn default_lib_output() -> CrateType {
|
||||||
@ -988,6 +992,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
|||||||
let parse_only = debugging_opts.parse_only;
|
let parse_only = debugging_opts.parse_only;
|
||||||
let no_trans = debugging_opts.no_trans;
|
let no_trans = debugging_opts.no_trans;
|
||||||
let treat_err_as_bug = debugging_opts.treat_err_as_bug;
|
let treat_err_as_bug = debugging_opts.treat_err_as_bug;
|
||||||
|
let mir_opt_level = debugging_opts.mir_opt_level.unwrap_or(1);
|
||||||
let incremental_compilation = debugging_opts.incr_comp;
|
let incremental_compilation = debugging_opts.incr_comp;
|
||||||
let dump_dep_graph = debugging_opts.dump_dep_graph;
|
let dump_dep_graph = debugging_opts.dump_dep_graph;
|
||||||
let no_analysis = debugging_opts.no_analysis;
|
let no_analysis = debugging_opts.no_analysis;
|
||||||
@ -1166,6 +1171,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
|||||||
parse_only: parse_only,
|
parse_only: parse_only,
|
||||||
no_trans: no_trans,
|
no_trans: no_trans,
|
||||||
treat_err_as_bug: treat_err_as_bug,
|
treat_err_as_bug: treat_err_as_bug,
|
||||||
|
mir_opt_level: mir_opt_level,
|
||||||
build_dep_graph: incremental_compilation || dump_dep_graph,
|
build_dep_graph: incremental_compilation || dump_dep_graph,
|
||||||
dump_dep_graph: dump_dep_graph,
|
dump_dep_graph: dump_dep_graph,
|
||||||
no_analysis: no_analysis,
|
no_analysis: no_analysis,
|
||||||
|
@ -396,6 +396,9 @@ impl<'tcx> fmt::Debug for ty::adjustment::AutoAdjustment<'tcx> {
|
|||||||
ty::adjustment::AdjustUnsafeFnPointer => {
|
ty::adjustment::AdjustUnsafeFnPointer => {
|
||||||
write!(f, "AdjustUnsafeFnPointer")
|
write!(f, "AdjustUnsafeFnPointer")
|
||||||
}
|
}
|
||||||
|
ty::adjustment::AdjustMutToConstPointer => {
|
||||||
|
write!(f, "AdjustMutToConstPointer")
|
||||||
|
}
|
||||||
ty::adjustment::AdjustDerefRef(ref data) => {
|
ty::adjustment::AdjustDerefRef(ref data) => {
|
||||||
write!(f, "{:?}", data)
|
write!(f, "{:?}", data)
|
||||||
}
|
}
|
||||||
|
@ -844,6 +844,18 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
|||||||
"match checking",
|
"match checking",
|
||||||
|| middle::check_match::check_crate(tcx));
|
|| middle::check_match::check_crate(tcx));
|
||||||
|
|
||||||
|
// this must run before MIR dump, because
|
||||||
|
// "not all control paths return a value" is reported here.
|
||||||
|
//
|
||||||
|
// maybe move the check to a MIR pass?
|
||||||
|
time(time_passes,
|
||||||
|
"liveness checking",
|
||||||
|
|| middle::liveness::check_crate(tcx));
|
||||||
|
|
||||||
|
time(time_passes,
|
||||||
|
"rvalue checking",
|
||||||
|
|| rvalues::check_crate(tcx));
|
||||||
|
|
||||||
let mut mir_map =
|
let mut mir_map =
|
||||||
time(time_passes,
|
time(time_passes,
|
||||||
"MIR dump",
|
"MIR dump",
|
||||||
@ -853,18 +865,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
|||||||
"MIR passes",
|
"MIR passes",
|
||||||
|| mir_map.run_passes(&mut sess.plugin_mir_passes.borrow_mut(), tcx));
|
|| mir_map.run_passes(&mut sess.plugin_mir_passes.borrow_mut(), tcx));
|
||||||
|
|
||||||
time(time_passes,
|
|
||||||
"liveness checking",
|
|
||||||
|| middle::liveness::check_crate(tcx));
|
|
||||||
|
|
||||||
time(time_passes,
|
time(time_passes,
|
||||||
"borrow checking",
|
"borrow checking",
|
||||||
|| borrowck::check_crate(tcx));
|
|| borrowck::check_crate(tcx));
|
||||||
|
|
||||||
time(time_passes,
|
|
||||||
"rvalue checking",
|
|
||||||
|| rvalues::check_crate(tcx));
|
|
||||||
|
|
||||||
// Avoid overwhelming user with errors if type checking failed.
|
// Avoid overwhelming user with errors if type checking failed.
|
||||||
// I'm not sure how helpful this is, to be honest, but it avoids
|
// I'm not sure how helpful this is, to be honest, but it avoids
|
||||||
// a
|
// a
|
||||||
|
@ -620,8 +620,14 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adjustment::AdjustMutToConstPointer => {
|
||||||
|
this.emit_enum_variant("AdjustMutToConstPointer", 3, 0, |_| {
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
adjustment::AdjustDerefRef(ref auto_deref_ref) => {
|
adjustment::AdjustDerefRef(ref auto_deref_ref) => {
|
||||||
this.emit_enum_variant("AdjustDerefRef", 3, 2, |this| {
|
this.emit_enum_variant("AdjustDerefRef", 4, 2, |this| {
|
||||||
this.emit_enum_variant_arg(0,
|
this.emit_enum_variant_arg(0,
|
||||||
|this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref)))
|
|this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref)))
|
||||||
})
|
})
|
||||||
@ -1002,12 +1008,14 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
|
|||||||
fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
|
fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
|
||||||
-> adjustment::AutoAdjustment<'tcx> {
|
-> adjustment::AutoAdjustment<'tcx> {
|
||||||
self.read_enum("AutoAdjustment", |this| {
|
self.read_enum("AutoAdjustment", |this| {
|
||||||
let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", "AdjustDerefRef"];
|
let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer",
|
||||||
|
"AdjustMutToConstPointer", "AdjustDerefRef"];
|
||||||
this.read_enum_variant(&variants, |this, i| {
|
this.read_enum_variant(&variants, |this, i| {
|
||||||
Ok(match i {
|
Ok(match i {
|
||||||
1 => adjustment::AdjustReifyFnPointer,
|
1 => adjustment::AdjustReifyFnPointer,
|
||||||
2 => adjustment::AdjustUnsafeFnPointer,
|
2 => adjustment::AdjustUnsafeFnPointer,
|
||||||
3 => {
|
3 => adjustment::AdjustMutToConstPointer,
|
||||||
|
4 => {
|
||||||
let auto_deref_ref: adjustment::AutoDerefRef =
|
let auto_deref_ref: adjustment::AutoDerefRef =
|
||||||
this.read_enum_variant_arg(0,
|
this.read_enum_variant_arg(0,
|
||||||
|this| Ok(this.read_auto_deref_ref(dcx))).unwrap();
|
|this| Ok(this.read_auto_deref_ref(dcx))).unwrap();
|
||||||
|
@ -41,7 +41,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
}
|
}
|
||||||
ExprKind::Field { lhs, name } => {
|
ExprKind::Field { lhs, name } => {
|
||||||
let lvalue = unpack!(block = this.as_lvalue(block, lhs));
|
let lvalue = unpack!(block = this.as_lvalue(block, lhs));
|
||||||
let lvalue = lvalue.field(name);
|
let lvalue = lvalue.field(name, expr.ty);
|
||||||
block.and(lvalue)
|
block.and(lvalue)
|
||||||
}
|
}
|
||||||
ExprKind::Deref { arg } => {
|
ExprKind::Deref { arg } => {
|
||||||
|
@ -139,7 +139,9 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
.collect();
|
.collect();
|
||||||
block.and(Rvalue::Aggregate(AggregateKind::Closure(closure_id, substs), upvars))
|
block.and(Rvalue::Aggregate(AggregateKind::Closure(closure_id, substs), upvars))
|
||||||
}
|
}
|
||||||
ExprKind::Adt { adt_def, variant_index, substs, fields, base } => { // see (*) above
|
ExprKind::Adt {
|
||||||
|
adt_def, variant_index, substs, fields, base
|
||||||
|
} => { // see (*) above
|
||||||
// first process the set of fields that were provided
|
// first process the set of fields that were provided
|
||||||
// (evaluating them in order given by user)
|
// (evaluating them in order given by user)
|
||||||
let fields_map: FnvHashMap<_, _> =
|
let fields_map: FnvHashMap<_, _> =
|
||||||
@ -147,25 +149,24 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
.map(|f| (f.name, unpack!(block = this.as_operand(block, f.expr))))
|
.map(|f| (f.name, unpack!(block = this.as_operand(block, f.expr))))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// if base expression is given, evaluate it now
|
|
||||||
let base = base.map(|base| unpack!(block = this.as_lvalue(block, base)));
|
|
||||||
|
|
||||||
// get list of all fields that we will need
|
|
||||||
let field_names = this.hir.all_fields(adt_def, variant_index);
|
let field_names = this.hir.all_fields(adt_def, variant_index);
|
||||||
|
|
||||||
// for the actual values we use, take either the
|
let fields = if let Some(FruInfo { base, field_types }) = base {
|
||||||
// expr the user specified or, if they didn't
|
let base = unpack!(block = this.as_lvalue(block, base));
|
||||||
// specify something for this field name, create a
|
|
||||||
// path relative to the base (which must have been
|
// MIR does not natively support FRU, so for each
|
||||||
// supplied, or the IR is internally
|
// base-supplied field, generate an operand that
|
||||||
// inconsistent).
|
// reads it from the base.
|
||||||
let fields: Vec<_> =
|
|
||||||
field_names.into_iter()
|
field_names.into_iter()
|
||||||
.map(|n| match fields_map.get(&n) {
|
.zip(field_types.into_iter())
|
||||||
|
.map(|(n, ty)| match fields_map.get(&n) {
|
||||||
Some(v) => v.clone(),
|
Some(v) => v.clone(),
|
||||||
None => Operand::Consume(base.clone().unwrap().field(n)),
|
None => Operand::Consume(base.clone().field(n, ty))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect()
|
||||||
|
} else {
|
||||||
|
field_names.iter().map(|n| fields_map[n].clone()).collect()
|
||||||
|
};
|
||||||
|
|
||||||
block.and(Rvalue::Aggregate(AggregateKind::Adt(adt_def, variant_index, substs),
|
block.and(Rvalue::Aggregate(AggregateKind::Adt(adt_def, variant_index, substs),
|
||||||
fields))
|
fields))
|
||||||
|
@ -404,7 +404,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
subpatterns.iter()
|
subpatterns.iter()
|
||||||
.map(|subpattern| {
|
.map(|subpattern| {
|
||||||
// e.g., `(x as Variant).0`
|
// e.g., `(x as Variant).0`
|
||||||
let lvalue = downcast_lvalue.clone().field(subpattern.field);
|
let lvalue = downcast_lvalue.clone().field(subpattern.field,
|
||||||
|
subpattern.field_ty());
|
||||||
// e.g., `(x as Variant).0 @ P1`
|
// e.g., `(x as Variant).0 @ P1`
|
||||||
MatchPair::new(lvalue, &subpattern.pattern)
|
MatchPair::new(lvalue, &subpattern.pattern)
|
||||||
});
|
});
|
||||||
|
@ -21,7 +21,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
-> Vec<MatchPair<'pat, 'tcx>> {
|
-> Vec<MatchPair<'pat, 'tcx>> {
|
||||||
subpatterns.iter()
|
subpatterns.iter()
|
||||||
.map(|fieldpat| {
|
.map(|fieldpat| {
|
||||||
let lvalue = lvalue.clone().field(fieldpat.field);
|
let lvalue = lvalue.clone().field(fieldpat.field,
|
||||||
|
fieldpat.field_ty());
|
||||||
MatchPair::new(lvalue, &fieldpat.pattern)
|
MatchPair::new(lvalue, &fieldpat.pattern)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -80,7 +80,7 @@ macro_rules! unpack {
|
|||||||
/// the main entry point for building MIR for a function
|
/// the main entry point for building MIR for a function
|
||||||
|
|
||||||
pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
|
pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
|
||||||
_span: Span,
|
span: Span,
|
||||||
implicit_arguments: Vec<Ty<'tcx>>,
|
implicit_arguments: Vec<Ty<'tcx>>,
|
||||||
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
|
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
|
||||||
argument_extent: CodeExtent,
|
argument_extent: CodeExtent,
|
||||||
@ -97,7 +97,7 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
|
|||||||
temp_decls: vec![],
|
temp_decls: vec![],
|
||||||
var_decls: vec![],
|
var_decls: vec![],
|
||||||
var_indices: FnvHashMap(),
|
var_indices: FnvHashMap(),
|
||||||
unit_temp: None
|
unit_temp: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
|
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
|
||||||
@ -119,6 +119,7 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
|
|||||||
arg_decls: arg_decls,
|
arg_decls: arg_decls,
|
||||||
temp_decls: builder.temp_decls,
|
temp_decls: builder.temp_decls,
|
||||||
return_ty: return_ty,
|
return_ty: return_ty,
|
||||||
|
span: span
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,25 +418,28 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
len: Operand<'tcx>,
|
len: Operand<'tcx>,
|
||||||
span: Span) {
|
span: Span) {
|
||||||
// fn(&(filename: &'static str, line: u32), index: usize, length: usize) -> !
|
// fn(&(filename: &'static str, line: u32), index: usize, length: usize) -> !
|
||||||
|
let region = ty::ReStatic; // FIXME(mir-borrowck): use a better region?
|
||||||
let func = self.lang_function(lang_items::PanicBoundsCheckFnLangItem);
|
let func = self.lang_function(lang_items::PanicBoundsCheckFnLangItem);
|
||||||
let args = func.ty.fn_args();
|
let args = self.hir.tcx().replace_late_bound_regions(&func.ty.fn_args(), |_| region).0;
|
||||||
let ref_ty = args.skip_binder()[0];
|
|
||||||
let (region, tup_ty) = if let ty::TyRef(region, tyandmut) = ref_ty.sty {
|
let ref_ty = args[0];
|
||||||
(region, tyandmut.ty)
|
let tup_ty = if let ty::TyRef(_, tyandmut) = ref_ty.sty {
|
||||||
|
tyandmut.ty
|
||||||
} else {
|
} else {
|
||||||
self.hir.span_bug(span, &format!("unexpected panic_bound_check type: {:?}", func.ty));
|
self.hir.span_bug(span, &format!("unexpected panic_bound_check type: {:?}", func.ty));
|
||||||
};
|
};
|
||||||
|
|
||||||
let (tuple, tuple_ref) = (self.temp(tup_ty), self.temp(ref_ty));
|
let (tuple, tuple_ref) = (self.temp(tup_ty), self.temp(ref_ty));
|
||||||
let (file, line) = self.span_to_fileline_args(span);
|
let (file, line) = self.span_to_fileline_args(span);
|
||||||
let elems = vec![Operand::Constant(file), Operand::Constant(line)];
|
let elems = vec![Operand::Constant(file), Operand::Constant(line)];
|
||||||
// FIXME: We should have this as a constant, rather than a stack variable (to not pollute
|
// FIXME: We should have this as a constant, rather than a stack variable (to not pollute
|
||||||
// icache with cold branch code), however to achieve that we either have to rely on rvalue
|
// icache with cold branch code), however to achieve that we either have to rely on rvalue
|
||||||
// promotion or have some way, in MIR, to create constants.
|
// promotion or have some way, in MIR, to create constants.
|
||||||
self.cfg.push_assign(block, DUMMY_SP, &tuple, // tuple = (file_arg, line_arg);
|
self.cfg.push_assign(block, span, &tuple, // tuple = (file_arg, line_arg);
|
||||||
Rvalue::Aggregate(AggregateKind::Tuple, elems));
|
Rvalue::Aggregate(AggregateKind::Tuple, elems));
|
||||||
// FIXME: is this region really correct here?
|
// FIXME: is this region really correct here?
|
||||||
self.cfg.push_assign(block, DUMMY_SP, &tuple_ref, // tuple_ref = &tuple;
|
self.cfg.push_assign(block, span, &tuple_ref, // tuple_ref = &tuple;
|
||||||
Rvalue::Ref(*region, BorrowKind::Unique, tuple));
|
Rvalue::Ref(region, BorrowKind::Shared, tuple));
|
||||||
let cleanup = self.diverge_cleanup();
|
let cleanup = self.diverge_cleanup();
|
||||||
self.cfg.terminate(block, Terminator::Call {
|
self.cfg.terminate(block, Terminator::Call {
|
||||||
func: Operand::Constant(func),
|
func: Operand::Constant(func),
|
||||||
@ -449,18 +452,21 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
/// Create diverge cleanup and branch to it from `block`.
|
/// Create diverge cleanup and branch to it from `block`.
|
||||||
pub fn panic(&mut self, block: BasicBlock, msg: &'static str, span: Span) {
|
pub fn panic(&mut self, block: BasicBlock, msg: &'static str, span: Span) {
|
||||||
// fn(&(msg: &'static str filename: &'static str, line: u32)) -> !
|
// fn(&(msg: &'static str filename: &'static str, line: u32)) -> !
|
||||||
|
let region = ty::ReStatic; // FIXME(mir-borrowck): use a better region?
|
||||||
let func = self.lang_function(lang_items::PanicFnLangItem);
|
let func = self.lang_function(lang_items::PanicFnLangItem);
|
||||||
let args = func.ty.fn_args();
|
let args = self.hir.tcx().replace_late_bound_regions(&func.ty.fn_args(), |_| region).0;
|
||||||
let ref_ty = args.skip_binder()[0];
|
|
||||||
let (region, tup_ty) = if let ty::TyRef(region, tyandmut) = ref_ty.sty {
|
let ref_ty = args[0];
|
||||||
(region, tyandmut.ty)
|
let tup_ty = if let ty::TyRef(_, tyandmut) = ref_ty.sty {
|
||||||
|
tyandmut.ty
|
||||||
} else {
|
} else {
|
||||||
self.hir.span_bug(span, &format!("unexpected panic type: {:?}", func.ty));
|
self.hir.span_bug(span, &format!("unexpected panic type: {:?}", func.ty));
|
||||||
};
|
};
|
||||||
|
|
||||||
let (tuple, tuple_ref) = (self.temp(tup_ty), self.temp(ref_ty));
|
let (tuple, tuple_ref) = (self.temp(tup_ty), self.temp(ref_ty));
|
||||||
let (file, line) = self.span_to_fileline_args(span);
|
let (file, line) = self.span_to_fileline_args(span);
|
||||||
let message = Constant {
|
let message = Constant {
|
||||||
span: DUMMY_SP,
|
span: span,
|
||||||
ty: self.hir.tcx().mk_static_str(),
|
ty: self.hir.tcx().mk_static_str(),
|
||||||
literal: self.hir.str_literal(intern_and_get_ident(msg))
|
literal: self.hir.str_literal(intern_and_get_ident(msg))
|
||||||
};
|
};
|
||||||
@ -470,11 +476,11 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
// FIXME: We should have this as a constant, rather than a stack variable (to not pollute
|
// FIXME: We should have this as a constant, rather than a stack variable (to not pollute
|
||||||
// icache with cold branch code), however to achieve that we either have to rely on rvalue
|
// icache with cold branch code), however to achieve that we either have to rely on rvalue
|
||||||
// promotion or have some way, in MIR, to create constants.
|
// promotion or have some way, in MIR, to create constants.
|
||||||
self.cfg.push_assign(block, DUMMY_SP, &tuple, // tuple = (message_arg, file_arg, line_arg);
|
self.cfg.push_assign(block, span, &tuple, // tuple = (message_arg, file_arg, line_arg);
|
||||||
Rvalue::Aggregate(AggregateKind::Tuple, elems));
|
Rvalue::Aggregate(AggregateKind::Tuple, elems));
|
||||||
// FIXME: is this region really correct here?
|
// FIXME: is this region really correct here?
|
||||||
self.cfg.push_assign(block, DUMMY_SP, &tuple_ref, // tuple_ref = &tuple;
|
self.cfg.push_assign(block, span, &tuple_ref, // tuple_ref = &tuple;
|
||||||
Rvalue::Ref(*region, BorrowKind::Unique, tuple));
|
Rvalue::Ref(region, BorrowKind::Shared, tuple));
|
||||||
let cleanup = self.diverge_cleanup();
|
let cleanup = self.diverge_cleanup();
|
||||||
self.cfg.terminate(block, Terminator::Call {
|
self.cfg.terminate(block, Terminator::Call {
|
||||||
func: Operand::Constant(func),
|
func: Operand::Constant(func),
|
||||||
@ -505,11 +511,11 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
fn span_to_fileline_args(&mut self, span: Span) -> (Constant<'tcx>, Constant<'tcx>) {
|
fn span_to_fileline_args(&mut self, span: Span) -> (Constant<'tcx>, Constant<'tcx>) {
|
||||||
let span_lines = self.hir.tcx().sess.codemap().lookup_char_pos(span.lo);
|
let span_lines = self.hir.tcx().sess.codemap().lookup_char_pos(span.lo);
|
||||||
(Constant {
|
(Constant {
|
||||||
span: DUMMY_SP,
|
span: span,
|
||||||
ty: self.hir.tcx().mk_static_str(),
|
ty: self.hir.tcx().mk_static_str(),
|
||||||
literal: self.hir.str_literal(intern_and_get_ident(&span_lines.file.name))
|
literal: self.hir.str_literal(intern_and_get_ident(&span_lines.file.name))
|
||||||
}, Constant {
|
}, Constant {
|
||||||
span: DUMMY_SP,
|
span: span,
|
||||||
ty: self.hir.tcx().types.u32,
|
ty: self.hir.tcx().types.u32,
|
||||||
literal: self.hir.usize_literal(span_lines.line)
|
literal: self.hir.usize_literal(span_lines.line)
|
||||||
})
|
})
|
||||||
|
@ -32,6 +32,8 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||||||
debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
|
debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
|
||||||
|
|
||||||
let expr_ty = cx.tcx.expr_ty(self); // note: no adjustments (yet)!
|
let expr_ty = cx.tcx.expr_ty(self); // note: no adjustments (yet)!
|
||||||
|
let temp_lifetime = cx.tcx.region_maps.temporary_scope(self.id);
|
||||||
|
let expr_extent = cx.tcx.region_maps.node_extent(self.id);
|
||||||
|
|
||||||
let kind = match self.node {
|
let kind = match self.node {
|
||||||
// Here comes the interesting stuff:
|
// Here comes the interesting stuff:
|
||||||
@ -54,14 +56,35 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||||||
// Find the actual method implementation being called and
|
// Find the actual method implementation being called and
|
||||||
// build the appropriate UFCS call expression with the
|
// build the appropriate UFCS call expression with the
|
||||||
// callee-object as self parameter.
|
// callee-object as self parameter.
|
||||||
|
|
||||||
|
// rewrite f(u, v) into FnOnce::call_once(f, (u, v))
|
||||||
|
|
||||||
let method = method_callee(cx, self, ty::MethodCall::expr(self.id));
|
let method = method_callee(cx, self, ty::MethodCall::expr(self.id));
|
||||||
let mut argrefs = vec![fun.to_ref()];
|
|
||||||
argrefs.extend(args.iter().map(|a| a.to_ref()));
|
let sig = match method.ty.sty {
|
||||||
|
ty::TyBareFn(_, fn_ty) => &fn_ty.sig,
|
||||||
|
_ => cx.tcx.sess.span_bug(self.span, "type of method is not an fn")
|
||||||
|
};
|
||||||
|
|
||||||
|
let sig = cx.tcx.no_late_bound_regions(sig).unwrap_or_else(|| {
|
||||||
|
cx.tcx.sess.span_bug(self.span, "method call has late-bound regions")
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(sig.inputs.len(), 2);
|
||||||
|
|
||||||
|
let tupled_args = Expr {
|
||||||
|
ty: sig.inputs[1],
|
||||||
|
temp_lifetime: temp_lifetime,
|
||||||
|
span: self.span,
|
||||||
|
kind: ExprKind::Tuple {
|
||||||
|
fields: args.iter().map(ToRef::to_ref).collect()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ExprKind::Call {
|
ExprKind::Call {
|
||||||
ty: method.ty,
|
ty: method.ty,
|
||||||
fun: method.to_ref(),
|
fun: method.to_ref(),
|
||||||
args: argrefs,
|
args: vec![fun.to_ref(), tupled_args.to_ref()]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let adt_data = if let hir::ExprPath(..) = fun.node {
|
let adt_data = if let hir::ExprPath(..) = fun.node {
|
||||||
@ -125,13 +148,22 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprAssignOp(op, ref lhs, ref rhs) => {
|
hir::ExprAssignOp(op, ref lhs, ref rhs) => {
|
||||||
let op = bin_op(op.node);
|
if cx.tcx.is_method_call(self.id) {
|
||||||
|
let pass_args = if hir_util::is_by_value_binop(op.node) {
|
||||||
|
PassArgs::ByValue
|
||||||
|
} else {
|
||||||
|
PassArgs::ByRef
|
||||||
|
};
|
||||||
|
overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
|
||||||
|
pass_args, lhs.to_ref(), vec![rhs])
|
||||||
|
} else {
|
||||||
ExprKind::AssignOp {
|
ExprKind::AssignOp {
|
||||||
op: op,
|
op: bin_op(op.node),
|
||||||
lhs: lhs.to_ref(),
|
lhs: lhs.to_ref(),
|
||||||
rhs: rhs.to_ref(),
|
rhs: rhs.to_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hir::ExprLit(..) => ExprKind::Literal {
|
hir::ExprLit(..) => ExprKind::Literal {
|
||||||
literal: cx.const_eval_literal(self)
|
literal: cx.const_eval_literal(self)
|
||||||
@ -227,13 +259,23 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||||||
variant_index: 0,
|
variant_index: 0,
|
||||||
substs: substs,
|
substs: substs,
|
||||||
fields: field_refs,
|
fields: field_refs,
|
||||||
|
base: base.as_ref().map(|base| {
|
||||||
|
FruInfo {
|
||||||
base: base.to_ref(),
|
base: base.to_ref(),
|
||||||
|
field_types: cx.tcx.tables
|
||||||
|
.borrow()
|
||||||
|
.fru_field_types[&self.id]
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::TyEnum(adt, substs) => {
|
ty::TyEnum(adt, substs) => {
|
||||||
match cx.tcx.def_map.borrow()[&self.id].full_def() {
|
match cx.tcx.def_map.borrow()[&self.id].full_def() {
|
||||||
Def::Variant(enum_id, variant_id) => {
|
Def::Variant(enum_id, variant_id) => {
|
||||||
debug_assert!(adt.did == enum_id);
|
debug_assert!(adt.did == enum_id);
|
||||||
|
assert!(base.is_none());
|
||||||
|
|
||||||
let index = adt.variant_index_with_id(variant_id);
|
let index = adt.variant_index_with_id(variant_id);
|
||||||
let field_refs = field_refs(&adt.variants[index], fields);
|
let field_refs = field_refs(&adt.variants[index], fields);
|
||||||
ExprKind::Adt {
|
ExprKind::Adt {
|
||||||
@ -241,7 +283,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||||||
variant_index: index,
|
variant_index: index,
|
||||||
substs: substs,
|
substs: substs,
|
||||||
fields: field_refs,
|
fields: field_refs,
|
||||||
base: base.to_ref(),
|
base: None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ref def => {
|
ref def => {
|
||||||
@ -385,9 +427,6 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||||||
ExprKind::Tuple { fields: fields.to_ref() },
|
ExprKind::Tuple { fields: fields.to_ref() },
|
||||||
};
|
};
|
||||||
|
|
||||||
let temp_lifetime = cx.tcx.region_maps.temporary_scope(self.id);
|
|
||||||
let expr_extent = cx.tcx.region_maps.node_extent(self.id);
|
|
||||||
|
|
||||||
let mut expr = Expr {
|
let mut expr = Expr {
|
||||||
temp_lifetime: temp_lifetime,
|
temp_lifetime: temp_lifetime,
|
||||||
ty: expr_ty,
|
ty: expr_ty,
|
||||||
@ -395,6 +434,9 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||||||
kind: kind,
|
kind: kind,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
|
||||||
|
expr, cx.tcx.tables.borrow().adjustments.get(&self.id));
|
||||||
|
|
||||||
// Now apply adjustments, if any.
|
// Now apply adjustments, if any.
|
||||||
match cx.tcx.tables.borrow().adjustments.get(&self.id) {
|
match cx.tcx.tables.borrow().adjustments.get(&self.id) {
|
||||||
None => {}
|
None => {}
|
||||||
@ -416,6 +458,15 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||||||
kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
|
kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Some(&ty::adjustment::AdjustMutToConstPointer) => {
|
||||||
|
let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
|
||||||
|
expr = Expr {
|
||||||
|
temp_lifetime: temp_lifetime,
|
||||||
|
ty: adjusted_ty,
|
||||||
|
span: self.span,
|
||||||
|
kind: ExprKind::Cast { source: expr.to_ref() },
|
||||||
|
};
|
||||||
|
}
|
||||||
Some(&ty::adjustment::AdjustDerefRef(ref adj)) => {
|
Some(&ty::adjustment::AdjustDerefRef(ref adj)) => {
|
||||||
for i in 0..adj.autoderefs {
|
for i in 0..adj.autoderefs {
|
||||||
let i = i as u32;
|
let i = i as u32;
|
||||||
@ -426,10 +477,38 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||||||
self.span,
|
self.span,
|
||||||
i,
|
i,
|
||||||
|mc| cx.tcx.tables.borrow().method_map.get(&mc).map(|m| m.ty));
|
|mc| cx.tcx.tables.borrow().method_map.get(&mc).map(|m| m.ty));
|
||||||
let kind = if cx.tcx.is_overloaded_autoderef(self.id, i) {
|
debug!("make_mirror: autoderef #{}, adjusted_ty={:?}", i, adjusted_ty);
|
||||||
overloaded_lvalue(cx, self, ty::MethodCall::autoderef(self.id, i),
|
let method_key = ty::MethodCall::autoderef(self.id, i);
|
||||||
PassArgs::ByValue, expr.to_ref(), vec![])
|
let meth_ty =
|
||||||
|
cx.tcx.tables.borrow().method_map.get(&method_key).map(|m| m.ty);
|
||||||
|
let kind = if let Some(meth_ty) = meth_ty {
|
||||||
|
debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty);
|
||||||
|
|
||||||
|
let ref_ty = cx.tcx.no_late_bound_regions(&meth_ty.fn_ret());
|
||||||
|
let (region, mutbl) = match ref_ty {
|
||||||
|
Some(ty::FnConverging(&ty::TyS {
|
||||||
|
sty: ty::TyRef(region, mt), ..
|
||||||
|
})) => (region, mt.mutbl),
|
||||||
|
_ => cx.tcx.sess.span_bug(
|
||||||
|
expr.span, "autoderef returned bad type")
|
||||||
|
};
|
||||||
|
|
||||||
|
expr = Expr {
|
||||||
|
temp_lifetime: temp_lifetime,
|
||||||
|
ty: cx.tcx.mk_ref(
|
||||||
|
region, ty::TypeAndMut { ty: expr.ty, mutbl: mutbl }),
|
||||||
|
span: expr.span,
|
||||||
|
kind: ExprKind::Borrow {
|
||||||
|
region: *region,
|
||||||
|
borrow_kind: to_borrow_kind(mutbl),
|
||||||
|
arg: expr.to_ref()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
overloaded_lvalue(cx, self, method_key,
|
||||||
|
PassArgs::ByRef, expr.to_ref(), vec![])
|
||||||
} else {
|
} else {
|
||||||
|
debug!("make_mirror: built-in autoderef");
|
||||||
ExprKind::Deref { arg: expr.to_ref() }
|
ExprKind::Deref { arg: expr.to_ref() }
|
||||||
};
|
};
|
||||||
expr = Expr {
|
expr = Expr {
|
||||||
@ -749,11 +828,16 @@ fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
|
|||||||
};
|
};
|
||||||
match upvar_capture {
|
match upvar_capture {
|
||||||
ty::UpvarCapture::ByValue => field_kind,
|
ty::UpvarCapture::ByValue => field_kind,
|
||||||
ty::UpvarCapture::ByRef(_) => {
|
ty::UpvarCapture::ByRef(borrow) => {
|
||||||
ExprKind::Deref {
|
ExprKind::Deref {
|
||||||
arg: Expr {
|
arg: Expr {
|
||||||
temp_lifetime: temp_lifetime,
|
temp_lifetime: temp_lifetime,
|
||||||
|
ty: cx.tcx.mk_ref(
|
||||||
|
cx.tcx.mk_region(borrow.region),
|
||||||
|
ty::TypeAndMut {
|
||||||
ty: var_ty,
|
ty: var_ty,
|
||||||
|
mutbl: borrow.kind.to_mutbl_lossy()
|
||||||
|
}),
|
||||||
span: expr.span,
|
span: expr.span,
|
||||||
kind: field_kind,
|
kind: field_kind,
|
||||||
}.to_ref()
|
}.to_ref()
|
||||||
|
@ -314,3 +314,20 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> FieldPattern<'tcx> {
|
||||||
|
pub fn field_ty(&self) -> Ty<'tcx> {
|
||||||
|
debug!("field_ty({:?},ty={:?})", self, self.pattern.ty);
|
||||||
|
let r = match *self.pattern.kind {
|
||||||
|
PatternKind::Binding { mode: BindingMode::ByRef(..), ..} => {
|
||||||
|
match self.pattern.ty.sty {
|
||||||
|
ty::TyRef(_, mt) => mt.ty,
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => self.pattern.ty
|
||||||
|
};
|
||||||
|
debug!("field_ty -> {:?}", r);
|
||||||
|
r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -229,7 +229,7 @@ pub enum ExprKind<'tcx> {
|
|||||||
variant_index: usize,
|
variant_index: usize,
|
||||||
substs: &'tcx Substs<'tcx>,
|
substs: &'tcx Substs<'tcx>,
|
||||||
fields: Vec<FieldExprRef<'tcx>>,
|
fields: Vec<FieldExprRef<'tcx>>,
|
||||||
base: Option<ExprRef<'tcx>>,
|
base: Option<FruInfo<'tcx>>
|
||||||
},
|
},
|
||||||
Closure {
|
Closure {
|
||||||
closure_id: DefId,
|
closure_id: DefId,
|
||||||
@ -256,6 +256,12 @@ pub struct FieldExprRef<'tcx> {
|
|||||||
pub expr: ExprRef<'tcx>,
|
pub expr: ExprRef<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct FruInfo<'tcx> {
|
||||||
|
pub base: ExprRef<'tcx>,
|
||||||
|
pub field_types: Vec<Ty<'tcx>>
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Arm<'tcx> {
|
pub struct Arm<'tcx> {
|
||||||
pub patterns: Vec<Pattern<'tcx>>,
|
pub patterns: Vec<Pattern<'tcx>>,
|
||||||
|
@ -20,6 +20,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
|||||||
#![cfg_attr(not(stage0), deny(warnings))]
|
#![cfg_attr(not(stage0), deny(warnings))]
|
||||||
#![unstable(feature = "rustc_private", issue = "27812")]
|
#![unstable(feature = "rustc_private", issue = "27812")]
|
||||||
|
|
||||||
|
#![feature(box_patterns)]
|
||||||
#![feature(rustc_private)]
|
#![feature(rustc_private)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
|
|
||||||
|
@ -22,7 +22,8 @@ extern crate rustc_front;
|
|||||||
use build;
|
use build;
|
||||||
use graphviz;
|
use graphviz;
|
||||||
use pretty;
|
use pretty;
|
||||||
use transform::{simplify_cfg, no_landing_pads};
|
use transform::{clear_dead_blocks, simplify_cfg, type_check};
|
||||||
|
use transform::{no_landing_pads};
|
||||||
use rustc::dep_graph::DepNode;
|
use rustc::dep_graph::DepNode;
|
||||||
use rustc::mir::repr::Mir;
|
use rustc::mir::repr::Mir;
|
||||||
use hair::cx::Cx;
|
use hair::cx::Cx;
|
||||||
@ -148,9 +149,12 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
|
|||||||
|
|
||||||
match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
|
match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
|
||||||
Ok(mut mir) => {
|
Ok(mut mir) => {
|
||||||
no_landing_pads::NoLandingPads.run_on_mir(&mut mir, self.tcx);
|
clear_dead_blocks::ClearDeadBlocks::new().run_on_mir(&mut mir, &infcx);
|
||||||
simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, self.tcx);
|
type_check::TypeckMir::new().run_on_mir(&mut mir, &infcx);
|
||||||
|
no_landing_pads::NoLandingPads.run_on_mir(&mut mir, &infcx);
|
||||||
|
if self.tcx.sess.opts.mir_opt_level > 0 {
|
||||||
|
simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, &infcx);
|
||||||
|
}
|
||||||
let meta_item_list = self.attr
|
let meta_item_list = self.attr
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|a| a.meta_item_list())
|
.flat_map(|a| a.meta_item_list())
|
||||||
|
81
src/librustc_mir/transform/clear_dead_blocks.rs
Normal file
81
src/librustc_mir/transform/clear_dead_blocks.rs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! A pass that erases the contents of dead blocks. This pass must
|
||||||
|
//! run before any analysis passes because some of the dead blocks
|
||||||
|
//! can be ill-typed.
|
||||||
|
//!
|
||||||
|
//! The main problem is that typeck lets most blocks whose end is not
|
||||||
|
//! reachable have an arbitrary return type, rather than having the
|
||||||
|
//! usual () return type (as a note, typeck's notion of reachability
|
||||||
|
//! is in fact slightly weaker than MIR CFG reachability - see #31617).
|
||||||
|
//!
|
||||||
|
//! A standard example of the situation is:
|
||||||
|
//! ```rust
|
||||||
|
//! fn example() {
|
||||||
|
//! let _a: char = { return; };
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Here the block (`{ return; }`) has the return type `char`,
|
||||||
|
//! rather than `()`, but the MIR we naively generate still contains
|
||||||
|
//! the `_a = ()` write in the unreachable block "after" the return.
|
||||||
|
//!
|
||||||
|
//! As we have to run this pass even when we want to debug the MIR,
|
||||||
|
//! this pass just replaces the blocks with empty "return" blocks
|
||||||
|
//! and does not renumber anything.
|
||||||
|
|
||||||
|
use rustc::middle::infer;
|
||||||
|
use rustc::mir::repr::*;
|
||||||
|
use rustc::mir::transform::MirPass;
|
||||||
|
|
||||||
|
pub struct ClearDeadBlocks;
|
||||||
|
|
||||||
|
impl ClearDeadBlocks {
|
||||||
|
pub fn new() -> ClearDeadBlocks {
|
||||||
|
ClearDeadBlocks
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_dead_blocks(&self, mir: &mut Mir) {
|
||||||
|
let mut seen = vec![false; mir.basic_blocks.len()];
|
||||||
|
|
||||||
|
// These blocks are always required.
|
||||||
|
seen[START_BLOCK.index()] = true;
|
||||||
|
seen[END_BLOCK.index()] = true;
|
||||||
|
|
||||||
|
let mut worklist = vec![START_BLOCK];
|
||||||
|
while let Some(bb) = worklist.pop() {
|
||||||
|
for succ in mir.basic_block_data(bb).terminator().successors().iter() {
|
||||||
|
if !seen[succ.index()] {
|
||||||
|
seen[succ.index()] = true;
|
||||||
|
worklist.push(*succ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n, (block, seen)) in mir.basic_blocks.iter_mut().zip(seen).enumerate() {
|
||||||
|
if !seen {
|
||||||
|
info!("clearing block #{}: {:?}", n, block);
|
||||||
|
*block = BasicBlockData {
|
||||||
|
statements: vec![],
|
||||||
|
terminator: Some(Terminator::Return),
|
||||||
|
is_cleanup: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MirPass for ClearDeadBlocks {
|
||||||
|
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &infer::InferCtxt<'a, 'tcx>)
|
||||||
|
{
|
||||||
|
self.clear_dead_blocks(mir);
|
||||||
|
}
|
||||||
|
}
|
@ -16,18 +16,13 @@ use rustc::middle::ty;
|
|||||||
use rustc::mir::repr::*;
|
use rustc::mir::repr::*;
|
||||||
use rustc::mir::visit::MutVisitor;
|
use rustc::mir::visit::MutVisitor;
|
||||||
use rustc::mir::mir_map::MirMap;
|
use rustc::mir::mir_map::MirMap;
|
||||||
use rustc::mir::transform::MirPass;
|
|
||||||
|
|
||||||
pub fn erase_regions<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &mut MirMap<'tcx>) {
|
pub fn erase_regions<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &mut MirMap<'tcx>) {
|
||||||
let mut eraser = EraseRegions;
|
|
||||||
|
|
||||||
for (_, mir) in &mut mir_map.map {
|
for (_, mir) in &mut mir_map.map {
|
||||||
eraser.run_on_mir(mir, tcx);
|
EraseRegionsVisitor::new(tcx).visit_mir(mir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EraseRegions;
|
|
||||||
|
|
||||||
struct EraseRegionsVisitor<'a, 'tcx: 'a> {
|
struct EraseRegionsVisitor<'a, 'tcx: 'a> {
|
||||||
tcx: &'a ty::ctxt<'tcx>,
|
tcx: &'a ty::ctxt<'tcx>,
|
||||||
}
|
}
|
||||||
@ -58,12 +53,6 @@ impl<'a, 'tcx> EraseRegionsVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MirPass for EraseRegions {
|
|
||||||
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ty::ctxt<'tcx>) {
|
|
||||||
EraseRegionsVisitor::new(tcx).visit_mir(mir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
|
||||||
fn visit_mir(&mut self, mir: &mut Mir<'tcx>) {
|
fn visit_mir(&mut self, mir: &mut Mir<'tcx>) {
|
||||||
self.erase_regions_return_ty(&mut mir.return_ty);
|
self.erase_regions_return_ty(&mut mir.return_ty);
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
pub mod clear_dead_blocks;
|
||||||
pub mod simplify_cfg;
|
pub mod simplify_cfg;
|
||||||
pub mod erase_regions;
|
pub mod erase_regions;
|
||||||
pub mod no_landing_pads;
|
pub mod no_landing_pads;
|
||||||
|
pub mod type_check;
|
||||||
mod util;
|
mod util;
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
//! This pass removes the unwind branch of all the terminators when the no-landing-pads option is
|
//! This pass removes the unwind branch of all the terminators when the no-landing-pads option is
|
||||||
//! specified.
|
//! specified.
|
||||||
|
|
||||||
use rustc::middle::ty;
|
use rustc::middle::infer;
|
||||||
use rustc::mir::repr::*;
|
use rustc::mir::repr::*;
|
||||||
use rustc::mir::visit::MutVisitor;
|
use rustc::mir::visit::MutVisitor;
|
||||||
use rustc::mir::transform::MirPass;
|
use rustc::mir::transform::MirPass;
|
||||||
@ -41,8 +41,9 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MirPass for NoLandingPads {
|
impl MirPass for NoLandingPads {
|
||||||
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ty::ctxt<'tcx>) {
|
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>,
|
||||||
if tcx.sess.no_landing_pads() {
|
infcx: &infer::InferCtxt<'a, 'tcx>) {
|
||||||
|
if infcx.tcx.sess.no_landing_pads() {
|
||||||
self.visit_mir(mir);
|
self.visit_mir(mir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use rustc::middle::const_eval::ConstVal;
|
use rustc::middle::const_eval::ConstVal;
|
||||||
|
use rustc::middle::infer;
|
||||||
use rustc::mir::repr::*;
|
use rustc::mir::repr::*;
|
||||||
use transform::util;
|
use transform::util;
|
||||||
use rustc::mir::transform::MirPass;
|
use rustc::mir::transform::MirPass;
|
||||||
@ -119,7 +120,7 @@ impl SimplifyCfg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MirPass for SimplifyCfg {
|
impl MirPass for SimplifyCfg {
|
||||||
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &::rustc::middle::ty::ctxt<'tcx>) {
|
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &infer::InferCtxt<'a, 'tcx>) {
|
||||||
let mut changed = true;
|
let mut changed = true;
|
||||||
while changed {
|
while changed {
|
||||||
changed = self.simplify_branches(mir);
|
changed = self.simplify_branches(mir);
|
||||||
|
598
src/librustc_mir/transform/type_check.rs
Normal file
598
src/librustc_mir/transform/type_check.rs
Normal file
@ -0,0 +1,598 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! This pass type-checks the MIR to ensure it is not broken.
|
||||||
|
#![allow(unreachable_code)]
|
||||||
|
|
||||||
|
use rustc::middle::infer::{self, InferCtxt};
|
||||||
|
use rustc::middle::traits;
|
||||||
|
use rustc::middle::ty::{self, Ty};
|
||||||
|
use rustc::middle::ty::fold::TypeFoldable;
|
||||||
|
use rustc::mir::repr::*;
|
||||||
|
use rustc::mir::tcx::LvalueTy;
|
||||||
|
use rustc::mir::transform::MirPass;
|
||||||
|
use rustc::mir::visit::{self, Visitor};
|
||||||
|
|
||||||
|
use syntax::codemap::{Span, DUMMY_SP};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
macro_rules! span_mirbug {
|
||||||
|
($context:expr, $elem:expr, $($message:tt)*) => ({
|
||||||
|
$context.tcx().sess.span_warn(
|
||||||
|
$context.last_span,
|
||||||
|
&format!("broken MIR ({:?}): {}", $elem, format!($($message)*))
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! span_mirbug_and_err {
|
||||||
|
($context:expr, $elem:expr, $($message:tt)*) => ({
|
||||||
|
{
|
||||||
|
$context.tcx().sess.span_warn(
|
||||||
|
$context.last_span,
|
||||||
|
&format!("broken MIR ({:?}): {:?}", $elem, format!($($message)*))
|
||||||
|
);
|
||||||
|
$context.error()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
enum FieldAccessError {
|
||||||
|
OutOfRange { field_count: usize }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies that MIR types are sane to not crash further checks.
|
||||||
|
///
|
||||||
|
/// The sanitize_XYZ methods here take an MIR object and compute its
|
||||||
|
/// type, calling `span_mirbug` and returning an error type if there
|
||||||
|
/// is a problem.
|
||||||
|
struct TypeVerifier<'a, 'b: 'a, 'tcx: 'b> {
|
||||||
|
cx: &'a mut TypeChecker<'b, 'tcx>,
|
||||||
|
mir: &'a Mir<'tcx>,
|
||||||
|
last_span: Span,
|
||||||
|
errors_reported: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||||
|
fn visit_span(&mut self, span: &Span) {
|
||||||
|
if *span != DUMMY_SP {
|
||||||
|
self.last_span = *span;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, _context: visit::LvalueContext) {
|
||||||
|
self.sanitize_lvalue(lvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_constant(&mut self, constant: &Constant<'tcx>) {
|
||||||
|
self.super_constant(constant);
|
||||||
|
self.sanitize_type(constant, constant.ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
|
||||||
|
self.super_rvalue(rvalue);
|
||||||
|
if let Some(ty) = self.mir.rvalue_ty(self.tcx(), rvalue) {
|
||||||
|
self.sanitize_type(rvalue, ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_mir(&mut self, mir: &Mir<'tcx>) {
|
||||||
|
if let ty::FnConverging(t) = mir.return_ty {
|
||||||
|
self.sanitize_type(&"return type", t);
|
||||||
|
}
|
||||||
|
for var_decl in &mir.var_decls {
|
||||||
|
self.sanitize_type(var_decl, var_decl.ty);
|
||||||
|
}
|
||||||
|
for (n, arg_decl) in mir.arg_decls.iter().enumerate() {
|
||||||
|
self.sanitize_type(&(n, arg_decl), arg_decl.ty);
|
||||||
|
}
|
||||||
|
for (n, tmp_decl) in mir.temp_decls.iter().enumerate() {
|
||||||
|
self.sanitize_type(&(n, tmp_decl), tmp_decl.ty);
|
||||||
|
}
|
||||||
|
if self.errors_reported {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.super_mir(mir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||||
|
fn new(cx: &'a mut TypeChecker<'b, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
|
||||||
|
TypeVerifier {
|
||||||
|
cx: cx,
|
||||||
|
mir: mir,
|
||||||
|
last_span: mir.span,
|
||||||
|
errors_reported: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tcx(&self) -> &'a ty::ctxt<'tcx> {
|
||||||
|
self.cx.infcx.tcx
|
||||||
|
}
|
||||||
|
|
||||||
|
fn infcx(&self) -> &'a InferCtxt<'a, 'tcx> {
|
||||||
|
self.cx.infcx
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sanitize_type(&mut self, parent: &fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
if ty.needs_infer() || ty.has_escaping_regions() || ty.references_error() {
|
||||||
|
span_mirbug_and_err!(self, parent, "bad type {:?}", ty)
|
||||||
|
} else {
|
||||||
|
ty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>) -> LvalueTy<'tcx> {
|
||||||
|
debug!("sanitize_lvalue: {:?}", lvalue);
|
||||||
|
match *lvalue {
|
||||||
|
Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index as usize].ty },
|
||||||
|
Lvalue::Temp(index) =>
|
||||||
|
LvalueTy::Ty { ty: self.mir.temp_decls[index as usize].ty },
|
||||||
|
Lvalue::Arg(index) =>
|
||||||
|
LvalueTy::Ty { ty: self.mir.arg_decls[index as usize].ty },
|
||||||
|
Lvalue::Static(def_id) =>
|
||||||
|
LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty },
|
||||||
|
Lvalue::ReturnPointer => {
|
||||||
|
if let ty::FnConverging(return_ty) = self.mir.return_ty {
|
||||||
|
LvalueTy::Ty { ty: return_ty }
|
||||||
|
} else {
|
||||||
|
LvalueTy::Ty {
|
||||||
|
ty: span_mirbug_and_err!(
|
||||||
|
self, lvalue, "return in diverging function")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Lvalue::Projection(ref proj) => {
|
||||||
|
let base_ty = self.sanitize_lvalue(&proj.base);
|
||||||
|
if let LvalueTy::Ty { ty } = base_ty {
|
||||||
|
if ty.references_error() {
|
||||||
|
assert!(self.errors_reported);
|
||||||
|
return LvalueTy::Ty { ty: self.tcx().types.err };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.sanitize_projection(base_ty, &proj.elem, lvalue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sanitize_projection(&mut self,
|
||||||
|
base: LvalueTy<'tcx>,
|
||||||
|
pi: &LvalueElem<'tcx>,
|
||||||
|
lvalue: &Lvalue<'tcx>)
|
||||||
|
-> LvalueTy<'tcx> {
|
||||||
|
debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, lvalue);
|
||||||
|
let tcx = self.tcx();
|
||||||
|
let base_ty = base.to_ty(tcx);
|
||||||
|
let span = self.last_span;
|
||||||
|
match *pi {
|
||||||
|
ProjectionElem::Deref => {
|
||||||
|
let deref_ty = base_ty.builtin_deref(true, ty::LvaluePreference::NoPreference);
|
||||||
|
LvalueTy::Ty {
|
||||||
|
ty: deref_ty.map(|t| t.ty).unwrap_or_else(|| {
|
||||||
|
span_mirbug_and_err!(
|
||||||
|
self, lvalue, "deref of non-pointer {:?}", base_ty)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ProjectionElem::Index(ref i) => {
|
||||||
|
self.visit_operand(i);
|
||||||
|
let index_ty = self.mir.operand_ty(tcx, i);
|
||||||
|
if index_ty != tcx.types.usize {
|
||||||
|
LvalueTy::Ty {
|
||||||
|
ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LvalueTy::Ty {
|
||||||
|
ty: base_ty.builtin_index().unwrap_or_else(|| {
|
||||||
|
span_mirbug_and_err!(
|
||||||
|
self, lvalue, "index of non-array {:?}", base_ty)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ProjectionElem::ConstantIndex { .. } => {
|
||||||
|
// consider verifying in-bounds
|
||||||
|
LvalueTy::Ty {
|
||||||
|
ty: base_ty.builtin_index().unwrap_or_else(|| {
|
||||||
|
span_mirbug_and_err!(
|
||||||
|
self, lvalue, "index of non-array {:?}", base_ty)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ProjectionElem::Downcast(adt_def1, index) =>
|
||||||
|
match base_ty.sty {
|
||||||
|
ty::TyEnum(adt_def, substs) if adt_def == adt_def1 => {
|
||||||
|
if index >= adt_def.variants.len() {
|
||||||
|
LvalueTy::Ty {
|
||||||
|
ty: span_mirbug_and_err!(
|
||||||
|
self,
|
||||||
|
lvalue,
|
||||||
|
"cast to variant #{:?} but enum only has {:?}",
|
||||||
|
index,
|
||||||
|
adt_def.variants.len())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LvalueTy::Downcast {
|
||||||
|
adt_def: adt_def,
|
||||||
|
substs: substs,
|
||||||
|
variant_index: index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => LvalueTy::Ty {
|
||||||
|
ty: span_mirbug_and_err!(
|
||||||
|
self, lvalue, "can't downcast {:?} as {:?}",
|
||||||
|
base_ty, adt_def1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ProjectionElem::Field(field, fty) => {
|
||||||
|
let fty = self.sanitize_type(lvalue, fty);
|
||||||
|
match self.field_ty(lvalue, base, field) {
|
||||||
|
Ok(ty) => {
|
||||||
|
if let Err(terr) = self.cx.mk_eqty(span, ty, fty) {
|
||||||
|
span_mirbug!(
|
||||||
|
self, lvalue, "bad field access ({:?}: {:?}): {:?}",
|
||||||
|
ty, fty, terr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(FieldAccessError::OutOfRange { field_count }) => {
|
||||||
|
span_mirbug!(
|
||||||
|
self, lvalue, "accessed field #{} but variant only has {}",
|
||||||
|
field.index(), field_count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LvalueTy::Ty { ty: fty }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error(&mut self) -> Ty<'tcx> {
|
||||||
|
self.errors_reported = true;
|
||||||
|
self.tcx().types.err
|
||||||
|
}
|
||||||
|
|
||||||
|
fn field_ty(&mut self,
|
||||||
|
parent: &fmt::Debug,
|
||||||
|
base_ty: LvalueTy<'tcx>,
|
||||||
|
field: Field)
|
||||||
|
-> Result<Ty<'tcx>, FieldAccessError>
|
||||||
|
{
|
||||||
|
let tcx = self.tcx();
|
||||||
|
|
||||||
|
let (variant, substs) = match base_ty {
|
||||||
|
LvalueTy::Downcast { adt_def, substs, variant_index } => {
|
||||||
|
(&adt_def.variants[variant_index], substs)
|
||||||
|
}
|
||||||
|
LvalueTy::Ty { ty } => match ty.sty {
|
||||||
|
ty::TyStruct(adt_def, substs) | ty::TyEnum(adt_def, substs)
|
||||||
|
if adt_def.is_univariant() => {
|
||||||
|
(&adt_def.variants[0], substs)
|
||||||
|
}
|
||||||
|
ty::TyTuple(ref tys) | ty::TyClosure(_, box ty::ClosureSubsts {
|
||||||
|
upvar_tys: ref tys, ..
|
||||||
|
}) => {
|
||||||
|
return match tys.get(field.index()) {
|
||||||
|
Some(&ty) => Ok(ty),
|
||||||
|
None => Err(FieldAccessError::OutOfRange {
|
||||||
|
field_count: tys.len()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return Ok(span_mirbug_and_err!(
|
||||||
|
self, parent, "can't project out of {:?}", base_ty))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(field) = variant.fields.get(field.index()) {
|
||||||
|
Ok(self.normalize(field.ty(tcx, substs)))
|
||||||
|
} else {
|
||||||
|
Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
let infcx = self.infcx();
|
||||||
|
let mut selcx = traits::SelectionContext::new(infcx);
|
||||||
|
let cause = traits::ObligationCause::misc(self.last_span, 0);
|
||||||
|
let traits::Normalized { value: ty, obligations } =
|
||||||
|
traits::normalize(&mut selcx, cause, &ty);
|
||||||
|
|
||||||
|
debug!("normalize: ty={:?} obligations={:?}",
|
||||||
|
ty,
|
||||||
|
obligations);
|
||||||
|
|
||||||
|
let mut fulfill_cx = &mut self.cx.fulfillment_cx;
|
||||||
|
for obligation in obligations {
|
||||||
|
fulfill_cx.register_predicate_obligation(infcx, obligation);
|
||||||
|
}
|
||||||
|
|
||||||
|
ty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TypeChecker<'a, 'tcx: 'a> {
|
||||||
|
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||||
|
fulfillment_cx: traits::FulfillmentContext<'tcx>,
|
||||||
|
last_span: Span
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
|
fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
|
||||||
|
TypeChecker {
|
||||||
|
infcx: infcx,
|
||||||
|
fulfillment_cx: traits::FulfillmentContext::new(),
|
||||||
|
last_span: DUMMY_SP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mk_subty(&self, span: Span, sup: Ty<'tcx>, sub: Ty<'tcx>)
|
||||||
|
-> infer::UnitResult<'tcx>
|
||||||
|
{
|
||||||
|
infer::mk_subty(self.infcx, false, infer::TypeOrigin::Misc(span),
|
||||||
|
sup, sub)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mk_eqty(&self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>)
|
||||||
|
-> infer::UnitResult<'tcx>
|
||||||
|
{
|
||||||
|
infer::mk_eqty(self.infcx, false, infer::TypeOrigin::Misc(span),
|
||||||
|
a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tcx(&self) -> &'a ty::ctxt<'tcx> {
|
||||||
|
self.infcx.tcx
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>) {
|
||||||
|
debug!("check_stmt: {:?}", stmt);
|
||||||
|
let tcx = self.tcx();
|
||||||
|
match stmt.kind {
|
||||||
|
StatementKind::Assign(ref lv, ref rv) => {
|
||||||
|
let lv_ty = mir.lvalue_ty(tcx, lv).to_ty(tcx);
|
||||||
|
let rv_ty = mir.rvalue_ty(tcx, rv);
|
||||||
|
if let Some(rv_ty) = rv_ty {
|
||||||
|
if let Err(terr) = self.mk_subty(self.last_span, rv_ty, lv_ty) {
|
||||||
|
span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
|
||||||
|
lv_ty, rv_ty, terr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: rvalue with undeterminable type - e.g. inline
|
||||||
|
// asm.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_terminator(&self,
|
||||||
|
mir: &Mir<'tcx>,
|
||||||
|
term: &Terminator<'tcx>) {
|
||||||
|
debug!("check_terminator: {:?}", term);
|
||||||
|
let tcx = self.tcx();
|
||||||
|
match *term {
|
||||||
|
Terminator::Goto { .. } |
|
||||||
|
Terminator::Resume |
|
||||||
|
Terminator::Return |
|
||||||
|
Terminator::Drop { .. } => {
|
||||||
|
// no checks needed for these
|
||||||
|
}
|
||||||
|
|
||||||
|
Terminator::If { ref cond, .. } => {
|
||||||
|
let cond_ty = mir.operand_ty(tcx, cond);
|
||||||
|
match cond_ty.sty {
|
||||||
|
ty::TyBool => {}
|
||||||
|
_ => {
|
||||||
|
span_mirbug!(self, term, "bad If ({:?}, not bool", cond_ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Terminator::SwitchInt { ref discr, switch_ty, .. } => {
|
||||||
|
let discr_ty = mir.lvalue_ty(tcx, discr).to_ty(tcx);
|
||||||
|
if let Err(terr) = self.mk_subty(self.last_span, discr_ty, switch_ty) {
|
||||||
|
span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}",
|
||||||
|
switch_ty, discr_ty, terr);
|
||||||
|
}
|
||||||
|
if !switch_ty.is_integral() && !switch_ty.is_char() &&
|
||||||
|
!switch_ty.is_bool()
|
||||||
|
{
|
||||||
|
span_mirbug!(self, term, "bad SwitchInt discr ty {:?}",switch_ty);
|
||||||
|
}
|
||||||
|
// FIXME: check the values
|
||||||
|
}
|
||||||
|
Terminator::Switch { ref discr, adt_def, ref targets } => {
|
||||||
|
let discr_ty = mir.lvalue_ty(tcx, discr).to_ty(tcx);
|
||||||
|
match discr_ty.sty {
|
||||||
|
ty::TyEnum(def, _)
|
||||||
|
if def == adt_def && adt_def.variants.len() == targets.len()
|
||||||
|
=> {},
|
||||||
|
_ => {
|
||||||
|
span_mirbug!(self, term, "bad Switch ({:?} on {:?})",
|
||||||
|
adt_def, discr_ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Terminator::Call { ref func, ref args, ref destination, .. } => {
|
||||||
|
let func_ty = mir.operand_ty(tcx, func);
|
||||||
|
debug!("check_terminator: call, func_ty={:?}", func_ty);
|
||||||
|
let func_ty = match func_ty.sty {
|
||||||
|
ty::TyBareFn(_, func_ty) => func_ty,
|
||||||
|
_ => {
|
||||||
|
span_mirbug!(self, term, "call to non-function {:?}", func_ty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let sig = tcx.erase_late_bound_regions(&func_ty.sig);
|
||||||
|
self.check_call_dest(mir, term, &sig, destination);
|
||||||
|
|
||||||
|
if self.is_box_free(func) {
|
||||||
|
self.check_box_free_inputs(mir, term, &sig, args);
|
||||||
|
} else {
|
||||||
|
self.check_call_inputs(mir, term, &sig, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_call_dest(&self,
|
||||||
|
mir: &Mir<'tcx>,
|
||||||
|
term: &Terminator<'tcx>,
|
||||||
|
sig: &ty::FnSig<'tcx>,
|
||||||
|
destination: &Option<(Lvalue<'tcx>, BasicBlock)>) {
|
||||||
|
let tcx = self.tcx();
|
||||||
|
match (destination, sig.output) {
|
||||||
|
(&Some(..), ty::FnDiverging) => {
|
||||||
|
span_mirbug!(self, term, "call to diverging function {:?} with dest", sig);
|
||||||
|
}
|
||||||
|
(&Some((ref dest, _)), ty::FnConverging(ty)) => {
|
||||||
|
let dest_ty = mir.lvalue_ty(tcx, dest).to_ty(tcx);
|
||||||
|
if let Err(terr) = self.mk_subty(self.last_span, ty, dest_ty) {
|
||||||
|
span_mirbug!(self, term,
|
||||||
|
"call dest mismatch ({:?} <- {:?}): {:?}",
|
||||||
|
dest_ty, ty, terr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(&None, ty::FnDiverging) => {}
|
||||||
|
(&None, ty::FnConverging(..)) => {
|
||||||
|
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_call_inputs(&self,
|
||||||
|
mir: &Mir<'tcx>,
|
||||||
|
term: &Terminator<'tcx>,
|
||||||
|
sig: &ty::FnSig<'tcx>,
|
||||||
|
args: &[Operand<'tcx>])
|
||||||
|
{
|
||||||
|
debug!("check_call_inputs({:?}, {:?})", sig, args);
|
||||||
|
if args.len() < sig.inputs.len() ||
|
||||||
|
(args.len() > sig.inputs.len() && !sig.variadic) {
|
||||||
|
span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
|
||||||
|
}
|
||||||
|
for (n, (fn_arg, op_arg)) in sig.inputs.iter().zip(args).enumerate() {
|
||||||
|
let op_arg_ty = mir.operand_ty(self.tcx(), op_arg);
|
||||||
|
if let Err(terr) = self.mk_subty(self.last_span, op_arg_ty, fn_arg) {
|
||||||
|
span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}",
|
||||||
|
n, fn_arg, op_arg_ty, terr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_box_free(&self, operand: &Operand<'tcx>) -> bool {
|
||||||
|
match operand {
|
||||||
|
&Operand::Constant(Constant {
|
||||||
|
literal: Literal::Item { def_id, .. }, ..
|
||||||
|
}) => {
|
||||||
|
Some(def_id) == self.tcx().lang_items.box_free_fn()
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_box_free_inputs(&self,
|
||||||
|
mir: &Mir<'tcx>,
|
||||||
|
term: &Terminator<'tcx>,
|
||||||
|
sig: &ty::FnSig<'tcx>,
|
||||||
|
args: &[Operand<'tcx>])
|
||||||
|
{
|
||||||
|
debug!("check_box_free_inputs");
|
||||||
|
|
||||||
|
// box_free takes a Box as a pointer. Allow for that.
|
||||||
|
|
||||||
|
if sig.inputs.len() != 1 {
|
||||||
|
span_mirbug!(self, term, "box_free should take 1 argument");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pointee_ty = match sig.inputs[0].sty {
|
||||||
|
ty::TyRawPtr(mt) => mt.ty,
|
||||||
|
_ => {
|
||||||
|
span_mirbug!(self, term, "box_free should take a raw ptr");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if args.len() != 1 {
|
||||||
|
span_mirbug!(self, term, "box_free called with wrong # of args");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let arg_ty = match mir.operand_ty(self.tcx(), &args[0]).sty {
|
||||||
|
ty::TyRawPtr(mt) => mt.ty,
|
||||||
|
ty::TyBox(ty) => ty,
|
||||||
|
_ => {
|
||||||
|
span_mirbug!(self, term, "box_free called with bad arg ty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(terr) = self.mk_subty(self.last_span, arg_ty, pointee_ty) {
|
||||||
|
span_mirbug!(self, term, "bad box_free arg ({:?} <- {:?}): {:?}",
|
||||||
|
pointee_ty, arg_ty, terr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
|
||||||
|
self.last_span = mir.span;
|
||||||
|
debug!("run_on_mir: {:?}", mir.span);
|
||||||
|
for block in &mir.basic_blocks {
|
||||||
|
for stmt in &block.statements {
|
||||||
|
if stmt.span != DUMMY_SP {
|
||||||
|
self.last_span = stmt.span;
|
||||||
|
}
|
||||||
|
self.check_stmt(mir, stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref terminator) = block.terminator {
|
||||||
|
self.check_terminator(mir, terminator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_obligations(&mut self, mir: &Mir<'tcx>) {
|
||||||
|
self.last_span = mir.span;
|
||||||
|
if let Err(e) = self.fulfillment_cx.select_all_or_error(self.infcx) {
|
||||||
|
span_mirbug!(self, "", "errors selecting obligation: {:?}",
|
||||||
|
e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TypeckMir;
|
||||||
|
|
||||||
|
impl TypeckMir {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
TypeckMir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MirPass for TypeckMir {
|
||||||
|
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, infcx: &InferCtxt<'a, 'tcx>)
|
||||||
|
{
|
||||||
|
if infcx.tcx.sess.err_count() > 0 {
|
||||||
|
// compiling a broken program can obviously result in a
|
||||||
|
// broken MIR, so try not to report duplicate errors.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut checker = TypeChecker::new(infcx);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut verifier = TypeVerifier::new(&mut checker, mir);
|
||||||
|
verifier.visit_mir(mir);
|
||||||
|
if verifier.errors_reported {
|
||||||
|
// don't do further checks to avoid ICEs
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checker.typeck_mir(mir);
|
||||||
|
checker.verify_obligations(mir);
|
||||||
|
}
|
||||||
|
}
|
@ -768,7 +768,8 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp
|
|||||||
match v.tcx.tables.borrow().adjustments.get(&e.id) {
|
match v.tcx.tables.borrow().adjustments.get(&e.id) {
|
||||||
None |
|
None |
|
||||||
Some(&ty::adjustment::AdjustReifyFnPointer) |
|
Some(&ty::adjustment::AdjustReifyFnPointer) |
|
||||||
Some(&ty::adjustment::AdjustUnsafeFnPointer) => {}
|
Some(&ty::adjustment::AdjustUnsafeFnPointer) |
|
||||||
|
Some(&ty::adjustment::AdjustMutToConstPointer) => {}
|
||||||
|
|
||||||
Some(&ty::adjustment::AdjustDerefRef(
|
Some(&ty::adjustment::AdjustDerefRef(
|
||||||
ty::adjustment::AutoDerefRef { autoderefs, .. }
|
ty::adjustment::AutoDerefRef { autoderefs, .. }
|
||||||
|
@ -40,7 +40,7 @@ use trans::type_of;
|
|||||||
use trans::Disr;
|
use trans::Disr;
|
||||||
use middle::subst::Substs;
|
use middle::subst::Substs;
|
||||||
use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
|
use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
|
||||||
use middle::ty::adjustment::AdjustUnsafeFnPointer;
|
use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
|
||||||
use middle::ty::{self, Ty};
|
use middle::ty::{self, Ty};
|
||||||
use middle::ty::cast::{CastTy,IntTy};
|
use middle::ty::cast::{CastTy,IntTy};
|
||||||
use util::nodemap::NodeMap;
|
use util::nodemap::NodeMap;
|
||||||
@ -354,7 +354,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||||||
// FIXME(#19925) once fn item types are
|
// FIXME(#19925) once fn item types are
|
||||||
// zero-sized, we'll need to do something here
|
// zero-sized, we'll need to do something here
|
||||||
}
|
}
|
||||||
Some(AdjustUnsafeFnPointer) => {
|
Some(AdjustUnsafeFnPointer) | Some(AdjustMutToConstPointer) => {
|
||||||
// purely a type-level thing
|
// purely a type-level thing
|
||||||
}
|
}
|
||||||
Some(AdjustDerefRef(adj)) => {
|
Some(AdjustDerefRef(adj)) => {
|
||||||
|
@ -71,7 +71,8 @@ use trans::tvec;
|
|||||||
use trans::type_of;
|
use trans::type_of;
|
||||||
use trans::Disr;
|
use trans::Disr;
|
||||||
use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
|
use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
|
||||||
use middle::ty::adjustment::{AdjustUnsafeFnPointer, CustomCoerceUnsized};
|
use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
|
||||||
|
use middle::ty::adjustment::CustomCoerceUnsized;
|
||||||
use middle::ty::{self, Ty};
|
use middle::ty::{self, Ty};
|
||||||
use middle::ty::MethodCall;
|
use middle::ty::MethodCall;
|
||||||
use middle::ty::cast::{CastKind, CastTy};
|
use middle::ty::cast::{CastKind, CastTy};
|
||||||
@ -354,7 +355,7 @@ fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||||||
// zero-sized, we'll need to return true here
|
// zero-sized, we'll need to return true here
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
AdjustUnsafeFnPointer => {
|
AdjustUnsafeFnPointer | AdjustMutToConstPointer => {
|
||||||
// purely a type-level thing
|
// purely a type-level thing
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -391,7 +392,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||||||
// FIXME(#19925) once fn item types are
|
// FIXME(#19925) once fn item types are
|
||||||
// zero-sized, we'll need to do something here
|
// zero-sized, we'll need to do something here
|
||||||
}
|
}
|
||||||
AdjustUnsafeFnPointer => {
|
AdjustUnsafeFnPointer | AdjustMutToConstPointer => {
|
||||||
// purely a type-level thing
|
// purely a type-level thing
|
||||||
}
|
}
|
||||||
AdjustDerefRef(ref adj) => {
|
AdjustDerefRef(ref adj) => {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use llvm::{BasicBlockRef, ValueRef, OperandBundleDef};
|
use llvm::{BasicBlockRef, ValueRef, OperandBundleDef};
|
||||||
use rustc::middle::ty;
|
use rustc::middle::ty::{self, Ty};
|
||||||
use rustc::mir::repr as mir;
|
use rustc::mir::repr as mir;
|
||||||
use syntax::abi::Abi;
|
use syntax::abi::Abi;
|
||||||
use trans::adt;
|
use trans::adt;
|
||||||
@ -26,8 +26,55 @@ use trans::type_::Type;
|
|||||||
|
|
||||||
use super::MirContext;
|
use super::MirContext;
|
||||||
use super::operand::OperandValue::{FatPtr, Immediate, Ref};
|
use super::operand::OperandValue::{FatPtr, Immediate, Ref};
|
||||||
|
use super::operand::OperandRef;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
enum AbiStyle {
|
||||||
|
Foreign,
|
||||||
|
RustCall,
|
||||||
|
Rust
|
||||||
|
}
|
||||||
|
|
||||||
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||||
|
fn abi_style(&self, fn_ty: Ty<'tcx>) -> AbiStyle {
|
||||||
|
if let ty::TyBareFn(_, ref f) = fn_ty.sty {
|
||||||
|
// We do not translate intrinsics here (they shouldn’t be functions)
|
||||||
|
assert!(f.abi != Abi::RustIntrinsic && f.abi != Abi::PlatformIntrinsic);
|
||||||
|
|
||||||
|
match f.abi {
|
||||||
|
Abi::Rust => AbiStyle::Rust,
|
||||||
|
Abi::RustCall => AbiStyle::RustCall,
|
||||||
|
_ => AbiStyle::Foreign
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arg_operands(&mut self,
|
||||||
|
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
||||||
|
abi_style: AbiStyle,
|
||||||
|
args: &[mir::Operand<'tcx>])
|
||||||
|
-> Vec<OperandRef<'tcx>>
|
||||||
|
{
|
||||||
|
match abi_style {
|
||||||
|
AbiStyle::Foreign | AbiStyle::Rust => {
|
||||||
|
args.iter().map(|arg| self.trans_operand(bcx, arg)).collect()
|
||||||
|
}
|
||||||
|
AbiStyle::RustCall => match args.split_last() {
|
||||||
|
None => vec![],
|
||||||
|
Some((tup, self_ty)) => {
|
||||||
|
// we can reorder safely because of MIR
|
||||||
|
let untupled_args = self.trans_operand_untupled(bcx, tup);
|
||||||
|
self_ty
|
||||||
|
.iter().map(|arg| self.trans_operand(bcx, arg))
|
||||||
|
.chain(untupled_args.into_iter())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn trans_block(&mut self, bb: mir::BasicBlock) {
|
pub fn trans_block(&mut self, bb: mir::BasicBlock) {
|
||||||
debug!("trans_block({:?})", bb);
|
debug!("trans_block({:?})", bb);
|
||||||
|
|
||||||
@ -159,13 +206,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
let mut arg_tys = Vec::new();
|
let mut arg_tys = Vec::new();
|
||||||
|
|
||||||
// Foreign-ABI functions are translated differently
|
// Foreign-ABI functions are translated differently
|
||||||
let is_foreign = if let ty::TyBareFn(_, ref f) = callee.ty.sty {
|
let abi_style = self.abi_style(callee.ty);
|
||||||
// We do not translate intrinsics here (they shouldn’t be functions)
|
let is_foreign = abi_style == AbiStyle::Foreign;
|
||||||
assert!(f.abi != Abi::RustIntrinsic && f.abi != Abi::PlatformIntrinsic);
|
|
||||||
f.abi != Abi::Rust && f.abi != Abi::RustCall
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
// Prepare the return value destination
|
// Prepare the return value destination
|
||||||
let (ret_dest_ty, must_copy_dest) = if let Some((ref d, _)) = *destination {
|
let (ret_dest_ty, must_copy_dest) = if let Some((ref d, _)) = *destination {
|
||||||
@ -182,8 +224,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Process the rest of the args.
|
// Process the rest of the args.
|
||||||
for arg in args {
|
for operand in self.arg_operands(&bcx, abi_style, args) {
|
||||||
let operand = self.trans_operand(&bcx, arg);
|
|
||||||
match operand.val {
|
match operand.val {
|
||||||
Ref(llval) | Immediate(llval) => llargs.push(llval),
|
Ref(llval) | Immediate(llval) => llargs.push(llval),
|
||||||
FatPtr(b, e) => {
|
FatPtr(b, e) => {
|
||||||
|
@ -126,7 +126,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
mir::ProjectionElem::Field(ref field) => {
|
mir::ProjectionElem::Field(ref field, _) => {
|
||||||
let base_ty = tr_base.ty.to_ty(tcx);
|
let base_ty = tr_base.ty.to_ty(tcx);
|
||||||
let base_repr = adt::represent_type(ccx, base_ty);
|
let base_repr = adt::represent_type(ccx, base_ty);
|
||||||
let discr = match tr_base.ty {
|
let discr = match tr_base.ty {
|
||||||
|
@ -9,13 +9,16 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use llvm::ValueRef;
|
use llvm::ValueRef;
|
||||||
use rustc::middle::ty::{Ty, TypeFoldable};
|
use rustc::middle::ty::{self, Ty};
|
||||||
use rustc::mir::repr as mir;
|
use rustc::mir::repr as mir;
|
||||||
|
use trans::adt;
|
||||||
use trans::base;
|
use trans::base;
|
||||||
use trans::common::{self, Block, BlockAndBuilder};
|
use trans::common::{self, Block, BlockAndBuilder};
|
||||||
use trans::datum;
|
use trans::datum;
|
||||||
|
use trans::Disr;
|
||||||
|
|
||||||
use super::{MirContext, TempRef};
|
use super::{MirContext, TempRef};
|
||||||
|
use super::lvalue::LvalueRef;
|
||||||
|
|
||||||
/// The representation of a Rust value. The enum variant is in fact
|
/// The representation of a Rust value. The enum variant is in fact
|
||||||
/// uniquely determined by the value's type, but is kept as a
|
/// uniquely determined by the value's type, but is kept as a
|
||||||
@ -90,6 +93,32 @@ impl<'tcx> OperandRef<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||||
|
pub fn trans_load(&mut self,
|
||||||
|
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
||||||
|
llval: ValueRef,
|
||||||
|
ty: Ty<'tcx>)
|
||||||
|
-> OperandRef<'tcx>
|
||||||
|
{
|
||||||
|
debug!("trans_load: {} @ {:?}", bcx.val_to_string(llval), ty);
|
||||||
|
|
||||||
|
let val = match datum::appropriate_rvalue_mode(bcx.ccx(), ty) {
|
||||||
|
datum::ByValue => {
|
||||||
|
bcx.with_block(|bcx| {
|
||||||
|
OperandValue::Immediate(base::load_ty(bcx, llval, ty))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
datum::ByRef if common::type_is_fat_ptr(bcx.tcx(), ty) => {
|
||||||
|
let (lldata, llextra) = bcx.with_block(|bcx| {
|
||||||
|
base::load_fat_ptr(bcx, llval, ty)
|
||||||
|
});
|
||||||
|
OperandValue::FatPtr(lldata, llextra)
|
||||||
|
}
|
||||||
|
datum::ByRef => OperandValue::Ref(llval)
|
||||||
|
};
|
||||||
|
|
||||||
|
OperandRef { val: val, ty: ty }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn trans_operand(&mut self,
|
pub fn trans_operand(&mut self,
|
||||||
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
||||||
operand: &mir::Operand<'tcx>)
|
operand: &mir::Operand<'tcx>)
|
||||||
@ -120,30 +149,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
// out from their home
|
// out from their home
|
||||||
let tr_lvalue = self.trans_lvalue(bcx, lvalue);
|
let tr_lvalue = self.trans_lvalue(bcx, lvalue);
|
||||||
let ty = tr_lvalue.ty.to_ty(bcx.tcx());
|
let ty = tr_lvalue.ty.to_ty(bcx.tcx());
|
||||||
debug!("trans_operand: tr_lvalue={} @ {:?}",
|
self.trans_load(bcx, tr_lvalue.llval, ty)
|
||||||
bcx.val_to_string(tr_lvalue.llval),
|
|
||||||
ty);
|
|
||||||
let val = match datum::appropriate_rvalue_mode(bcx.ccx(), ty) {
|
|
||||||
datum::ByValue => {
|
|
||||||
bcx.with_block(|bcx| {
|
|
||||||
OperandValue::Immediate(base::load_ty(bcx, tr_lvalue.llval, ty))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
datum::ByRef if common::type_is_fat_ptr(bcx.tcx(), ty) => {
|
|
||||||
let (lldata, llextra) = bcx.with_block(|bcx| {
|
|
||||||
base::load_fat_ptr(bcx, tr_lvalue.llval, ty)
|
|
||||||
});
|
|
||||||
OperandValue::FatPtr(lldata, llextra)
|
|
||||||
}
|
|
||||||
datum::ByRef => OperandValue::Ref(tr_lvalue.llval)
|
|
||||||
};
|
|
||||||
|
|
||||||
assert!(!ty.has_erasable_regions());
|
|
||||||
|
|
||||||
OperandRef {
|
|
||||||
val: val,
|
|
||||||
ty: ty
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mir::Operand::Constant(ref constant) => {
|
mir::Operand::Constant(ref constant) => {
|
||||||
@ -197,4 +203,46 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn trans_operand_untupled(&mut self,
|
||||||
|
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
||||||
|
operand: &mir::Operand<'tcx>)
|
||||||
|
-> Vec<OperandRef<'tcx>>
|
||||||
|
{
|
||||||
|
// FIXME: consider having some optimization to avoid tupling/untupling
|
||||||
|
// (and storing/loading in the case of immediates)
|
||||||
|
|
||||||
|
// avoid trans_operand for pointless copying
|
||||||
|
let lv = match *operand {
|
||||||
|
mir::Operand::Consume(ref lvalue) => self.trans_lvalue(bcx, lvalue),
|
||||||
|
mir::Operand::Constant(ref constant) => {
|
||||||
|
// FIXME: consider being less pessimized
|
||||||
|
if constant.ty.is_nil() {
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
|
||||||
|
let ty = bcx.monomorphize(&constant.ty);
|
||||||
|
let lv = LvalueRef::alloca(bcx, ty, "__untuple_alloca");
|
||||||
|
let constant = self.trans_constant(bcx, constant);
|
||||||
|
self.store_operand(bcx, lv.llval, constant);
|
||||||
|
lv
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let lv_ty = lv.ty.to_ty(bcx.tcx());
|
||||||
|
let result_types = match lv_ty.sty {
|
||||||
|
ty::TyTuple(ref tys) => tys,
|
||||||
|
_ => bcx.tcx().sess.span_bug(
|
||||||
|
self.mir.span,
|
||||||
|
&format!("bad final argument to \"rust-call\" fn {:?}", lv_ty))
|
||||||
|
};
|
||||||
|
|
||||||
|
let base_repr = adt::represent_type(bcx.ccx(), lv_ty);
|
||||||
|
let base = adt::MaybeSizedValue::sized(lv.llval);
|
||||||
|
result_types.iter().enumerate().map(|(n, &ty)| {
|
||||||
|
self.trans_load(bcx, bcx.with_block(|bcx| {
|
||||||
|
adt::trans_field_ptr(bcx, &base_repr, base, Disr(0), n)
|
||||||
|
}), ty)
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ use middle::traits::{self, ObligationCause};
|
|||||||
use middle::traits::{predicate_for_trait_def, report_selection_error};
|
use middle::traits::{predicate_for_trait_def, report_selection_error};
|
||||||
use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
|
use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
|
||||||
use middle::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer};
|
use middle::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer};
|
||||||
use middle::ty::adjustment::{AdjustUnsafeFnPointer};
|
use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
|
||||||
use middle::ty::{self, LvaluePreference, TypeAndMut, Ty};
|
use middle::ty::{self, LvaluePreference, TypeAndMut, Ty};
|
||||||
use middle::ty::fold::TypeFoldable;
|
use middle::ty::fold::TypeFoldable;
|
||||||
use middle::ty::error::TypeError;
|
use middle::ty::error::TypeError;
|
||||||
@ -427,6 +427,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||||||
autoref: Some(AutoUnsafe(mutbl_b)),
|
autoref: Some(AutoUnsafe(mutbl_b)),
|
||||||
unsize: None
|
unsize: None
|
||||||
})))
|
})))
|
||||||
|
} else if mt_a.mutbl != mutbl_b {
|
||||||
|
Ok(Some(AdjustMutToConstPointer))
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -3179,8 +3179,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
|||||||
check_struct_fields_on_error(fcx, expr.id, fields, base_expr);
|
check_struct_fields_on_error(fcx, expr.id, fields, base_expr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let (adt, variant) = match fcx.def_struct_variant(def, path.span) {
|
let variant = match fcx.def_struct_variant(def, path.span) {
|
||||||
Some((adt, variant)) => (adt, variant),
|
Some((_, variant)) => variant,
|
||||||
None => {
|
None => {
|
||||||
span_err!(fcx.tcx().sess, path.span, E0071,
|
span_err!(fcx.tcx().sess, path.span, E0071,
|
||||||
"`{}` does not name a structure",
|
"`{}` does not name a structure",
|
||||||
@ -3195,15 +3195,26 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
|||||||
|
|
||||||
check_expr_struct_fields(fcx, expr_ty, expr.span, variant, fields,
|
check_expr_struct_fields(fcx, expr_ty, expr.span, variant, fields,
|
||||||
base_expr.is_none());
|
base_expr.is_none());
|
||||||
|
|
||||||
if let &Some(ref base_expr) = base_expr {
|
if let &Some(ref base_expr) = base_expr {
|
||||||
check_expr_has_type(fcx, base_expr, expr_ty);
|
check_expr_has_type(fcx, base_expr, expr_ty);
|
||||||
if adt.adt_kind() == ty::AdtKind::Enum {
|
match expr_ty.sty {
|
||||||
|
ty::TyStruct(adt, substs) => {
|
||||||
|
fcx.inh.tables.borrow_mut().fru_field_types.insert(
|
||||||
|
expr.id,
|
||||||
|
adt.struct_variant().fields.iter().map(|f| {
|
||||||
|
fcx.normalize_associated_types_in(
|
||||||
|
expr.span, &f.ty(tcx, substs)
|
||||||
|
)
|
||||||
|
}).collect()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
span_err!(tcx.sess, base_expr.span, E0436,
|
span_err!(tcx.sess, base_expr.span, E0436,
|
||||||
"functional record update syntax requires a struct");
|
"functional record update syntax requires a struct");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ExprCheckerWithTy = fn(&FnCtxt, &hir::Expr, Ty);
|
type ExprCheckerWithTy = fn(&FnCtxt, &hir::Expr, Ty);
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &hir::Expr) {
|
|||||||
wbcx.visit_upvar_borrow_map();
|
wbcx.visit_upvar_borrow_map();
|
||||||
wbcx.visit_closures();
|
wbcx.visit_closures();
|
||||||
wbcx.visit_liberated_fn_sigs();
|
wbcx.visit_liberated_fn_sigs();
|
||||||
|
wbcx.visit_fru_field_types();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
|
pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
|
||||||
@ -64,6 +65,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
|
|||||||
wbcx.visit_upvar_borrow_map();
|
wbcx.visit_upvar_borrow_map();
|
||||||
wbcx.visit_closures();
|
wbcx.visit_closures();
|
||||||
wbcx.visit_liberated_fn_sigs();
|
wbcx.visit_liberated_fn_sigs();
|
||||||
|
wbcx.visit_fru_field_types();
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
@ -305,6 +307,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||||||
adjustment::AdjustReifyFnPointer
|
adjustment::AdjustReifyFnPointer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adjustment::AdjustMutToConstPointer => {
|
||||||
|
adjustment::AdjustMutToConstPointer
|
||||||
|
}
|
||||||
|
|
||||||
adjustment::AdjustUnsafeFnPointer => {
|
adjustment::AdjustUnsafeFnPointer => {
|
||||||
adjustment::AdjustUnsafeFnPointer
|
adjustment::AdjustUnsafeFnPointer
|
||||||
}
|
}
|
||||||
@ -367,6 +373,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_fru_field_types(&self) {
|
||||||
|
for (&node_id, ftys) in self.fcx.inh.tables.borrow().fru_field_types.iter() {
|
||||||
|
let ftys = self.resolve(ftys, ResolvingFieldTypes(node_id));
|
||||||
|
self.tcx().tables.borrow_mut().fru_field_types.insert(node_id, ftys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve<T:TypeFoldable<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
|
fn resolve<T:TypeFoldable<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
|
||||||
t.fold_with(&mut Resolver::new(self.fcx, reason))
|
t.fold_with(&mut Resolver::new(self.fcx, reason))
|
||||||
}
|
}
|
||||||
@ -383,6 +396,7 @@ enum ResolveReason {
|
|||||||
ResolvingUpvar(ty::UpvarId),
|
ResolvingUpvar(ty::UpvarId),
|
||||||
ResolvingClosure(DefId),
|
ResolvingClosure(DefId),
|
||||||
ResolvingFnSig(ast::NodeId),
|
ResolvingFnSig(ast::NodeId),
|
||||||
|
ResolvingFieldTypes(ast::NodeId)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResolveReason {
|
impl ResolveReason {
|
||||||
@ -397,6 +411,9 @@ impl ResolveReason {
|
|||||||
ResolvingFnSig(id) => {
|
ResolvingFnSig(id) => {
|
||||||
tcx.map.span(id)
|
tcx.map.span(id)
|
||||||
}
|
}
|
||||||
|
ResolvingFieldTypes(id) => {
|
||||||
|
tcx.map.span(id)
|
||||||
|
}
|
||||||
ResolvingClosure(did) => {
|
ResolvingClosure(did) => {
|
||||||
if let Some(node_id) = tcx.map.as_local_node_id(did) {
|
if let Some(node_id) = tcx.map.as_local_node_id(did) {
|
||||||
tcx.expr_span(node_id)
|
tcx.expr_span(node_id)
|
||||||
@ -474,14 +491,14 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
|
|||||||
"cannot determine a type for this closure")
|
"cannot determine a type for this closure")
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvingFnSig(id) => {
|
ResolvingFnSig(id) | ResolvingFieldTypes(id) => {
|
||||||
// any failures here should also fail when
|
// any failures here should also fail when
|
||||||
// resolving the patterns, closure types, or
|
// resolving the patterns, closure types, or
|
||||||
// something else.
|
// something else.
|
||||||
let span = self.reason.span(self.tcx);
|
let span = self.reason.span(self.tcx);
|
||||||
self.tcx.sess.delay_span_bug(
|
self.tcx.sess.delay_span_bug(
|
||||||
span,
|
span,
|
||||||
&format!("cannot resolve some aspect of fn sig for {:?}", id));
|
&format!("cannot resolve some aspect of data for {:?}", id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,17 +21,14 @@ extern crate syntax;
|
|||||||
use rustc::mir::transform::MirPass;
|
use rustc::mir::transform::MirPass;
|
||||||
use rustc::mir::repr::{Mir, Literal};
|
use rustc::mir::repr::{Mir, Literal};
|
||||||
use rustc::mir::visit::MutVisitor;
|
use rustc::mir::visit::MutVisitor;
|
||||||
use rustc::middle::ty;
|
use rustc::middle::infer::InferCtxt;
|
||||||
use rustc::middle::const_eval::ConstVal;
|
use rustc::middle::const_eval::ConstVal;
|
||||||
use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray};
|
|
||||||
use rustc_plugin::Registry;
|
use rustc_plugin::Registry;
|
||||||
use rustc_front::hir;
|
|
||||||
use syntax::attr;
|
|
||||||
|
|
||||||
struct Pass;
|
struct Pass;
|
||||||
|
|
||||||
impl MirPass for Pass {
|
impl MirPass for Pass {
|
||||||
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ty::ctxt<'tcx>) {
|
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &InferCtxt<'a, 'tcx>) {
|
||||||
Visitor.visit_mir(mir)
|
Visitor.visit_mir(mir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
187
src/test/run-pass/mir_augmented_assignments.rs
Normal file
187
src/test/run-pass/mir_augmented_assignments.rs
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(augmented_assignments)]
|
||||||
|
#![feature(op_assign_traits)]
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use std::ops::{
|
||||||
|
AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, MulAssign, RemAssign,
|
||||||
|
ShlAssign, ShrAssign, SubAssign,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct Int(i32);
|
||||||
|
|
||||||
|
struct Slice([i32]);
|
||||||
|
|
||||||
|
impl Slice {
|
||||||
|
fn new(slice: &mut [i32]) -> &mut Slice {
|
||||||
|
unsafe {
|
||||||
|
mem::transmute(slice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
main_mir();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_mir]
|
||||||
|
fn main_mir() {
|
||||||
|
let mut x = Int(1);
|
||||||
|
|
||||||
|
x += Int(2);
|
||||||
|
assert_eq!(x, Int(0b11));
|
||||||
|
|
||||||
|
x &= Int(0b01);
|
||||||
|
assert_eq!(x, Int(0b01));
|
||||||
|
|
||||||
|
x |= Int(0b10);
|
||||||
|
assert_eq!(x, Int(0b11));
|
||||||
|
|
||||||
|
x ^= Int(0b01);
|
||||||
|
assert_eq!(x, Int(0b10));
|
||||||
|
|
||||||
|
x /= Int(2);
|
||||||
|
assert_eq!(x, Int(1));
|
||||||
|
|
||||||
|
x *= Int(3);
|
||||||
|
assert_eq!(x, Int(3));
|
||||||
|
|
||||||
|
x %= Int(2);
|
||||||
|
assert_eq!(x, Int(1));
|
||||||
|
|
||||||
|
// overloaded RHS
|
||||||
|
x <<= 1u8;
|
||||||
|
assert_eq!(x, Int(2));
|
||||||
|
|
||||||
|
x <<= 1u16;
|
||||||
|
assert_eq!(x, Int(4));
|
||||||
|
|
||||||
|
x >>= 1u8;
|
||||||
|
assert_eq!(x, Int(2));
|
||||||
|
|
||||||
|
x >>= 1u16;
|
||||||
|
assert_eq!(x, Int(1));
|
||||||
|
|
||||||
|
x -= Int(1);
|
||||||
|
assert_eq!(x, Int(0));
|
||||||
|
|
||||||
|
// indexed LHS
|
||||||
|
// FIXME(mir-drop): use the vec![..] macro
|
||||||
|
let mut v = Vec::new();
|
||||||
|
v.push(Int(1));
|
||||||
|
v.push(Int(2));
|
||||||
|
v[0] += Int(2);
|
||||||
|
assert_eq!(v[0], Int(3));
|
||||||
|
|
||||||
|
// unsized RHS
|
||||||
|
let mut array = [0, 1, 2];
|
||||||
|
*Slice::new(&mut array) += 1;
|
||||||
|
assert_eq!(array[0], 1);
|
||||||
|
assert_eq!(array[1], 2);
|
||||||
|
assert_eq!(array[2], 3);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for Int {
|
||||||
|
#[rustc_mir]
|
||||||
|
fn add_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 += rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitAndAssign for Int {
|
||||||
|
#[rustc_mir]
|
||||||
|
fn bitand_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 &= rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOrAssign for Int {
|
||||||
|
#[rustc_mir]
|
||||||
|
fn bitor_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 |= rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitXorAssign for Int {
|
||||||
|
#[rustc_mir]
|
||||||
|
fn bitxor_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 ^= rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DivAssign for Int {
|
||||||
|
#[rustc_mir]
|
||||||
|
fn div_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 /= rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MulAssign for Int {
|
||||||
|
#[rustc_mir]
|
||||||
|
fn mul_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 *= rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RemAssign for Int {
|
||||||
|
#[rustc_mir]
|
||||||
|
fn rem_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 %= rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShlAssign<u8> for Int {
|
||||||
|
#[rustc_mir]
|
||||||
|
fn shl_assign(&mut self, rhs: u8) {
|
||||||
|
self.0 <<= rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShlAssign<u16> for Int {
|
||||||
|
#[rustc_mir]
|
||||||
|
fn shl_assign(&mut self, rhs: u16) {
|
||||||
|
self.0 <<= rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShrAssign<u8> for Int {
|
||||||
|
#[rustc_mir]
|
||||||
|
fn shr_assign(&mut self, rhs: u8) {
|
||||||
|
self.0 >>= rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShrAssign<u16> for Int {
|
||||||
|
#[rustc_mir]
|
||||||
|
fn shr_assign(&mut self, rhs: u16) {
|
||||||
|
self.0 >>= rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for Int {
|
||||||
|
#[rustc_mir]
|
||||||
|
fn sub_assign(&mut self, rhs: Int) {
|
||||||
|
self.0 -= rhs.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign<i32> for Slice {
|
||||||
|
#[rustc_mir]
|
||||||
|
fn add_assign(&mut self, rhs: i32) {
|
||||||
|
for lhs in &mut self.0 {
|
||||||
|
*lhs += rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
src/test/run-pass/mir_autoderef.rs
Normal file
41
src/test/run-pass/mir_autoderef.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
pub struct MyRef(u32);
|
||||||
|
|
||||||
|
impl Deref for MyRef {
|
||||||
|
type Target = u32;
|
||||||
|
fn deref(&self) -> &u32 { &self.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for MyRef {
|
||||||
|
fn deref_mut(&mut self) -> &mut u32 { &mut self.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[rustc_mir]
|
||||||
|
fn deref(x: &MyRef) -> &u32 {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_mir]
|
||||||
|
fn deref_mut(x: &mut MyRef) -> &mut u32 {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut r = MyRef(2);
|
||||||
|
assert_eq!(deref(&r) as *const _, &r.0 as *const _);
|
||||||
|
assert_eq!(deref_mut(&mut r) as *mut _, &mut r.0 as *mut _);
|
||||||
|
}
|
41
src/test/run-pass/mir_struct_with_assoc_ty.rs
Normal file
41
src/test/run-pass/mir_struct_with_assoc_ty.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
pub trait DataBind {
|
||||||
|
type Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DataBind for Global<T> {
|
||||||
|
type Data = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Global<T>(PhantomData<T>);
|
||||||
|
|
||||||
|
pub struct Data {
|
||||||
|
pub offsets: <Global<[u32; 2]> as DataBind>::Data,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_mir]
|
||||||
|
fn create_data() -> Data {
|
||||||
|
let mut d = Data { offsets: [1, 2] };
|
||||||
|
d.offsets[0] = 3;
|
||||||
|
d
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let d = create_data();
|
||||||
|
assert_eq!(d.offsets[0], 3);
|
||||||
|
assert_eq!(d.offsets[1], 2);
|
||||||
|
}
|
@ -8,7 +8,7 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs, unboxed_closures, fn_traits)]
|
||||||
|
|
||||||
#[rustc_mir]
|
#[rustc_mir]
|
||||||
fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
|
fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
|
||||||
@ -117,6 +117,27 @@ fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
|
|||||||
f(x, y)
|
f(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rustc_mir]
|
||||||
|
fn test_fn_direct_call<F>(f: &F, x: i32, y: i32) -> i32
|
||||||
|
where F: Fn(i32, i32) -> i32
|
||||||
|
{
|
||||||
|
f.call((x, y))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_mir]
|
||||||
|
fn test_fn_const_call<F>(f: &F) -> i32
|
||||||
|
where F: Fn(i32, i32) -> i32
|
||||||
|
{
|
||||||
|
f.call((100, -1))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_mir]
|
||||||
|
fn test_fn_nil_call<F>(f: &F) -> i32
|
||||||
|
where F: Fn() -> i32
|
||||||
|
{
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
assert_eq!(test1(1, (2, 3), &[4, 5, 6]), (1, (2, 3), &[4, 5, 6][..]));
|
assert_eq!(test1(1, (2, 3), &[4, 5, 6]), (1, (2, 3), &[4, 5, 6][..]));
|
||||||
assert_eq!(test2(98), 98);
|
assert_eq!(test2(98), 98);
|
||||||
@ -128,9 +149,14 @@ fn main() {
|
|||||||
assert_eq!(test8(), 2);
|
assert_eq!(test8(), 2);
|
||||||
assert_eq!(test9(), 41 + 42 * 43);
|
assert_eq!(test9(), 41 + 42 * 43);
|
||||||
|
|
||||||
let closure = |x: i32, y: i32| { x + y };
|
let r = 3;
|
||||||
assert_eq!(test_closure(&closure, 100, 1), 101);
|
let closure = |x: i32, y: i32| { r*(x + (y*2)) };
|
||||||
|
assert_eq!(test_fn_const_call(&closure), 294);
|
||||||
|
assert_eq!(test_closure(&closure, 100, 1), 306);
|
||||||
let function_object = &closure as &Fn(i32, i32) -> i32;
|
let function_object = &closure as &Fn(i32, i32) -> i32;
|
||||||
assert_eq!(test_fn_object(function_object, 100, 2), 102);
|
assert_eq!(test_fn_object(function_object, 100, 2), 312);
|
||||||
assert_eq!(test_fn_impl(&function_object, 100, 3), 103);
|
assert_eq!(test_fn_impl(&function_object, 100, 3), 318);
|
||||||
|
assert_eq!(test_fn_direct_call(&closure, 100, 4), 324);
|
||||||
|
|
||||||
|
assert_eq!(test_fn_nil_call(&(|| 42)), 42);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user