Change:
} } <ins> fn make_mirror_unadjusted<'a, 'tcx>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> Expr<'tcx> { let expr_ty = cx.tcx.expr_ty(expr); let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); let kind = match expr.node { // Here comes the interesting stuff: hir::ExprMethodCall(_, _, ref args) => { // Rewrite a.b(c) into UFCS form like Trait::b(a, c) let expr = method_callee(cx, expr, ty::MethodCall::expr(expr.id)); let args = args.iter() .map(|e| e.to_ref()) .collect(); ExprKind::Call { ty: expr.ty, fun: expr.to_ref(), args: args, } } hir::ExprCall(ref fun, ref args) => { if cx.tcx.is_method_call(expr.id) { // The callee is something implementing Fn, FnMut, or FnOnce. // Find the actual method implementation being called and // build the appropriate UFCS call expression with the // callee-object as expr parameter. // rewrite f(u, v) into FnOnce::call_once(f, (u, v)) let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id)); let sig = match method.ty.sty { ty::TyFnDef(_, _, fn_ty) => &fn_ty.sig, _ => span_bug!(expr.span, "type of method is not an fn") }; let sig = cx.tcx.no_late_bound_regions(sig).unwrap_or_else(|| { span_bug!(expr.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: expr.span, kind: ExprKind::Tuple { fields: args.iter().map(ToRef::to_ref).collect() } }; ExprKind::Call { ty: method.ty, fun: method.to_ref(), args: vec![fun.to_ref(), tupled_args.to_ref()] } } else { let adt_data = if let hir::ExprPath(..) = fun.node { // Tuple-like ADTs are represented as ExprCall. We convert them here. expr_ty.ty_adt_def().and_then(|adt_def|{ match cx.tcx.def_map.borrow()[&fun.id].full_def() { Def::Variant(_, variant_id) => { Some((adt_def, adt_def.variant_index_with_id(variant_id))) }, Def::Struct(..) => { Some((adt_def, 0)) }, _ => None } }) } else { None }; if let Some((adt_def, index)) = adt_data { let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(fun.id).substs); let field_refs = args.iter().enumerate().map(|(idx, e)| FieldExprRef { name: Field::new(idx), expr: e.to_ref() }).collect(); ExprKind::Adt { adt_def: adt_def, substs: substs, variant_index: index, fields: field_refs, base: None } } else { ExprKind::Call { ty: cx.tcx.node_id_to_type(fun.id), fun: fun.to_ref(), args: args.to_ref(), } } } } hir::ExprAddrOf(mutbl, ref expr) => { let region = match expr_ty.sty { ty::TyRef(r, _) => r, _ => span_bug!(expr.span, "type of & not region"), }; ExprKind::Borrow { region: *region, borrow_kind: to_borrow_kind(mutbl), arg: expr.to_ref(), } } hir::ExprBlock(ref blk) => { ExprKind::Block { body: &blk } } hir::ExprAssign(ref lhs, ref rhs) => { ExprKind::Assign { lhs: lhs.to_ref(), rhs: rhs.to_ref(), } } hir::ExprAssignOp(op, ref lhs, ref rhs) => { if cx.tcx.is_method_call(expr.id) { let pass_args = if op.node.is_by_value() { PassArgs::ByValue } else { PassArgs::ByRef }; overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id), pass_args, lhs.to_ref(), vec![rhs]) } else { ExprKind::AssignOp { op: bin_op(op.node), lhs: lhs.to_ref(), rhs: rhs.to_ref(), } } } hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) }, hir::ExprBinary(op, ref lhs, ref rhs) => { if cx.tcx.is_method_call(expr.id) { let pass_args = if op.node.is_by_value() { PassArgs::ByValue } else { PassArgs::ByRef }; overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id), pass_args, lhs.to_ref(), vec![rhs]) } else { // FIXME overflow match op.node { hir::BinOp_::BiAnd => { ExprKind::LogicalOp { op: LogicalOp::And, lhs: lhs.to_ref(), rhs: rhs.to_ref(), } } hir::BinOp_::BiOr => { ExprKind::LogicalOp { op: LogicalOp::Or, lhs: lhs.to_ref(), rhs: rhs.to_ref(), } } _ => { let op = bin_op(op.node); ExprKind::Binary { op: op, lhs: lhs.to_ref(), rhs: rhs.to_ref(), } } } } } hir::ExprIndex(ref lhs, ref index) => { if cx.tcx.is_method_call(expr.id) { overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id), PassArgs::ByValue, lhs.to_ref(), vec![index]) } else { ExprKind::Index { lhs: lhs.to_ref(), index: index.to_ref(), } } } hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => { if cx.tcx.is_method_call(expr.id) { overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id), PassArgs::ByValue, arg.to_ref(), vec![]) } else { ExprKind::Deref { arg: arg.to_ref() } } } hir::ExprUnary(hir::UnOp::UnNot, ref arg) => { if cx.tcx.is_method_call(expr.id) { overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id), PassArgs::ByValue, arg.to_ref(), vec![]) } else { ExprKind::Unary { op: UnOp::Not, arg: arg.to_ref(), } } } hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => { if cx.tcx.is_method_call(expr.id) { overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id), PassArgs::ByValue, arg.to_ref(), vec![]) } else { // FIXME runtime-overflow if let hir::ExprLit(_) = arg.node { ExprKind::Literal { literal: cx.const_eval_literal(expr), } } else { ExprKind::Unary { op: UnOp::Neg, arg: arg.to_ref(), } } } } hir::ExprStruct(_, ref fields, ref base) => { match expr_ty.sty { ty::TyStruct(adt, substs) => { let field_refs = field_refs(&adt.variants[0], fields); ExprKind::Adt { adt_def: adt, variant_index: 0, substs: substs, fields: field_refs, base: base.as_ref().map(|base| { FruInfo { base: base.to_ref(), field_types: cx.tcx.tables .borrow() .fru_field_types[&expr.id] .clone() } }) } } ty::TyEnum(adt, substs) => { match cx.tcx.def_map.borrow()[&expr.id].full_def() { Def::Variant(enum_id, variant_id) => { debug_assert!(adt.did == enum_id); assert!(base.is_none()); let index = adt.variant_index_with_id(variant_id); let field_refs = field_refs(&adt.variants[index], fields); ExprKind::Adt { adt_def: adt, variant_index: index, substs: substs, fields: field_refs, base: None } } ref def => { span_bug!( expr.span, "unexpected def: {:?}", def); } } } _ => { span_bug!( expr.span, "unexpected type for struct literal: {:?}", expr_ty); } } } hir::ExprClosure(..) => { let closure_ty = cx.tcx.expr_ty(expr); let (def_id, substs) = match closure_ty.sty { ty::TyClosure(def_id, ref substs) => (def_id, substs), _ => { span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty); } }; let upvars = cx.tcx.with_freevars(expr.id, |freevars| { freevars.iter() .enumerate() .map(|(i, fv)| capture_freevar(cx, expr, fv, substs.upvar_tys[i])) .collect() }); ExprKind::Closure { closure_id: def_id, substs: &substs, upvars: upvars, } } hir::ExprPath(..) => { convert_path_expr(cx, expr) } hir::ExprInlineAsm(ref asm, ref outputs, ref inputs) => { ExprKind::InlineAsm { asm: asm, outputs: outputs.to_ref(), inputs: inputs.to_ref() } } // Now comes the rote stuff: hir::ExprRepeat(ref v, ref c) => ExprKind::Repeat { value: v.to_ref(), count: TypedConstVal { ty: cx.tcx.expr_ty(c), span: c.span, value: match const_eval::eval_const_expr(cx.tcx, c) { ConstVal::Integral(ConstInt::Usize(u)) => u, other => bug!("constant evaluation of repeat count yielded {:?}", other), }, } }, hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() }, hir::ExprBreak(label) => ExprKind::Break { label: label.map(|_| loop_label(cx, expr)) }, hir::ExprAgain(label) => ExprKind::Continue { label: label.map(|_| loop_label(cx, expr)) }, hir::ExprMatch(ref discr, ref arms, _) => ExprKind::Match { discriminant: discr.to_ref(), arms: arms.iter().map(|a| convert_arm(cx, a)).collect() }, hir::ExprIf(ref cond, ref then, ref otherwise) => ExprKind::If { condition: cond.to_ref(), then: block::to_expr_ref(cx, then), otherwise: otherwise.to_ref() }, hir::ExprWhile(ref cond, ref body, _) => ExprKind::Loop { condition: Some(cond.to_ref()), body: block::to_expr_ref(cx, body) }, hir::ExprLoop(ref body, _) => ExprKind::Loop { condition: None, body: block::to_expr_ref(cx, body) }, hir::ExprField(ref source, name) => { let index = match cx.tcx.expr_ty_adjusted(source).sty { ty::TyStruct(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node), ref ty => span_bug!( expr.span, "field of non-struct: {:?}", ty), }; let index = index.unwrap_or_else(|| { span_bug!( expr.span, "no index found for field `{}`", name.node) }); ExprKind::Field { lhs: source.to_ref(), name: Field::new(index) } } hir::ExprTupField(ref source, index) => ExprKind::Field { lhs: source.to_ref(), name: Field::new(index.node as usize) }, hir::ExprCast(ref source, _) => { // Check to see if this cast is a "coercion cast", where the cast is actually done // using a coercion (or is a no-op). if let Some(&TyCastKind::CoercionCast) = cx.tcx.cast_kinds.borrow().get(&source.id) { // Skip the actual cast itexpr, as it's now a no-op. return source.make_mirror(cx); } else { ExprKind::Cast { source: source.to_ref() } } } hir::ExprType(ref source, _) => return source.make_mirror(cx), hir::ExprBox(ref value) => ExprKind::Box { value: value.to_ref(), value_extents: cx.tcx.region_maps.node_extent(value.id) }, hir::ExprVec(ref fields) => ExprKind::Vec { fields: fields.to_ref() }, hir::ExprTup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() }, }; Expr { temp_lifetime: temp_lifetime, ty: expr_ty, span: expr.span, kind: kind, } } </ins> fn method_callee<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &hir::Expr, method_call: ty::MethodCall)

Discussion:
Compiling the crate with on ARM Linux: or : This was my first contact with mir and it wasn't peaceful :) Maybe I should have tried a , erm instead...
More ICEy stuff: coming from crate.
Minimal reproduction: It's the that is the problem. What happens is that we first reify to a function pointer, then try to cast the function pointer itself. It seems that we don't expect an cast in the MIR. I'm pretty sure that is only valid when it's a no-op, so we can probably just handle it MIR translation. that seem correct?
I some code to not build noop casts, the lifetimes may be different here though?
possibly, doing first and using in the cast works, so I'd say that lifetimes are the most likely source of difference between the two types in the cast. Do we have a lifetime-ignoring comparison we could use in this case?
Problem is, you can't ignore lifetimes, what if this is a to cast? There might be another way to tell that a cast only triggered a coercion, at the HAIR level. EDIT: Well, actually, the good old is a reification coercion + ptr-to-int cast.
do you mind giving a backtrace for that second error and opening a new issue for it (since it's unrelated to the two in the main post). If you could reduce it to a smaller reproduction, that would be even better.
There were no backtraces, unfortunately. Let's clarify one thing though - is turning off for a single crate and then resuming the mir'ed build, ok? That's how I arrived at the latter issue. (edit: wasn't the problem)
Actually MIR compilation has been bootstrappable for the compiler for a while now, so trying to use it for more complex codebases is really valuable, since it finds bugs like this.
The compiler doesn't generate a backtrace even if you set ?
That was the case indeed. (both ended in a segfault) -original message- Subject: Re: From: Eduard-Mihai Burtescu Date: 01.05.2016 12:22 The compiler doesn't generate a backtrace even if you set ? You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub:
Yeah, that's why I tried it - that whole sentence was a big pun on the word mir. (meaning both peace and world)