From eb37c648d7c2b5587182c7d654622cf80542bea9 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 29 Dec 2018 21:10:00 +0000 Subject: [PATCH 1/3] Remove incorrect debug assertion in interpret Cast type may be a subtype of the destination type. There is a later assertion that they have the same layout. --- src/librustc_mir/interpret/step.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 29a8547035e..4ca865cc844 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -259,8 +259,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> )?; } - Cast(kind, ref operand, cast_ty) => { - debug_assert_eq!(self.monomorphize(cast_ty)?, dest.layout.ty); + Cast(kind, ref operand, _) => { let src = self.eval_operand(operand, None)?; self.cast(src, kind, dest)?; } From ff4d4b277f40b33b02e529d14c462ac11ab059ab Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 30 Mar 2019 13:00:41 +0000 Subject: [PATCH 2/3] Allow subtyping of the final expression of a constant Fixes an ICE for the following code: fn foo(_ : &()) {} static X: fn(&'static ()) = foo; --- src/librustc_mir/build/mod.rs | 33 +++++++++++++++++---- src/librustc_typeck/check/mod.rs | 2 ++ src/librustc_typeck/check/writeback.rs | 8 +++++ src/test/run-pass/mir/mir_static_subtype.rs | 8 +++++ 4 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 src/test/run-pass/mir/mir_static_subtype.rs diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 79e1d5daae1..16ab233bd2e 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -147,7 +147,21 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t build::construct_fn(cx, id, arguments, safety, abi, return_ty, yield_ty, return_ty_span, body) } else { - build::construct_const(cx, body_id, return_ty_span) + // Get the revealed type of this const. This is *not* the adjusted + // type of its body, which may be a subtype of this type. For + // example: + // + // fn foo(_: &()) {} + // static X: fn(&'static ()) = foo; + // + // The adjusted type of the body of X is `for<'a> fn(&'a ())` which + // is not the same as the type of X. We need the type of the return + // place to be the type of the constant because NLL typeck will + // equate them. + + let return_ty = cx.tables().node_type(id); + + build::construct_const(cx, body_id, return_ty, return_ty_span) }; // Convert the Mir to global types. @@ -730,16 +744,25 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, fn construct_const<'a, 'gcx, 'tcx>( hir: Cx<'a, 'gcx, 'tcx>, body_id: hir::BodyId, - ty_span: Span, + const_ty: Ty<'tcx>, + const_ty_span: Span, ) -> Mir<'tcx> { let tcx = hir.tcx(); - let ast_expr = &tcx.hir().body(body_id).value; - let ty = hir.tables().expr_ty_adjusted(ast_expr); let owner_id = tcx.hir().body_owner(body_id); let span = tcx.hir().span(owner_id); - let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, ty_span, vec![], vec![]); + let mut builder = Builder::new( + hir, + span, + 0, + Safety::Safe, + const_ty, + const_ty_span, + vec![], + vec![], + ); let mut block = START_BLOCK; + let ast_expr = &tcx.hir().body(body_id).value; let expr = builder.hir.mirror(ast_expr); unpack!(block = builder.into_expr(&Place::RETURN_PLACE, block, expr)); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 79477b6fea8..bd715df6e9d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -866,6 +866,8 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx.check_expr_coercable_to_type(&body.value, revealed_ty); + fcx.write_ty(id, revealed_ty); + fcx }; diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index efff08f6696..193b17af55e 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -42,6 +42,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for arg in &body.arguments { wbcx.visit_node_id(arg.pat.span, arg.hir_id); } + // Type only exists for constants and statics, not functions. + match self.tcx.hir().body_owner_kind(item_id) { + hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => { + let item_hir_id = self.tcx.hir().node_to_hir_id(item_id); + wbcx.visit_node_id(body.value.span, item_hir_id); + } + hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (), + } wbcx.visit_body(body); wbcx.visit_upvar_capture_map(); wbcx.visit_upvar_list_map(); diff --git a/src/test/run-pass/mir/mir_static_subtype.rs b/src/test/run-pass/mir/mir_static_subtype.rs new file mode 100644 index 00000000000..5b1ccd7ddf6 --- /dev/null +++ b/src/test/run-pass/mir/mir_static_subtype.rs @@ -0,0 +1,8 @@ +// Test that subtyping the body of a static doesn't cause an ICE. + +fn foo(_ : &()) {} +static X: fn(&'static ()) = foo; + +fn main() { + let _ = X; +} From e9c687b04a9511f2b93f35b5325d1b6ab5f5bb01 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 30 Mar 2019 13:05:33 +0000 Subject: [PATCH 3/3] Evaluate hair::ExprKind::Use in into This avoids some unnecessary moves --- src/librustc_mir/build/expr/as_rvalue.rs | 5 +---- src/librustc_mir/build/expr/category.rs | 2 +- src/librustc_mir/build/expr/into.rs | 4 +++- src/test/mir-opt/array-index-is-temporary.rs | 21 ++++++++++---------- src/test/mir-opt/retag.rs | 14 ++++++------- 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index c58b570d8fc..da2de43c09e 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -150,10 +150,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let source = unpack!(block = this.as_operand(block, scope, source)); block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty)) } - ExprKind::Use { source } => { - let source = unpack!(block = this.as_operand(block, scope, source)); - block.and(Rvalue::Use(source)) - } ExprKind::Pointer { cast, source } => { let source = unpack!(block = this.as_operand(block, scope, source)); block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty)) @@ -363,6 +359,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::NeverToAny { .. } + | ExprKind::Use { .. } | ExprKind::Loop { .. } | ExprKind::LogicalOp { .. } | ExprKind::Call { .. } diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs index 52f1d0eca5e..4e24b6853d6 100644 --- a/src/librustc_mir/build/expr/category.rs +++ b/src/librustc_mir/build/expr/category.rs @@ -48,6 +48,7 @@ impl Category { | ExprKind::If { .. } | ExprKind::Match { .. } | ExprKind::NeverToAny { .. } + | ExprKind::Use { .. } | ExprKind::Call { .. } => Some(Category::Rvalue(RvalueFunc::Into)), ExprKind::Array { .. } @@ -58,7 +59,6 @@ impl Category { | ExprKind::Binary { .. } | ExprKind::Box { .. } | ExprKind::Cast { .. } - | ExprKind::Use { .. } | ExprKind::Pointer { .. } | ExprKind::Repeat { .. } | ExprKind::Borrow { .. } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 8967572ea8f..30ed9cef36f 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -327,6 +327,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { success.unit() } } + ExprKind::Use { source } => { + this.into(destination, block, source) + } // These cases don't actually need a destination ExprKind::Assign { .. } @@ -379,7 +382,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::Binary { .. } | ExprKind::Box { .. } | ExprKind::Cast { .. } - | ExprKind::Use { .. } | ExprKind::Pointer { .. } | ExprKind::Repeat { .. } | ExprKind::Borrow { .. } diff --git a/src/test/mir-opt/array-index-is-temporary.rs b/src/test/mir-opt/array-index-is-temporary.rs index 856e1063f60..00a6b26d0cf 100644 --- a/src/test/mir-opt/array-index-is-temporary.rs +++ b/src/test/mir-opt/array-index-is-temporary.rs @@ -18,25 +18,24 @@ fn main() { // START rustc.main.EraseRegions.after.mir // bb0: { // ... -// _6 = &mut _2; -// _5 = &mut (*_6); -// _4 = move _5 as *mut usize (Misc); -// _3 = move _4; +// _5 = &mut _2; +// _4 = &mut (*_5); +// _3 = move _4 as *mut usize (Misc); // ... -// _8 = _3; -// _7 = const foo(move _8) -> bb1; +// _7 = _3; +// _6 = const foo(move _7) -> bb1; // } // // bb1: { // ... -// _9 = _2; -// _10 = Len(_1); -// _11 = Lt(_9, _10); -// assert(move _11, "index out of bounds: the len is move _10 but the index is _9") -> bb2; +// _8 = _2; +// _9 = Len(_1); +// _10 = Lt(_8, _9); +// assert(move _10, "index out of bounds: the len is move _9 but the index is _8") -> bb2; // } // // bb2: { -// _1[_9] = move _7; +// _1[_8] = move _6; // ... // return; // } diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs index 1f8abf10fa5..6b7c863fcd4 100644 --- a/src/test/mir-opt/retag.rs +++ b/src/test/mir-opt/retag.rs @@ -75,18 +75,18 @@ fn main() { // _10 = move _8; // Retag(_10); // ... -// _15 = &mut (*_10); -// Retag(_15); -// _14 = move _15 as *mut i32 (Misc); -// Retag([raw] _14); +// _13 = &mut (*_10); +// Retag(_13); +// _12 = move _13 as *mut i32 (Misc); +// Retag([raw] _12); // ... -// _18 = move _19(move _20) -> bb2; +// _16 = move _17(move _18) -> bb2; // } // // bb2: { -// Retag(_18); +// Retag(_16); // ... -// _22 = const Test::foo_shr(move _23, move _25) -> bb3; +// _20 = const Test::foo_shr(move _21, move _23) -> bb3; // } // // bb3: {