diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index b0660230c2ce6..1befa24f528b4 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -2006,7 +2006,8 @@ impl + PartialOrd + Clone + ToPrimitive> Iterator for Range { // This first checks if the elements are representable as i64. If they aren't, try u64 (to // handle cases like range(huge, huger)). We don't use uint/int because the difference of // the i64/u64 might lie within their range. - let bound = match self.state.to_i64() { + let state = self.state.to_i64(); + let bound = match state { Some(a) => { let sz = self.stop.to_i64().map(|b| b.checked_sub(&a)); match sz { diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 7997af1ee5e11..00965a957e4cc 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -840,8 +840,10 @@ fn encode_inlined_item(ecx: &EncodeContext, ebml_w: &mut Encoder, ii: InlinedItemRef) { let mut eii = ecx.encode_inlined_item.borrow_mut(); - let eii: &mut EncodeInlinedItem = &mut *eii; - (*eii)(ecx, ebml_w, ii) + unsafe { + let eii: &mut EncodeInlinedItem = ::std::mem::transmute_copy(& &mut *eii); + (*eii)(ecx, ebml_w, ii) + } } fn style_fn_family(s: FnStyle) -> char { diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index b570cb43f164e..8dd1ee7d77a9e 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -242,7 +242,7 @@ impl<'a> CheckLoanCtxt<'a> { let mut loan_path = loan_path; loop { match *loan_path { - LpVar(_) | LpUpvar(_) => { + LpVar(_) | LpUpvar(_) | LpAliasableRvalue(_) => { break; } LpExtend(ref lp_base, _, _) => { @@ -633,7 +633,7 @@ impl<'a> CheckLoanCtxt<'a> { */ match **lp { - LpVar(_) | LpUpvar(_) => { + LpVar(_) | LpUpvar(_) | LpAliasableRvalue(_) => { // assigning to `x` does not require that `x` is initialized } LpExtend(ref lp_base, _, LpInterior(_)) => { @@ -722,7 +722,9 @@ impl<'a> CheckLoanCtxt<'a> { debug!("mark_writes_through_upvars_as_used_mut(cmt={})", cmt.repr(this.tcx())); match cmt.cat.clone() { - mc::cat_local(id) | mc::cat_arg(id) => { + mc::cat_local(id) | + mc::cat_arg(id) | + mc::cat_aliasable_rvalue(id) => { this.tcx().used_mut_nodes.borrow_mut().insert(id); return; } diff --git a/src/librustc/middle/borrowck/gather_loans/gather_moves.rs b/src/librustc/middle/borrowck/gather_loans/gather_moves.rs index 322471f30294f..1deaf6261177f 100644 --- a/src/librustc/middle/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc/middle/borrowck/gather_loans/gather_moves.rs @@ -148,7 +148,8 @@ fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt, mc::cat_rvalue(..) | mc::cat_local(..) | - mc::cat_arg(..) => { + mc::cat_arg(..) | + mc::cat_aliasable_rvalue(..) => { None } diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index 0785538cc76ab..f2f00bf098c8b 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -16,6 +16,7 @@ use middle::borrowck::*; use euv = middle::expr_use_visitor; use mc = middle::mem_categorization; +use middle::mem_categorization::Typer; use middle::ty; use util::ppaux::Repr; use syntax::ast; @@ -67,6 +68,7 @@ impl<'a> GuaranteeLifetimeContext<'a> { match cmt.cat { mc::cat_rvalue(..) | + mc::cat_aliasable_rvalue(..) | mc::cat_copied_upvar(..) | // L-Local mc::cat_local(..) | // L-Local mc::cat_arg(..) | // L-Local @@ -178,6 +180,12 @@ impl<'a> GuaranteeLifetimeContext<'a> { mc::cat_arg(local_id) => { ty::ReScope(self.bccx.tcx.region_maps.var_scope(local_id)) } + mc::cat_aliasable_rvalue(expr_id) => { + match self.bccx.tcx.temporary_scope(expr_id) { + Some(scope) => ty::ReScope(scope), + None => ty::ReStatic, + } + } mc::cat_deref(_, _, mc::UnsafePtr(..)) => { ty::ReStatic } diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 454c3dcd5d3ca..2090def8df4af 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -395,9 +395,10 @@ impl<'a> GatherLoanCtxt<'a> { //! from a local variable, mark the mutability decl as necessary. match *loan_path { - LpVar(local_id) | - LpUpvar(ty::UpvarId{ var_id: local_id, closure_expr_id: _ }) => { - self.tcx().used_mut_nodes.borrow_mut().insert(local_id); + LpVar(id) | + LpUpvar(ty::UpvarId{ var_id: id, closure_expr_id: _ }) | + LpAliasableRvalue(id) => { + self.tcx().used_mut_nodes.borrow_mut().insert(id); } LpExtend(ref base, mc::McInherited, _) => { self.mark_loan_path_as_mutated(&**base); @@ -446,13 +447,20 @@ impl<'a> GatherLoanCtxt<'a> { //! with immutable `&` pointers, because borrows of such pointers //! do not require restrictions and hence do not cause a loan. - let lexical_scope = lp.kill_scope(self.bccx.tcx); - let rm = &self.bccx.tcx.region_maps; - if rm.is_subscope_of(lexical_scope, loan_scope) { - lexical_scope - } else { - assert!(self.bccx.tcx.region_maps.is_subscope_of(loan_scope, lexical_scope)); - loan_scope + match lp.kill_scope(self.bccx.tcx) { + Some(lexical_scope) => { + let rm = &self.bccx.tcx.region_maps; + if rm.is_subscope_of(lexical_scope, loan_scope) { + lexical_scope + } else { + assert!(self.bccx + .tcx + .region_maps + .is_subscope_of(loan_scope, lexical_scope)); + loan_scope + } + } + None => loan_scope, } } diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs index 48399cb0b7e02..3a8ee2fd50f24 100644 --- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -73,6 +73,12 @@ impl<'a> RestrictionsContext<'a> { SafeIf(lp.clone(), vec!(lp)) } + mc::cat_aliasable_rvalue(expr_id) => { + // R-Variable, effectively + let lp = Rc::new(LpAliasableRvalue(expr_id)); + SafeIf(lp.clone(), vec!(lp)) + } + mc::cat_upvar(upvar_id, _) => { // R-Variable, captured into closure let lp = Rc::new(LpUpvar(upvar_id)); diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 6c5352ed796d6..3894bebf72349 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -277,6 +277,7 @@ impl Loan { pub enum LoanPath { LpVar(ast::NodeId), // `x` in doc.rs LpUpvar(ty::UpvarId), // `x` captured by-value into closure + LpAliasableRvalue(ast::NodeId), // potentially-aliasable rvalue LpExtend(Rc, mc::MutabilityCategory, LoanPathElem) } @@ -299,11 +300,15 @@ pub fn closure_to_block(closure_id: ast::NodeId, } impl LoanPath { - pub fn kill_scope(&self, tcx: &ty::ctxt) -> ast::NodeId { + pub fn kill_scope(&self, tcx: &ty::ctxt) -> Option { match *self { - LpVar(local_id) => tcx.region_maps.var_scope(local_id), - LpUpvar(upvar_id) => - closure_to_block(upvar_id.closure_expr_id, tcx), + LpVar(local_id) => Some(tcx.region_maps.var_scope(local_id)), + LpUpvar(upvar_id) => { + Some(closure_to_block(upvar_id.closure_expr_id, tcx)) + } + LpAliasableRvalue(expr_id) => { + tcx.region_maps.temporary_scope(expr_id) + } LpExtend(ref base, _, _) => base.kill_scope(tcx), } } @@ -328,6 +333,10 @@ pub fn opt_loan_path(cmt: &mc::cmt) -> Option> { Some(Rc::new(LpVar(id))) } + mc::cat_aliasable_rvalue(id) => { + Some(Rc::new(LpAliasableRvalue(id))) + } + mc::cat_upvar(ty::UpvarId {var_id: id, closure_expr_id: proc_id}, _) | mc::cat_copied_upvar(mc::CopiedUpvar { upvar_id: id, onceness: _, @@ -799,6 +808,10 @@ impl<'a> BorrowckCtxt<'a> { out.push_str(ty::local_var_name_str(self.tcx, id).get()); } + LpAliasableRvalue(_) => { + out.push_str("") + } + LpExtend(ref lp_base, _, LpInterior(mc::InteriorField(fname))) => { self.append_autoderefd_loan_path_to_string(&**lp_base, out); match fname { @@ -836,7 +849,10 @@ impl<'a> BorrowckCtxt<'a> { self.append_autoderefd_loan_path_to_string(&**lp_base, out) } - LpVar(..) | LpUpvar(..) | LpExtend(_, _, LpInterior(..)) => { + LpVar(..) | + LpUpvar(..) | + LpExtend(_, _, LpInterior(..)) | + LpAliasableRvalue(..) => { self.append_loan_path_to_string(loan_path, out) } } @@ -903,6 +919,10 @@ impl Repr for LoanPath { format!("$({} captured by id={})", s, closure_expr_id) } + &LpAliasableRvalue(id) => { + format!("$(rvalue{})", id) + } + &LpExtend(ref lp, _, LpDeref(_)) => { format!("{}.*", lp.repr(tcx)) } diff --git a/src/librustc/middle/borrowck/move_data.rs b/src/librustc/middle/borrowck/move_data.rs index 6ec3f82ad68e7..0a2065f171108 100644 --- a/src/librustc/middle/borrowck/move_data.rs +++ b/src/librustc/middle/borrowck/move_data.rs @@ -26,6 +26,7 @@ use middle::dataflow::BitwiseOperator; use middle::dataflow::DataFlowOperator; use euv = middle::expr_use_visitor; use mc = middle::mem_categorization; +use middle::mem_categorization::Typer; use middle::ty; use syntax::ast; use syntax::ast_util; @@ -163,7 +164,7 @@ pub type AssignDataFlow<'a> = DataFlowContext<'a, AssignDataFlowOperator>; fn loan_path_is_precise(loan_path: &LoanPath) -> bool { match *loan_path { - LpVar(_) | LpUpvar(_) => { + LpVar(_) | LpUpvar(_) | LpAliasableRvalue(_) => { true } LpExtend(_, _, LpInterior(mc::InteriorElement(_))) => { @@ -248,7 +249,7 @@ impl MoveData { } let index = match *lp { - LpVar(..) | LpUpvar(..) => { + LpVar(..) | LpUpvar(..) | LpAliasableRvalue(..) => { let index = MovePathIndex(self.paths.borrow().len()); self.paths.borrow_mut().push(MovePath { @@ -319,7 +320,7 @@ impl MoveData { } None => { match **lp { - LpVar(..) | LpUpvar(..) => { } + LpVar(..) | LpUpvar(..) | LpAliasableRvalue(..) => { } LpExtend(ref b, _, _) => { self.add_existing_base_paths(b, result); } @@ -440,6 +441,17 @@ impl MoveData { let path = *self.path_map.borrow().get(&path.loan_path); self.kill_moves(path, kill_id, dfcx_moves); } + LpAliasableRvalue(id) => { + match tcx.temporary_scope(id) { + Some(kill_id) => { + let path = *self.path_map + .borrow() + .get(&path.loan_path); + self.kill_moves(path, kill_id, dfcx_moves); + } + None => {} + } + } LpExtend(..) => {} } } @@ -456,6 +468,14 @@ impl MoveData { let kill_id = closure_to_block(closure_expr_id, tcx); dfcx_assign.add_kill(kill_id, assignment_index); } + LpAliasableRvalue(expr_id) => { + match tcx.temporary_scope(expr_id) { + Some(kill_id) => { + dfcx_assign.add_kill(kill_id, assignment_index) + } + None => {} + } + } LpExtend(..) => { tcx.sess.bug("var assignment for non var path"); } diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 4f6885f05ed16..25447e4b48ec5 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -79,12 +79,14 @@ impl<'a> CFGBuilder<'a> { fn stmt(&mut self, stmt: Gc, pred: CFGIndex) -> CFGIndex { match stmt.node { - ast::StmtDecl(ref decl, _) => { - self.decl(&**decl, pred) + ast::StmtDecl(ref decl, stmt_id) => { + self.decl(&**decl, stmt_id, pred) } - ast::StmtExpr(ref expr, _) | ast::StmtSemi(ref expr, _) => { - self.expr(expr.clone(), pred) + ast::StmtExpr(ref expr, stmt_id) | + ast::StmtSemi(ref expr, stmt_id) => { + let expr_exit = self.expr(expr.clone(), pred); + self.add_node(stmt_id, [expr_exit]) } ast::StmtMac(..) => { @@ -93,11 +95,13 @@ impl<'a> CFGBuilder<'a> { } } - fn decl(&mut self, decl: &ast::Decl, pred: CFGIndex) -> CFGIndex { + fn decl(&mut self, decl: &ast::Decl, stmt_id: ast::NodeId, pred: CFGIndex) + -> CFGIndex { match decl.node { ast::DeclLocal(ref local) => { let init_exit = self.opt_expr(local.init.clone(), pred); - self.pat(&*local.pat, init_exit) + let stmt_exit = self.add_node(stmt_id, [init_exit]); + self.pat(&*local.pat, stmt_exit) } ast::DeclItem(_) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index a690d5882141f..52e863dfd148b 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -80,6 +80,7 @@ use std::rc::Rc; #[deriving(Clone, PartialEq)] pub enum categorization { cat_rvalue(ty::Region), // temporary val, argument is its scope + cat_aliasable_rvalue(ast::NodeId), // rvalue that might be aliased cat_static_item, cat_copied_upvar(CopiedUpvar), // upvar copied into proc env cat_upvar(ty::UpvarId, ty::UpvarBorrow), // by ref upvar from stack closure @@ -270,6 +271,7 @@ pub trait Typer { fn is_method_call(&self, id: ast::NodeId) -> bool; fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option; fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow; + fn is_rvalue_aliasable(&self, expr_id: ast::NodeId) -> bool; } impl MutabilityCategory { @@ -676,6 +678,10 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { span: Span, expr_ty: ty::t) -> cmt { + if self.typer.is_rvalue_aliasable(id) { + return self.cat_aliasable_rvalue(id, span, expr_ty) + } + match self.typer.temporary_scope(id) { Some(scope) => { self.cat_rvalue(id, span, ty::ReScope(scope), expr_ty) @@ -700,6 +706,20 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { }) } + fn cat_aliasable_rvalue(&self, + cmt_id: ast::NodeId, + span: Span, + expr_ty: ty::t) + -> cmt { + Rc::new(cmt_ { + id: cmt_id, + span: span, + cat: cat_aliasable_rvalue(cmt_id), + mutbl: McDeclared, + ty: expr_ty, + }) + } + pub fn cat_field(&self, node: &N, base_cmt: cmt, @@ -1156,6 +1176,9 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { cat_rvalue(..) => { "non-lvalue".to_string() } + cat_aliasable_rvalue(..) => { + "aliasable non-lvalue".to_string() + } cat_local(_) => { "local variable".to_string() } @@ -1228,6 +1251,7 @@ impl cmt_ { cat_copied_upvar(..) | cat_local(..) | cat_arg(..) | + cat_aliasable_rvalue(..) | cat_deref(_, _, UnsafePtr(..)) | cat_deref(_, _, GcPtr(..)) | cat_deref(_, _, BorrowedPtr(..)) | @@ -1269,6 +1293,7 @@ impl cmt_ { cat_copied_upvar(CopiedUpvar {onceness: ast::Once, ..}) | cat_rvalue(..) | + cat_aliasable_rvalue(..) | cat_local(..) | cat_upvar(..) | cat_arg(_) | @@ -1324,7 +1349,8 @@ impl Repr for categorization { cat_copied_upvar(..) | cat_local(..) | cat_upvar(..) | - cat_arg(..) => { + cat_arg(..) | + cat_aliasable_rvalue(..) => { format!("{:?}", *self) } cat_deref(ref cmt, derefs, ptr) => { diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 5f5a324857ab9..68c419de1b1e9 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -74,6 +74,11 @@ The region maps encode information about region relationships. would have to cleanup. Therefore we ensure that the temporaries never outlast the conditional/repeating expression, preventing the need for dynamic checks and/or arbitrary amounts of stack space. + +- `aliasable_rvalues` is a set containing the IDs of every rvalue that is + potentially aliasable. Most rvalues cannot be aliased, but those referenced + by a pattern that contains `@` bindings are. The borrow checker must treat + these rvalues as though they were lvalues to prevent illegal mutations. */ pub struct RegionMaps { scope_map: RefCell>, @@ -81,6 +86,7 @@ pub struct RegionMaps { free_region_map: RefCell >>, rvalue_scopes: RefCell>, terminating_scopes: RefCell>, + pub aliasable_rvalues: RefCell>, } #[deriving(Clone)] @@ -145,6 +151,16 @@ impl RegionMaps { self.terminating_scopes.borrow_mut().insert(scope_id); } + pub fn mark_as_aliasable_rvalue(&self, expr_id: ast::NodeId) { + /*! + * Records that an rvalue is an ALIASABLE RVALUE. Aliasable rvalues + * are those that could potentially get referred to by multiple names. + * The borrow checker needs to be extra careful with these. + */ + + self.aliasable_rvalues.borrow_mut().insert(expr_id); + } + pub fn opt_encl_scope(&self, id: ast::NodeId) -> Option { //! Returns the narrowest scope that encloses `id`, if any. self.scope_map.borrow().find(&id).map(|x| *x) @@ -527,6 +543,7 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, } ast::ExprForLoop(ref _pat, ref _head, ref body, _) => { + //visitor.region_maps.mark_as_aliasable_rvalue(head.id); visitor.region_maps.mark_as_terminating_scope(body.id); // The variable parent of everything inside (most importantly, the @@ -534,7 +551,9 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, new_cx.var_parent = Some(body.id); } - ast::ExprMatch(..) => { + ast::ExprMatch(ref scrutinee, _) => { + visitor.region_maps.mark_as_aliasable_rvalue(scrutinee.id); + new_cx.var_parent = Some(expr.id); } @@ -650,6 +669,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, match local.init { Some(ref expr) => { + visitor.region_maps.mark_as_aliasable_rvalue(expr.id); record_rvalue_scope_if_borrow_expr(visitor, &**expr, blk_id); if is_binding_pat(&*local.pat) || is_borrowed_ty(&*local.ty) { @@ -910,6 +930,7 @@ pub fn resolve_crate(sess: &Session, krate: &ast::Crate) -> RegionMaps { free_region_map: RefCell::new(HashMap::new()), rvalue_scopes: RefCell::new(NodeMap::new()), terminating_scopes: RefCell::new(HashSet::new()), + aliasable_rvalues: RefCell::new(HashSet::new()), }; { let mut visitor = RegionResolutionVisitor { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8f60fe340e4d6..4a16d0bfed484 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4862,6 +4862,10 @@ impl mc::Typer for ty::ctxt { fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow { self.upvar_borrow_map.borrow().get_copy(&upvar_id) } + + fn is_rvalue_aliasable(&self, expr_id: ast::NodeId) -> bool { + self.region_maps.aliasable_rvalues.borrow().contains(&expr_id) + } } /// The category of explicit self. diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index d0431de81a359..ea5b382b3a030 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -290,6 +290,10 @@ impl<'fcx> mc::Typer for Rcx<'fcx> { fn upvar_borrow(&self, id: ty::UpvarId) -> ty::UpvarBorrow { self.fcx.inh.upvar_borrow_map.borrow().get_copy(&id) } + + fn is_rvalue_aliasable(&self, expr_id: ast::NodeId) -> bool { + self.tcx().region_maps.aliasable_rvalues.borrow().contains(&expr_id) + } } pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { @@ -1319,7 +1323,8 @@ fn link_region(rcx: &Rcx, mc::cat_local(..) | mc::cat_arg(..) | mc::cat_upvar(..) | - mc::cat_rvalue(..) => { + mc::cat_rvalue(..) | + mc::cat_aliasable_rvalue(..) => { // These are all "base cases" with independent lifetimes // that are not subject to inference return; @@ -1390,7 +1395,8 @@ fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx, mc::cat_copied_upvar(_) | mc::cat_local(_) | mc::cat_arg(_) | - mc::cat_upvar(..) => { + mc::cat_upvar(..) | + mc::cat_aliasable_rvalue(..) => { return; } } @@ -1442,7 +1448,8 @@ fn adjust_upvar_borrow_kind_for_unique(rcx: &Rcx, cmt: mc::cmt) { mc::cat_copied_upvar(_) | mc::cat_local(_) | mc::cat_arg(_) | - mc::cat_upvar(..) => { + mc::cat_upvar(..) | + mc::cat_aliasable_rvalue(..) => { return; } } diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 871f277a2da28..fe3e60d65d37d 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -559,8 +559,10 @@ impl<'a> MethodDef<'a> { fields: fields }; let mut f = self.combine_substructure.borrow_mut(); - let f: &mut CombineSubstructureFunc = &mut *f; - (*f)(cx, trait_.span, &substructure) + unsafe { + let f: &mut CombineSubstructureFunc = ::std::mem::transmute_copy(& &mut *f); + (*f)(cx, trait_.span, &substructure) + } } fn get_ret_ty(&self,