diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 0425c53d9dc3c..8317206c69adb 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -289,6 +289,10 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => { self.consume_operand(location, operand) } + Rvalue::VirtualRef(ref place) => { + let op = &Operand::Copy(*place); + self.consume_operand(location, op); + } Rvalue::Len(place) | Rvalue::Discriminant(place) => { let af = match *rvalue { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8ef2974c37232..9d8c5fe6d41d2 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1224,6 +1224,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => { self.consume_operand(location, (operand, span), flow_state) } + Rvalue::VirtualRef(place) => { + self.access_place( + location, + (place, span), + (Deep, Read(ReadKind::Copy)), + LocalMutationIsAllowed::No, + flow_state, + ); + + // Finally, check if path was already moved. + self.check_if_path_or_subpath_is_moved( + location, + InitializationRequiringAction::Use, + (place.as_ref(), span), + flow_state, + ); + } Rvalue::Len(place) | Rvalue::Discriminant(place) => { let af = match *rvalue { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 355254fe9429b..ed72f17740d3c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2278,6 +2278,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => { self.check_operand(operand, location); } + Rvalue::VirtualRef(place) => { + let op = &Operand::Copy(*place); + self.check_operand(op, location); + } Rvalue::BinaryOp(_, box (left, right)) | Rvalue::CheckedBinaryOp(_, box (left, right)) => { @@ -2308,6 +2312,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | Rvalue::BinaryOp(..) | Rvalue::CheckedBinaryOp(..) | Rvalue::NullaryOp(..) + | Rvalue::VirtualRef(..) | Rvalue::UnaryOp(..) | Rvalue::Discriminant(..) => None, diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index cad301812123b..9e50d33486cf2 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -1,11 +1,10 @@ -use crate::assert::expr_if_not; use rustc_ast::{ attr, ptr::P, token, tokenstream::{DelimSpan, TokenStream, TokenTree}, - BorrowKind, Expr, ExprKind, ItemKind, MacArgs, MacCall, MacDelimiter, Mutability, Path, - PathSegment, Stmt, StructRest, UseTree, UseTreeKind, DUMMY_NODE_ID, + BinOpKind, BorrowKind, Expr, ExprKind, ItemKind, MacArgs, MacCall, MacDelimiter, Mutability, + Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -16,11 +15,19 @@ use rustc_span::{ }; pub(super) struct Context<'cx, 'a> { + // An optimization. + // + // Elements that aren't consumed (PartialEq, PartialOrd, ...) can be copied **after** the + // `assert!` expression fails rather than copied on-the-fly. + best_case_captures: Vec, // Top-level `let captureN = Capture::new()` statements capture_decls: Vec, cx: &'cx ExtCtxt<'a>, // Formatting string used for debugging fmt_string: String, + // If the current expression being visited consumes itself. Used to construct + // `best_case_captures`. + is_consumed: bool, // Top-level `let __local_bindN = &expr` statements local_bind_decls: Vec, // Used to avoid capturing duplicated paths @@ -36,9 +43,11 @@ pub(super) struct Context<'cx, 'a> { impl<'cx, 'a> Context<'cx, 'a> { pub(super) fn new(cx: &'cx ExtCtxt<'a>, span: Span) -> Self { Self { + best_case_captures: <_>::default(), capture_decls: <_>::default(), cx, fmt_string: <_>::default(), + is_consumed: true, local_bind_decls: <_>::default(), paths: <_>::default(), span, @@ -69,14 +78,22 @@ impl<'cx, 'a> Context<'cx, 'a> { self.manage_cond_expr(&mut cond_expr); let initial_imports = self.build_initial_imports(); let panic = self.build_panic(&expr_str, panic_path); + let cond_expr_with_unlikely = self.build_unlikely(cond_expr); + + let Self { best_case_captures, capture_decls, cx, local_bind_decls, span, .. } = self; - let Self { capture_decls, cx, local_bind_decls, span, .. } = self; + let mut assert_then_stmts = Vec::with_capacity(2); + assert_then_stmts.extend(best_case_captures); + assert_then_stmts.push(self.cx.stmt_expr(panic)); + let assert_then = self.cx.block(span, assert_then_stmts); let mut stmts = Vec::with_capacity(4); stmts.push(initial_imports); stmts.extend(capture_decls.into_iter().map(|c| c.decl)); stmts.extend(local_bind_decls); - stmts.push(cx.stmt_expr(expr_if_not(cx, span, cond_expr, panic, None))); + stmts.push( + cx.stmt_expr(cx.expr(span, ExprKind::If(cond_expr_with_unlikely, assert_then, None))), + ); cx.expr_block(cx.block(span, stmts)) } @@ -115,6 +132,16 @@ impl<'cx, 'a> Context<'cx, 'a> { ) } + /// Takes the conditional expression of `assert!` and then wraps it inside `unlikely` + fn build_unlikely(&self, cond_expr: P) -> P { + let unlikely_path = self.cx.std_path(&[sym::intrinsics, sym::unlikely]); + self.cx.expr_call( + self.span, + self.cx.expr_path(self.cx.path(self.span, unlikely_path)), + vec![self.cx.expr(self.span, ExprKind::Unary(UnOp::Not, cond_expr))], + ) + } + /// The necessary custom `panic!(...)` expression. /// /// panic!( @@ -167,17 +194,39 @@ impl<'cx, 'a> Context<'cx, 'a> { /// See [Self::manage_initial_capture] and [Self::manage_try_capture] fn manage_cond_expr(&mut self, expr: &mut P) { match (*expr).kind { - ExprKind::AddrOf(_, _, ref mut local_expr) => { - self.manage_cond_expr(local_expr); + ExprKind::AddrOf(_, mutability, ref mut local_expr) => { + self.with_is_consumed_management( + matches!(mutability, Mutability::Mut), + |this| this.manage_cond_expr(local_expr) + ); } ExprKind::Array(ref mut local_exprs) => { for local_expr in local_exprs { self.manage_cond_expr(local_expr); } } - ExprKind::Binary(_, ref mut lhs, ref mut rhs) => { - self.manage_cond_expr(lhs); - self.manage_cond_expr(rhs); + ExprKind::Binary(ref op, ref mut lhs, ref mut rhs) => { + self.with_is_consumed_management( + matches!( + op.node, + BinOpKind::Add + | BinOpKind::And + | BinOpKind::BitAnd + | BinOpKind::BitOr + | BinOpKind::BitXor + | BinOpKind::Div + | BinOpKind::Mul + | BinOpKind::Or + | BinOpKind::Rem + | BinOpKind::Shl + | BinOpKind::Shr + | BinOpKind::Sub + ), + |this| { + this.manage_cond_expr(lhs); + this.manage_cond_expr(rhs); + } + ); } ExprKind::Call(_, ref mut local_exprs) => { for local_expr in local_exprs { @@ -228,8 +277,11 @@ impl<'cx, 'a> Context<'cx, 'a> { self.manage_cond_expr(local_expr); } } - ExprKind::Unary(_, ref mut local_expr) => { - self.manage_cond_expr(local_expr); + ExprKind::Unary(un_op, ref mut local_expr) => { + self.with_is_consumed_management( + matches!(un_op, UnOp::Neg | UnOp::Not), + |this| this.manage_cond_expr(local_expr) + ); } // Expressions that are not worth or can not be captured. // @@ -337,9 +389,23 @@ impl<'cx, 'a> Context<'cx, 'a> { )) .add_trailing_semicolon(); let local_bind_path = self.cx.expr_path(Path::from_ident(local_bind)); - let ret = self.cx.stmt_expr(local_bind_path); - let block = self.cx.expr_block(self.cx.block(self.span, vec![try_capture_call, ret])); - *expr = self.cx.expr_deref(self.span, block); + let rslt = if self.is_consumed { + let ret = self.cx.stmt_expr(local_bind_path); + self.cx.expr_block(self.cx.block(self.span, vec![try_capture_call, ret])) + } else { + self.best_case_captures.push(try_capture_call); + local_bind_path + }; + *expr = self.cx.expr_deref(self.span, rslt); + } + + // Calls `f` with the internal `is_consumed` set to `curr_is_consumed` and then + // sets the internal `is_consumed` back to its original value. + fn with_is_consumed_management(&mut self, curr_is_consumed: bool, f: impl FnOnce(&mut Self)) { + let prev_is_consumed = self.is_consumed; + self.is_consumed = curr_is_consumed; + f(self); + self.is_consumed = prev_is_consumed; } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index fbe830b2b1030..9f40b5264576c 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -503,6 +503,11 @@ fn codegen_stmt<'tcx>( let val = codegen_operand(fx, operand); lval.write_cvalue(fx, val); } + Rvalue::VirtualRef(place) => { + let cplace = codegen_place(fx, place); + let val = cplace.to_cvalue(fx); + lval.write_cvalue(fx, val) + } Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { let place = codegen_place(fx, place); let ref_ = place.place_ref(fx, lval.layout()); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 81c1897694ce6..30fc4db6e89bf 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -8,6 +8,7 @@ use crate::traits::*; use crate::MemFlags; use rustc_middle::mir; +use rustc_middle::mir::Operand; use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt}; @@ -401,6 +402,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_place_to_pointer(bx, place, mk_ref) } + mir::Rvalue::VirtualRef(place) => { + let operand = self.codegen_operand(&mut bx, &Operand::Copy(place)); + (bx, operand) + } mir::Rvalue::AddressOf(mutability, place) => { let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| { tcx.mk_ptr(ty::TypeAndMut { ty, mutbl: mutability }) @@ -755,6 +760,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool { match *rvalue { mir::Rvalue::Ref(..) | + mir::Rvalue::VirtualRef(..) | mir::Rvalue::AddressOf(..) | mir::Rvalue::Len(..) | mir::Rvalue::Cast(..) | // (*) diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 98f69456e49aa..06a2f40daef4f 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -172,6 +172,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.copy_op(&op, &dest)?; } + VirtualRef(ref place) => { + let op = self.eval_place_to_op(*place, Some(dest.layout))?; + self.copy_op(&op, &dest)?; + } + BinaryOp(bin_op, box (ref left, ref right)) => { let layout = binop_left_homogeneous(bin_op).then_some(dest.layout); let left = self.read_immediate(&self.eval_operand(left, layout)?)?; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 069fbed36ee3a..d216cde9d2886 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -445,6 +445,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::ThreadLocalRef(_) => self.check_op(ops::ThreadLocalAccess), Rvalue::Use(_) + | Rvalue::VirtualRef(..) | Rvalue::Repeat(..) | Rvalue::Discriminant(..) | Rvalue::Len(_) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 6e5a0c813ac20..84eddbb355cfa 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -260,6 +260,8 @@ where in_place::(cx, in_local, place.as_ref()) } + Rvalue::VirtualRef(place) => in_place::(cx, in_local, place.as_ref()), + Rvalue::Use(operand) | Rvalue::Repeat(operand, _) | Rvalue::UnaryOp(_, operand) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs index fd7febc17a3a7..e6c9f57e0d8c8 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs @@ -199,6 +199,7 @@ where mir::Rvalue::Cast(..) | mir::Rvalue::ShallowInitBox(..) | mir::Rvalue::Use(..) + | mir::Rvalue::VirtualRef(..) | mir::Rvalue::ThreadLocalRef(..) | mir::Rvalue::Repeat(..) | mir::Rvalue::Len(..) diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 3595a488d0c5b..2b4bdf5b5f28a 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -494,6 +494,10 @@ impl<'tcx> Validator<'_, 'tcx> { Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => { self.validate_operand(operand)?; } + Rvalue::VirtualRef(place) => { + let op = &Operand::Copy(*place); + self.validate_operand(op)? + } Rvalue::Discriminant(place) | Rvalue::Len(place) => { self.validate_place(place.as_ref())? diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index d830000b65f69..1f3cb401314d6 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -92,7 +92,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> { .borrow_mut() .unwrap_region_constraints() .opportunistic_resolve_var(rid); - self.tcx().reuse_or_mk_region(r, ty::ReVar(resolved)) + TypeFolder::tcx(self).reuse_or_mk_region(r, ty::ReVar(resolved)) } _ => r, } @@ -179,15 +179,13 @@ struct FullTypeResolver<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, } -impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { +impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { type Error = FixupError<'tcx>; fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { self.infcx.tcx } -} -impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result, Self::Error> { if !t.needs_infer() { Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects... diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 3f5b16d5ea5f7..6684745c8cfa2 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -159,6 +159,8 @@ pub enum MirPhase { /// of the `mir_promoted` query), these promoted elements are available in the `promoted_mir` /// query. ConstsPromoted = 2, + /// After this projections may only contain deref projections as the first element. + Derefered = 3, /// Beginning with this phase, the following variants are disallowed: /// * [`TerminatorKind::DropAndReplace`](terminator::TerminatorKind::DropAndReplace) /// * [`TerminatorKind::FalseUnwind`](terminator::TerminatorKind::FalseUnwind) @@ -173,9 +175,7 @@ pub enum MirPhase { /// Furthermore, `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop` /// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands /// are allowed for non-`Copy` types. - DropsLowered = 3, - /// After this projections may only contain deref projections as the first element. - Derefered = 4, + DropsLowered = 4, /// Beginning with this phase, the following variant is disallowed: /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array` /// @@ -1174,6 +1174,15 @@ impl<'tcx> LocalDecl<'tcx> { } } + /// Returns `true` if this is a DerefTemp + pub fn is_deref_temp(&self) -> bool { + match self.local_info { + Some(box LocalInfo::DerefTemp) => return true, + _ => (), + } + return false; + } + /// Returns `true` is the local is from a compiler desugaring, e.g., /// `__next` from a `for` loop. #[inline] @@ -2616,6 +2625,15 @@ pub enum Rvalue<'tcx> { /// initialized but its content as uninitialized. Like other pointer casts, this in general /// affects alias analysis. ShallowInitBox(Operand<'tcx>, Ty<'tcx>), + + /// A virtual ref is equivalent to a read from a reference/pointer at the + /// codegen level, but is treated specially by drop elaboration. When such a read happens, it + /// is guaranteed that the only use of the returned value is a deref operation, immediately + /// followed by one or more projections. Drop elaboration treats this virtual ref as if the + /// read never happened and just projects further. This allows simplifying various MIR + /// optimizations and codegen backends that previously had to handle deref operations anywhere + /// in a place. + VirtualRef(Place<'tcx>), } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] @@ -2632,6 +2650,7 @@ impl<'tcx> Rvalue<'tcx> { Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false, Rvalue::Use(_) + | Rvalue::VirtualRef(_) | Rvalue::Repeat(_, _) | Rvalue::Ref(_, _, _) | Rvalue::ThreadLocalRef(_) @@ -2809,6 +2828,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { }; write!(fmt, "&{}{}{:?}", region, kind_str, place) } + VirtualRef(ref place) => write!(fmt, "virt {:#?}", place), AddressOf(mutability, ref place) => { let kind_str = match mutability { diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index c93b7a9550229..8ec04e61a2e0b 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -211,6 +211,7 @@ impl<'tcx> Rvalue<'tcx> { } }, Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty), + Rvalue::VirtualRef(ref place) => place.ty(local_decls, tcx).ty, } } diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 4201b2d11ce2a..f20c0101d9fd5 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -184,6 +184,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { Ref(region, bk, place) => { Ref(region.try_fold_with(folder)?, bk, place.try_fold_with(folder)?) } + VirtualRef(place) => VirtualRef(place.try_fold_with(folder)?), AddressOf(mutability, place) => AddressOf(mutability, place.try_fold_with(folder)?), Len(place) => Len(place.try_fold_with(folder)?), Cast(kind, op, ty) => Cast(kind, op.try_fold_with(folder)?, ty.try_fold_with(folder)?), @@ -235,6 +236,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { region.visit_with(visitor)?; place.visit_with(visitor) } + VirtualRef(ref place) => place.visit_with(visitor), AddressOf(_, ref place) => place.visit_with(visitor), Len(ref place) => place.visit_with(visitor), Cast(_, ref op, ty) => { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 5ce92d127f3db..9aea4ae61d44a 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -670,6 +670,13 @@ macro_rules! make_mir_visitor { }; self.visit_place(path, ctx, location); } + Rvalue::VirtualRef(place) => { + self.visit_place( + place, + PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), + location + ); + } Rvalue::AddressOf(m, path) => { let ctx = match m { diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 31b8fa1ce956f..b1b8bc13e2f13 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -86,7 +86,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { /// A convenient alternative to `try_fold_with` for use with infallible /// folders. Do not override this method, to ensure coherence with /// `try_fold_with`. - fn fold_with>(self, folder: &mut F) -> Self { + fn fold_with>(self, folder: &mut F) -> Self { self.try_fold_with(folder).into_ok() } @@ -216,7 +216,7 @@ pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> { /// A convenient alternative to `try_super_fold_with` for use with /// infallible folders. Do not override this method, to ensure coherence /// with `try_super_fold_with`. - fn super_fold_with>(self, folder: &mut F) -> Self { + fn super_fold_with>(self, folder: &mut F) -> Self { self.try_super_fold_with(folder).into_ok() } @@ -229,70 +229,46 @@ pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow; } -/// This trait is implemented for every folding traversal. There is a fold -/// method defined for every type of interest. Each such method has a default -/// that does an "identity" fold. Implementations of these methods often fall -/// back to a `super_fold_with` method if the primary argument doesn't -/// satisfy a particular condition. +/// This trait is implemented for every infallible folding traversal. There is +/// a fold method defined for every type of interest. Each such method has a +/// default that does an "identity" fold. Implementations of these methods +/// often fall back to a `super_fold_with` method if the primary argument +/// doesn't satisfy a particular condition. /// -/// If this folder is fallible (and therefore its [`Error`][`TypeFolder::Error`] -/// associated type is something other than the default `!`) then -/// [`FallibleTypeFolder`] should be implemented manually. Otherwise, -/// a blanket implementation of [`FallibleTypeFolder`] will defer to +/// A blanket implementation of [`FallibleTypeFolder`] will defer to /// the infallible methods of this trait to ensure that the two APIs /// are coherent. -pub trait TypeFolder<'tcx>: Sized { - type Error = !; - +pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> { fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; fn fold_binder(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T> where T: TypeFoldable<'tcx>, - Self: TypeFolder<'tcx, Error = !>, { t.super_fold_with(self) } - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> - where - Self: TypeFolder<'tcx, Error = !>, - { + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { t.super_fold_with(self) } - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> - where - Self: TypeFolder<'tcx, Error = !>, - { + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { r.super_fold_with(self) } - fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> - where - Self: TypeFolder<'tcx, Error = !>, - { + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { c.super_fold_with(self) } - fn fold_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ty::Unevaluated<'tcx> - where - Self: TypeFolder<'tcx, Error = !>, - { + fn fold_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ty::Unevaluated<'tcx> { uv.super_fold_with(self) } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> - where - Self: TypeFolder<'tcx, Error = !>, - { + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { p.super_fold_with(self) } - fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> - where - Self: TypeFolder<'tcx, Error = !>, - { + fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> { bug!("most type folders should not be folding MIR datastructures: {:?}", c) } } @@ -304,7 +280,11 @@ pub trait TypeFolder<'tcx>: Sized { /// A blanket implementation of this trait (that defers to the relevant /// method of [`TypeFolder`]) is provided for all infallible folders in /// order to ensure the two APIs are coherent. -pub trait FallibleTypeFolder<'tcx>: TypeFolder<'tcx> { +pub trait FallibleTypeFolder<'tcx>: Sized { + type Error; + + fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; + fn try_fold_binder(&mut self, t: Binder<'tcx, T>) -> Result, Self::Error> where T: TypeFoldable<'tcx>, @@ -350,45 +330,48 @@ pub trait FallibleTypeFolder<'tcx>: TypeFolder<'tcx> { // delegates to infallible methods to ensure coherence. impl<'tcx, F> FallibleTypeFolder<'tcx> for F where - F: TypeFolder<'tcx, Error = !>, + F: TypeFolder<'tcx>, { - fn try_fold_binder(&mut self, t: Binder<'tcx, T>) -> Result, Self::Error> + type Error = !; + + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + TypeFolder::tcx(self) + } + + fn try_fold_binder(&mut self, t: Binder<'tcx, T>) -> Result, !> where T: TypeFoldable<'tcx>, { Ok(self.fold_binder(t)) } - fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result, Self::Error> { + fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result, !> { Ok(self.fold_ty(t)) } - fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result, Self::Error> { + fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result, !> { Ok(self.fold_region(r)) } - fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result, Self::Error> { + fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result, !> { Ok(self.fold_const(c)) } fn try_fold_unevaluated( &mut self, c: ty::Unevaluated<'tcx>, - ) -> Result, Self::Error> { + ) -> Result, !> { Ok(self.fold_unevaluated(c)) } - fn try_fold_predicate( - &mut self, - p: ty::Predicate<'tcx>, - ) -> Result, Self::Error> { + fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result, !> { Ok(self.fold_predicate(p)) } fn try_fold_mir_const( &mut self, c: mir::ConstantKind<'tcx>, - ) -> Result, Self::Error> { + ) -> Result, !> { Ok(self.fold_mir_const(c)) } } diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 9bbbd7e2f7c5e..66a0a192a87c1 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -228,15 +228,13 @@ impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> { } } -impl<'tcx> TypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> { +impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> { type Error = NormalizationError<'tcx>; fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } -} -impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> { fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result, Self::Error> { match self.try_normalize_generic_arg_after_erasing_regions(ty.into()) { Ok(t) => Ok(t.expect_ty()), diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index ad2898ccd67ba..1417c8a511c24 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -705,7 +705,7 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { return val; } - let result = ty::fold::shift_vars(self.tcx(), val, self.binders_passed); + let result = ty::fold::shift_vars(TypeFolder::tcx(self), val, self.binders_passed); debug!("shift_vars: shifted result = {:?}", result); result diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 627fe3f7f576b..4681f942f92ff 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -102,7 +102,8 @@ where | mir::Rvalue::NullaryOp(..) | mir::Rvalue::UnaryOp(..) | mir::Rvalue::Discriminant(..) - | mir::Rvalue::Aggregate(..) => {} + | mir::Rvalue::Aggregate(..) + | mir::Rvalue::VirtualRef(..) => {} } } diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index e4c130f0807dd..5793a286bd03d 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -38,6 +38,7 @@ pub mod impls; pub mod move_paths; pub mod rustc_peek; pub mod storage; +pub mod un_derefer; pub(crate) mod indexes { pub(crate) use super::move_paths::MovePathIndex; diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index b08cb50f77aed..75b0a68e65802 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -1,3 +1,4 @@ +use crate::un_derefer::UnDerefer; use rustc_index::vec::IndexVec; use rustc_middle::mir::tcx::RvalueInitializationState; use rustc_middle::mir::*; @@ -19,6 +20,7 @@ struct MoveDataBuilder<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, data: MoveData<'tcx>, errors: Vec<(Place<'tcx>, MoveError<'tcx>)>, + un_derefer: UnDerefer<'tcx>, } impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { @@ -32,6 +34,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { tcx, param_env, errors: Vec::new(), + un_derefer: UnDerefer { tcx: tcx, derefer_sidetable: Default::default() }, data: MoveData { moves: IndexVec::new(), loc_map: LocationMap::new(body), @@ -94,6 +97,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { /// /// Maybe we should have separate "borrowck" and "moveck" modes. fn move_path_for(&mut self, place: Place<'tcx>) -> Result> { + if let Some(new_place) = self.builder.un_derefer.derefer(place.as_ref()) { + return self.move_path_for(new_place); + } + debug!("lookup({:?})", place); let mut base = self.builder.data.rev_lookup.locals[place.local]; @@ -224,6 +231,8 @@ pub(super) fn gather_moves<'tcx>( param_env: ty::ParamEnv<'tcx>, ) -> Result, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> { let mut builder = MoveDataBuilder::new(body, tcx, param_env); + let mut un_derefer = UnDerefer { tcx: tcx, derefer_sidetable: Default::default() }; + un_derefer.ref_finder(body); builder.gather_args(); @@ -276,6 +285,10 @@ struct Gatherer<'b, 'a, 'tcx> { impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn gather_statement(&mut self, stmt: &Statement<'tcx>) { match &stmt.kind { + StatementKind::Assign(box (place, Rvalue::VirtualRef(reffed))) => { + assert!(place.projection.is_empty()); + self.builder.un_derefer.derefer_sidetable.insert(place.local, *reffed); + } StatementKind::Assign(box (place, rval)) => { self.create_move_path(*place); if let RvalueInitializationState::Shallow = rval.initialization_state() { @@ -294,7 +307,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { } StatementKind::StorageLive(_) => {} StatementKind::StorageDead(local) => { - self.gather_move(Place::from(*local)); + // DerefTemp locals (results of VirtualRef) don't actually move anything. + if !self.builder.un_derefer.derefer_sidetable.contains_key(&local) { + self.gather_move(Place::from(*local)); + } } StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(..) => { span_bug!( @@ -328,6 +344,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { self.gather_operand(operand); } } + Rvalue::VirtualRef(..) => unreachable!(), Rvalue::Ref(..) | Rvalue::AddressOf(..) | Rvalue::Discriminant(..) @@ -439,6 +456,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn gather_move(&mut self, place: Place<'tcx>) { debug!("gather_move({:?}, {:?})", self.loc, place); + if let Some(new_place) = self.builder.un_derefer.derefer(place.as_ref()) { + self.gather_move(new_place); + return; + } if let [ref base @ .., ProjectionElem::Subslice { from, to, from_end: false }] = **place.projection @@ -494,6 +515,11 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn gather_init(&mut self, place: PlaceRef<'tcx>, kind: InitKind) { debug!("gather_init({:?}, {:?})", self.loc, place); + if let Some(new_place) = self.builder.un_derefer.derefer(place) { + self.gather_init(new_place.as_ref(), kind); + return; + } + let mut place = place; // Check if we are assigning into a field of a union, if so, lookup the place diff --git a/compiler/rustc_mir_dataflow/src/un_derefer.rs b/compiler/rustc_mir_dataflow/src/un_derefer.rs new file mode 100644 index 0000000000000..4c45d385707b1 --- /dev/null +++ b/compiler/rustc_mir_dataflow/src/un_derefer.rs @@ -0,0 +1,31 @@ +use rustc_data_structures::stable_map::FxHashMap; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +/// Used for reverting changes made by `DerefSeparator` +pub struct UnDerefer<'tcx> { + pub tcx: TyCtxt<'tcx>, + pub derefer_sidetable: FxHashMap>, +} + +impl<'tcx> UnDerefer<'tcx> { + pub fn derefer(&self, place: PlaceRef<'tcx>) -> Option> { + let reffed = self.derefer_sidetable.get(&place.local)?; + + let new_place = reffed.project_deeper(place.projection, self.tcx); + Some(new_place) + } + + pub fn ref_finder(&mut self, body: &Body<'tcx>) { + for (_bb, data) in body.basic_blocks().iter_enumerated() { + for stmt in data.statements.iter() { + match stmt.kind { + StatementKind::Assign(box (place, Rvalue::VirtualRef(reffed))) => { + self.derefer_sidetable.insert(place.local, reffed); + } + _ => (), + } + } + } + } +} diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index 0495439385bee..000abbee51e38 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -57,17 +57,6 @@ fn may_be_reference(ty: Ty<'_>) -> bool { } } -/// Determines whether or not this LocalDecl is temp, if not it needs retagging. -fn is_not_temp<'tcx>(local_decl: &LocalDecl<'tcx>) -> bool { - if let Some(local_info) = &local_decl.local_info { - match local_info.as_ref() { - LocalInfo::DerefTemp => return false, - _ => (), - }; - } - return true; -} - impl<'tcx> MirPass<'tcx> for AddRetag { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { sess.opts.debugging_opts.mir_emit_retag @@ -84,7 +73,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag { // a temporary and retag on that. is_stable(place.as_ref()) && may_be_reference(place.ty(&*local_decls, tcx).ty) - && is_not_temp(&local_decls[place.local]) + && !local_decls[place.local].is_deref_temp() }; let place_base_raw = |place: &Place<'tcx>| { // If this is a `Deref`, get the type of what we are deref'ing. diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 412a5b4fc9104..8b17b70e196f8 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -616,6 +616,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // There's no other checking to do at this time. Rvalue::Aggregate(..) | Rvalue::Use(..) + | Rvalue::VirtualRef(..) | Rvalue::Repeat(..) | Rvalue::Len(..) | Rvalue::Cast(..) diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 15ad13009e59a..b29440f17e45f 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -683,6 +683,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // There's no other checking to do at this time. Rvalue::Aggregate(..) | Rvalue::Use(..) + | Rvalue::VirtualRef(..) | Rvalue::Repeat(..) | Rvalue::Len(..) | Rvalue::Cast(..) diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs index bfb3ad1be2734..badb092fb25db 100644 --- a/compiler/rustc_mir_transform/src/deref_separator.rs +++ b/compiler/rustc_mir_transform/src/deref_separator.rs @@ -35,6 +35,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> { last_deref_idx = idx; } } + for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() { if !p_ref.projection.is_empty() && p_elem == ProjectionElem::Deref { let ty = p_ref.ty(&self.local_decls, self.tcx).ty; @@ -54,7 +55,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> { self.patcher.add_assign( loc, Place::from(temp), - Rvalue::Use(Operand::Move(deref_place)), + Rvalue::VirtualRef(deref_place), ); place_local = temp; last_len = p_ref.projection.len(); diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index e0e27c53f1822..d11f514ee1ae2 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -1,3 +1,4 @@ +use crate::deref_separator::deref_finder; use crate::MirPass; use rustc_data_structures::fx::FxHashMap; use rustc_index::bit_set::BitSet; @@ -9,6 +10,7 @@ use rustc_mir_dataflow::elaborate_drops::{DropElaborator, DropFlagMode, DropStyl use rustc_mir_dataflow::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; use rustc_mir_dataflow::on_lookup_result_bits; +use rustc_mir_dataflow::un_derefer::UnDerefer; use rustc_mir_dataflow::MoveDataParamEnv; use rustc_mir_dataflow::{on_all_children_bits, on_all_drop_children_bits}; use rustc_mir_dataflow::{Analysis, ResultsCursor}; @@ -26,6 +28,8 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("elaborate_drops({:?} @ {:?})", body.source, body.span); + let mut un_derefer = UnDerefer { tcx: tcx, derefer_sidetable: Default::default() }; + un_derefer.ref_finder(body); let def_id = body.source.def_id(); let param_env = tcx.param_env_reveal_all_normalized(def_id); let move_data = match MoveData::gather_moves(body, tcx, param_env) { @@ -41,7 +45,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { let elaborate_patch = { let body = &*body; let env = MoveDataParamEnv { move_data, param_env }; - let dead_unwinds = find_dead_unwinds(tcx, body, &env); + let dead_unwinds = find_dead_unwinds(tcx, body, &env, &un_derefer); let inits = MaybeInitializedPlaces::new(tcx, body, &env) .into_engine(tcx, body) @@ -65,10 +69,12 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { init_data: InitializationData { inits, uninits }, drop_flags: Default::default(), patch: MirPatch::new(body), + un_derefer: un_derefer, } .elaborate() }; elaborate_patch.apply(body); + deref_finder(tcx, body); } } @@ -79,6 +85,7 @@ fn find_dead_unwinds<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, env: &MoveDataParamEnv<'tcx>, + und: &UnDerefer<'tcx>, ) -> BitSet { debug!("find_dead_unwinds({:?})", body.span); // We only need to do this pass once, because unwind edges can only @@ -92,7 +99,9 @@ fn find_dead_unwinds<'tcx>( for (bb, bb_data) in body.basic_blocks().iter_enumerated() { let place = match bb_data.terminator().kind { TerminatorKind::Drop { ref place, unwind: Some(_), .. } - | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => place, + | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => { + und.derefer(place.as_ref()).unwrap_or(*place) + } _ => continue, }; @@ -256,6 +265,7 @@ struct ElaborateDropsCtxt<'a, 'tcx> { init_data: InitializationData<'a, 'tcx>, drop_flags: FxHashMap, patch: MirPatch<'tcx>, + un_derefer: UnDerefer<'tcx>, } impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { @@ -298,7 +308,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let terminator = data.terminator(); let place = match terminator.kind { TerminatorKind::Drop { ref place, .. } - | TerminatorKind::DropAndReplace { ref place, .. } => place, + | TerminatorKind::DropAndReplace { ref place, .. } => { + self.un_derefer.derefer(place.as_ref()).unwrap_or(*place) + } _ => continue, }; @@ -312,12 +324,17 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { LookupResult::Parent(None) => continue, LookupResult::Parent(Some(parent)) => { let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent); + + if self.body.local_decls[place.local].is_deref_temp() { + continue; + } + if maybe_dead { self.tcx.sess.delay_span_bug( terminator.source_info.span, &format!( "drop of untracked, uninitialized value {:?}, place {:?} ({:?})", - bb, place, path, + bb, place, path ), ); } @@ -348,7 +365,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let resume_block = self.patch.resume_block(); match terminator.kind { - TerminatorKind::Drop { place, target, unwind } => { + TerminatorKind::Drop { mut place, target, unwind } => { + if let Some(new_place) = self.un_derefer.derefer(place.as_ref()) { + place = new_place; + } + self.init_data.seek_before(loc); match self.move_data().rev_lookup.find(place.as_ref()) { LookupResult::Exact(path) => elaborate_drop( @@ -372,9 +393,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } } } - TerminatorKind::DropAndReplace { place, ref value, target, unwind } => { + TerminatorKind::DropAndReplace { mut place, ref value, target, unwind } => { assert!(!data.is_cleanup); + if let Some(new_place) = self.un_derefer.derefer(place.as_ref()) { + place = new_place; + } self.elaborate_replace(loc, place, value, target, unwind); } _ => continue, diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index b7caa61ef07a7..37014497c6887 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -415,6 +415,7 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc &remove_noop_landing_pads::RemoveNoopLandingPads, &cleanup_post_borrowck::CleanupNonCodegenStatements, &simplify::SimplifyCfg::new("early-opt"), + &deref_separator::Derefer, // These next passes must be executed together &add_call_guards::CriticalCallEdges, &elaborate_drops::ElaborateDrops, @@ -427,7 +428,6 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc &add_moves_for_packed_drops::AddMovesForPackedDrops, // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late, // but before optimizations begin. - &deref_separator::Derefer, &elaborate_box_derefs::ElaborateBoxDerefs, &add_retag::AddRetag, &lower_intrinsics::LowerIntrinsics, diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 33ea1c4ba2f59..ec4bff30f95cd 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -218,6 +218,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData< // These rvalues move the place to track Rvalue::Cast(_, Operand::Copy(place) | Operand::Move(place), _) | Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) + | Rvalue::VirtualRef(place) | Rvalue::UnaryOp(_, Operand::Copy(place) | Operand::Move(place)) | Rvalue::Discriminant(place) => tracked_place = place, } @@ -279,6 +280,7 @@ fn find_determining_place<'tcx>( // that may be const in the predecessor Rvalue::Use(Operand::Move(new) | Operand::Copy(new)) | Rvalue::UnaryOp(_, Operand::Copy(new) | Operand::Move(new)) + | Rvalue::VirtualRef(new) | Rvalue::Cast(_, Operand::Move(new) | Operand::Copy(new), _) | Rvalue::Repeat(Operand::Move(new) | Operand::Copy(new), _) | Rvalue::Discriminant(new) diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index f1087db09d132..1b94c59b55f09 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -1,5 +1,5 @@ use super::{cvs, wasm_base}; -use super::{LinkArgs, LinkerFlavor, PanicStrategy, Target, TargetOptions}; +use super::{LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions}; pub fn target() -> Target { let mut options = wasm_base::options(); @@ -26,6 +26,7 @@ pub fn target() -> Target { // functionality, and a .wasm file. exe_suffix: ".js".into(), linker: None, + relocation_model: RelocModel::Pic, panic_strategy: PanicStrategy::Unwind, no_default_libraries: false, post_link_args, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index b80a27eb07d06..7f15b683fda3e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -12,7 +12,7 @@ use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::traits::Normalized; use rustc_middle::mir; -use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; @@ -162,15 +162,13 @@ struct QueryNormalizer<'cx, 'tcx> { universes: Vec>, } -impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { +impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { type Error = NoSolution; fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { self.infcx.tcx } -} -impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { fn try_fold_binder>( &mut self, t: ty::Binder<'tcx, T>, diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index f46997b807ab2..cd43e1cadae9a 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -184,6 +184,11 @@ pub struct DirEntry(fs_imp::DirEntry); #[stable(feature = "rust1", since = "1.0.0")] pub struct OpenOptions(fs_imp::OpenOptions); +/// Representation of the various timestamps on a file. +#[derive(Copy, Clone, Debug, Default)] +#[unstable(feature = "file_set_times", issue = "98245")] +pub struct FileTimes(fs_imp::FileTimes); + /// Representation of the various permissions on a file. /// /// This module only currently provides one bit of information, @@ -590,6 +595,58 @@ impl File { pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> { self.inner.set_permissions(perm.0) } + + /// Changes the timestamps of the underlying file. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `futimens` function on Unix (falling back to + /// `futimes` on macOS before 10.13) and the `SetFileTime` function on Windows. Note that this + /// [may change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior + /// + /// # Errors + /// + /// This function will return an error if the user lacks permission to change timestamps on the + /// underlying file. It may also return an error in other os-specific unspecified cases. + /// + /// This function may return an error if the operating system lacks support to change one or + /// more of the timestamps set in the `FileTimes` structure. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_set_times)] + /// + /// fn main() -> std::io::Result<()> { + /// use std::fs::{self, File, FileTimes}; + /// + /// let src = fs::metadata("src")?; + /// let dest = File::options().write(true).open("dest")?; + /// let times = FileTimes::new() + /// .set_accessed(src.accessed()?) + /// .set_modified(src.modified()?); + /// dest.set_times(times)?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_set_times", issue = "98245")] + #[doc(alias = "futimens")] + #[doc(alias = "futimes")] + #[doc(alias = "SetFileTime")] + pub fn set_times(&self, times: FileTimes) -> io::Result<()> { + self.inner.set_times(times.0) + } + + /// Changes the modification time of the underlying file. + /// + /// This is an alias for `set_times(FileTimes::new().set_modified(time))`. + #[unstable(feature = "file_set_times", issue = "98245")] + #[inline] + pub fn set_modified(&self, time: SystemTime) -> io::Result<()> { + self.set_times(FileTimes::new().set_modified(time)) + } } // In addition to the `impl`s here, `File` also has `impl`s for @@ -1246,6 +1303,30 @@ impl FromInner for Metadata { } } +impl FileTimes { + /// Create a new `FileTimes` with no times set. + /// + /// Using the resulting `FileTimes` in [`File::set_times`] will not modify any timestamps. + #[unstable(feature = "file_set_times", issue = "98245")] + pub fn new() -> Self { + Self::default() + } + + /// Set the last access time of a file. + #[unstable(feature = "file_set_times", issue = "98245")] + pub fn set_accessed(mut self, t: SystemTime) -> Self { + self.0.set_accessed(t.into_inner()); + self + } + + /// Set the last modified time of a file. + #[unstable(feature = "file_set_times", issue = "98245")] + pub fn set_modified(mut self, t: SystemTime) -> Self { + self.0.set_modified(t.into_inner()); + self + } +} + impl Permissions { /// Returns `true` if these permissions describe a readonly (unwritable) file. /// diff --git a/library/std/src/sys/itron/abi.rs b/library/std/src/sys/itron/abi.rs index f99ee4fa897ea..5eb14bb7e534b 100644 --- a/library/std/src/sys/itron/abi.rs +++ b/library/std/src/sys/itron/abi.rs @@ -30,15 +30,32 @@ pub type ER = int_t; /// Error code type, `ID` on success pub type ER_ID = int_t; +/// Service call operational mode +pub type MODE = uint_t; + +/// OR waiting condition for an eventflag +pub const TWF_ORW: MODE = 0x01; + +/// Object attributes +pub type ATR = uint_t; + +/// FIFO wait order +pub const TA_FIFO: ATR = 0; +/// Only one task is allowed to be in the waiting state for the eventflag +pub const TA_WSGL: ATR = 0; +/// The eventflag’s bit pattern is cleared when a task is released from the +/// waiting state for that eventflag. +pub const TA_CLR: ATR = 0x04; + +/// Bit pattern of an eventflag +pub type FLGPTN = uint_t; + /// Task or interrupt priority pub type PRI = int_t; /// The special value of `PRI` representing the current task's priority. pub const TPRI_SELF: PRI = 0; -/// Object attributes -pub type ATR = uint_t; - /// Use the priority inheritance protocol #[cfg(target_os = "solid_asp3")] pub const TA_INHERIT: ATR = 0x02; @@ -90,6 +107,13 @@ pub struct T_CSEM { pub maxsem: uint_t, } +#[derive(Clone, Copy)] +#[repr(C)] +pub struct T_CFLG { + pub flgatr: ATR, + pub iflgptn: FLGPTN, +} + #[derive(Clone, Copy)] #[repr(C)] pub struct T_CMTX { @@ -139,6 +163,24 @@ extern "C" { pub fn sns_dsp() -> bool_t; #[link_name = "__asp3_get_tim"] pub fn get_tim(p_systim: *mut SYSTIM) -> ER; + #[link_name = "__asp3_acre_flg"] + pub fn acre_flg(pk_cflg: *const T_CFLG) -> ER_ID; + #[link_name = "__asp3_del_flg"] + pub fn del_flg(flgid: ID) -> ER; + #[link_name = "__asp3_set_flg"] + pub fn set_flg(flgid: ID, setptn: FLGPTN) -> ER; + #[link_name = "__asp3_clr_flg"] + pub fn clr_flg(flgid: ID, clrptn: FLGPTN) -> ER; + #[link_name = "__asp3_wai_flg"] + pub fn wai_flg(flgid: ID, waiptn: FLGPTN, wfmode: MODE, p_flgptn: *mut FLGPTN) -> ER; + #[link_name = "__asp3_twai_flg"] + pub fn twai_flg( + flgid: ID, + waiptn: FLGPTN, + wfmode: MODE, + p_flgptn: *mut FLGPTN, + tmout: TMO, + ) -> ER; #[link_name = "__asp3_acre_mtx"] pub fn acre_mtx(pk_cmtx: *const T_CMTX) -> ER_ID; #[link_name = "__asp3_del_mtx"] diff --git a/library/std/src/sys/itron/wait_flag.rs b/library/std/src/sys/itron/wait_flag.rs new file mode 100644 index 0000000000000..e432edd207754 --- /dev/null +++ b/library/std/src/sys/itron/wait_flag.rs @@ -0,0 +1,72 @@ +use crate::mem::MaybeUninit; +use crate::time::Duration; + +use super::{ + abi, + error::{expect_success, fail}, + time::with_tmos, +}; + +const CLEAR: abi::FLGPTN = 0; +const RAISED: abi::FLGPTN = 1; + +/// A thread parking primitive that is not susceptible to race conditions, +/// but provides no atomic ordering guarantees and allows only one `raise` per wait. +pub struct WaitFlag { + flag: abi::ID, +} + +impl WaitFlag { + /// Creates a new wait flag. + pub fn new() -> WaitFlag { + let flag = expect_success( + unsafe { + abi::acre_flg(&abi::T_CFLG { + flgatr: abi::TA_FIFO | abi::TA_WSGL | abi::TA_CLR, + iflgptn: CLEAR, + }) + }, + &"acre_flg", + ); + + WaitFlag { flag } + } + + /// Wait for the wait flag to be raised. + pub fn wait(&self) { + let mut token = MaybeUninit::uninit(); + expect_success( + unsafe { abi::wai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr()) }, + &"wai_flg", + ); + } + + /// Wait for the wait flag to be raised or the timeout to occur. + /// + /// Returns whether the flag was raised (`true`) or the operation timed out (`false`). + pub fn wait_timeout(&self, dur: Duration) -> bool { + let mut token = MaybeUninit::uninit(); + let res = with_tmos(dur, |tmout| unsafe { + abi::twai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr(), tmout) + }); + + match res { + abi::E_OK => true, + abi::E_TMOUT => false, + error => fail(error, &"twai_flg"), + } + } + + /// Raise the wait flag. + /// + /// Calls to this function should be balanced with the number of successful waits. + pub fn raise(&self) { + expect_success(unsafe { abi::set_flg(self.flag, RAISED) }, &"set_flg"); + } +} + +impl Drop for WaitFlag { + fn drop(&mut self) { + expect_success(unsafe { abi::del_flg(self.flag) }, &"del_flg"); + } +} diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index 3792a3820a534..ea24fedd0eb3d 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -1,13 +1,16 @@ #![allow(unused)] +use crate::arch::asm; use crate::cell::UnsafeCell; +use crate::cmp; +use crate::convert::TryInto; use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut}; use crate::ptr::{self, NonNull}; use crate::slice; use crate::slice::SliceIndex; -use super::super::mem::is_user_range; +use super::super::mem::{is_enclave_range, is_user_range}; use fortanix_sgx_abi::*; /// A type that can be safely read from or written to userspace. @@ -210,7 +213,9 @@ where unsafe { // Mustn't call alloc with size 0. let ptr = if size > 0 { - rtunwrap!(Ok, super::alloc(size, T::align_of())) as _ + // `copy_to_userspace` is more efficient when data is 8-byte aligned + let alignment = cmp::max(T::align_of(), 8); + rtunwrap!(Ok, super::alloc(size, alignment)) as _ } else { T::align_of() as _ // dangling pointer ok for size 0 }; @@ -225,13 +230,9 @@ where /// Copies `val` into freshly allocated space in user memory. pub fn new_from_enclave(val: &T) -> Self { unsafe { - let ret = Self::new_uninit_bytes(mem::size_of_val(val)); - ptr::copy( - val as *const T as *const u8, - ret.0.as_ptr() as *mut u8, - mem::size_of_val(val), - ); - ret + let mut user = Self::new_uninit_bytes(mem::size_of_val(val)); + user.copy_from_enclave(val); + user } } @@ -304,6 +305,105 @@ where } } +/// Copies `len` bytes of data from enclave pointer `src` to userspace `dst` +/// +/// This function mitigates stale data vulnerabilities by ensuring all writes to untrusted memory are either: +/// - preceded by the VERW instruction and followed by the MFENCE; LFENCE instruction sequence +/// - or are in multiples of 8 bytes, aligned to an 8-byte boundary +/// +/// # Panics +/// This function panics if: +/// +/// * The `src` pointer is null +/// * The `dst` pointer is null +/// * The `src` memory range is not in enclave memory +/// * The `dst` memory range is not in user memory +/// +/// # References +/// - https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00615.html +/// - https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/processor-mmio-stale-data-vulnerabilities.html#inpage-nav-3-2-2 +pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) { + unsafe fn copy_bytewise_to_userspace(src: *const u8, dst: *mut u8, len: usize) { + unsafe { + let mut seg_sel: u16 = 0; + for off in 0..len { + asm!(" + mov %ds, ({seg_sel}) + verw ({seg_sel}) + movb {val}, ({dst}) + mfence + lfence + ", + val = in(reg_byte) *src.offset(off as isize), + dst = in(reg) dst.offset(off as isize), + seg_sel = in(reg) &mut seg_sel, + options(nostack, att_syntax) + ); + } + } + } + + unsafe fn copy_aligned_quadwords_to_userspace(src: *const u8, dst: *mut u8, len: usize) { + unsafe { + asm!( + "rep movsq (%rsi), (%rdi)", + inout("rcx") len / 8 => _, + inout("rdi") dst => _, + inout("rsi") src => _, + options(att_syntax, nostack, preserves_flags) + ); + } + } + assert!(!src.is_null()); + assert!(!dst.is_null()); + assert!(is_enclave_range(src, len)); + assert!(is_user_range(dst, len)); + assert!(len < isize::MAX as usize); + assert!(!(src as usize).overflowing_add(len).1); + assert!(!(dst as usize).overflowing_add(len).1); + + if len < 8 { + // Can't align on 8 byte boundary: copy safely byte per byte + unsafe { + copy_bytewise_to_userspace(src, dst, len); + } + } else if len % 8 == 0 && dst as usize % 8 == 0 { + // Copying 8-byte aligned quadwords: copy quad word per quad word + unsafe { + copy_aligned_quadwords_to_userspace(src, dst, len); + } + } else { + // Split copies into three parts: + // +--------+ + // | small0 | Chunk smaller than 8 bytes + // +--------+ + // | big | Chunk 8-byte aligned, and size a multiple of 8 bytes + // +--------+ + // | small1 | Chunk smaller than 8 bytes + // +--------+ + + unsafe { + // Copy small0 + let small0_size = (8 - dst as usize % 8) as u8; + let small0_src = src; + let small0_dst = dst; + copy_bytewise_to_userspace(small0_src as _, small0_dst, small0_size as _); + + // Copy big + let small1_size = ((len - small0_size as usize) % 8) as u8; + let big_size = len - small0_size as usize - small1_size as usize; + let big_src = src.offset(small0_size as _); + let big_dst = dst.offset(small0_size as _); + copy_aligned_quadwords_to_userspace(big_src as _, big_dst, big_size); + + // Copy small1 + let small1_src = src.offset(big_size as isize + small0_size as isize); + let small1_dst = dst.offset(big_size as isize + small0_size as isize); + copy_bytewise_to_userspace(small1_src, small1_dst, small1_size as _); + } + } +} + #[unstable(feature = "sgx_platform", issue = "56975")] impl UserRef where @@ -352,7 +452,7 @@ where pub fn copy_from_enclave(&mut self, val: &T) { unsafe { assert_eq!(mem::size_of_val(val), mem::size_of_val(&*self.0.get())); - ptr::copy( + copy_to_userspace( val as *const T as *const u8, self.0.get() as *mut T as *mut u8, mem::size_of_val(val), diff --git a/library/std/src/sys/sgx/abi/usercalls/mod.rs b/library/std/src/sys/sgx/abi/usercalls/mod.rs index 2f99abba77667..79d1db5e1c50d 100644 --- a/library/std/src/sys/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/sgx/abi/usercalls/mod.rs @@ -6,6 +6,8 @@ use crate::time::{Duration, Instant}; pub(crate) mod alloc; #[macro_use] pub(crate) mod raw; +#[cfg(test)] +mod tests; use self::raw::*; diff --git a/library/std/src/sys/sgx/abi/usercalls/tests.rs b/library/std/src/sys/sgx/abi/usercalls/tests.rs new file mode 100644 index 0000000000000..cbf7d7d54f7a2 --- /dev/null +++ b/library/std/src/sys/sgx/abi/usercalls/tests.rs @@ -0,0 +1,30 @@ +use super::alloc::copy_to_userspace; +use super::alloc::User; + +#[test] +fn test_copy_function() { + let mut src = [0u8; 100]; + let mut dst = User::<[u8]>::uninitialized(100); + + for i in 0..src.len() { + src[i] = i as _; + } + + for size in 0..48 { + // For all possible alignment + for offset in 0..8 { + // overwrite complete dst + dst.copy_from_enclave(&[0u8; 100]); + + // Copy src[0..size] to dst + offset + unsafe { copy_to_userspace(src.as_ptr(), dst.as_mut_ptr().offset(offset), size) }; + + // Verify copy + for byte in 0..size { + unsafe { + assert_eq!(*dst.as_ptr().offset(offset + byte as isize), src[byte as usize]); + } + } + } + } +} diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs index 5ffa381f2e50f..2d21e4764fc21 100644 --- a/library/std/src/sys/solid/mod.rs +++ b/library/std/src/sys/solid/mod.rs @@ -15,6 +15,7 @@ mod itron { pub mod thread; pub(super) mod time; use super::unsupported; + pub mod wait_flag; } pub mod alloc; @@ -43,6 +44,7 @@ pub mod memchr; pub mod thread_local_dtor; pub mod thread_local_key; pub mod time; +pub use self::itron::wait_flag; mod rwlock; diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 8b0bbd6a55c6b..f33ab3a3e14b2 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -311,6 +311,9 @@ pub struct FilePermissions { mode: mode_t, } +#[derive(Copy, Clone)] +pub struct FileTimes([libc::timespec; 2]); + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct FileType { mode: mode_t, @@ -503,6 +506,43 @@ impl FilePermissions { } } +impl FileTimes { + pub fn set_accessed(&mut self, t: SystemTime) { + self.0[0] = t.t.to_timespec().expect("Invalid system time"); + } + + pub fn set_modified(&mut self, t: SystemTime) { + self.0[1] = t.t.to_timespec().expect("Invalid system time"); + } +} + +struct TimespecDebugAdapter<'a>(&'a libc::timespec); + +impl fmt::Debug for TimespecDebugAdapter<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("timespec") + .field("tv_sec", &self.0.tv_sec) + .field("tv_nsec", &self.0.tv_nsec) + .finish() + } +} + +impl fmt::Debug for FileTimes { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FileTimes") + .field("accessed", &TimespecDebugAdapter(&self.0[0])) + .field("modified", &TimespecDebugAdapter(&self.0[1])) + .finish() + } +} + +impl Default for FileTimes { + fn default() -> Self { + let omit = libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT }; + Self([omit; 2]) + } +} + impl FileType { pub fn is_dir(&self) -> bool { self.is(libc::S_IFDIR) @@ -1021,6 +1061,30 @@ impl File { cvt_r(|| unsafe { libc::fchmod(self.as_raw_fd(), perm.mode) })?; Ok(()) } + + pub fn set_times(&self, times: FileTimes) -> io::Result<()> { + cfg_if::cfg_if! { + // futimens requires macOS 10.13 + if #[cfg(target_os = "macos")] { + fn ts_to_tv(ts: &libc::timespec) -> libc::timeval { + libc::timeval { tv_sec: ts.tv_sec, tv_usec: (ts.tv_nsec / 1000) as _ } + } + cvt(unsafe { + weak!(fn futimens(c_int, *const libc::timespec) -> c_int); + futimens.get() + .map(|futimens| futimens(self.as_raw_fd(), times.0.as_ptr())) + .unwrap_or_else(|| { + let timevals = [ts_to_tv(×.0[0]), ts_to_tv(×.0[1])]; + libc::futimes(self.as_raw_fd(), timevals.as_ptr()) + }) + })?; + } else { + cvt(unsafe { libc::futimens(self.as_raw_fd(), times.0.as_ptr()) })?; + } + } + + Ok(()) + } } impl DirBuilder { diff --git a/library/std/src/sys/unsupported/fs.rs b/library/std/src/sys/unsupported/fs.rs index d1d2847cd33be..0e1a6257ed763 100644 --- a/library/std/src/sys/unsupported/fs.rs +++ b/library/std/src/sys/unsupported/fs.rs @@ -17,6 +17,9 @@ pub struct DirEntry(!); #[derive(Clone, Debug)] pub struct OpenOptions {} +#[derive(Copy, Clone, Debug, Default)] +pub struct FileTimes {} + pub struct FilePermissions(!); pub struct FileType(!); @@ -86,6 +89,11 @@ impl fmt::Debug for FilePermissions { } } +impl FileTimes { + pub fn set_accessed(&mut self, _t: SystemTime) {} + pub fn set_modified(&mut self, _t: SystemTime) {} +} + impl FileType { pub fn is_dir(&self) -> bool { self.0 @@ -237,6 +245,10 @@ impl File { pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { self.0 } + + pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { + self.0 + } } impl DirBuilder { diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index cd6815bfc2136..b0cc748037862 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -63,6 +63,12 @@ pub struct FilePermissions { readonly: bool, } +#[derive(Copy, Clone, Debug, Default)] +pub struct FileTimes { + accessed: Option, + modified: Option, +} + #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] pub struct FileType { bits: wasi::Filetype, @@ -112,6 +118,16 @@ impl FilePermissions { } } +impl FileTimes { + pub fn set_accessed(&mut self, t: SystemTime) { + self.accessed = t.to_wasi_timestamp_or_panic(); + } + + pub fn set_modified(&mut self, t: SystemTime) { + self.modified = t.to_wasi_timestamp_or_panic(); + } +} + impl FileType { pub fn is_dir(&self) -> bool { self.bits == wasi::FILETYPE_DIRECTORY @@ -459,6 +475,15 @@ impl File { unsupported() } + pub fn set_times(&self, times: FileTimes) -> io::Result<()> { + self.fd.filestat_set_times( + times.accessed.unwrap_or(0), + times.modified.unwrap_or(0), + times.accessed.map_or(0, || wasi::FSTFLAGS_ATIM) + | times.modified.map_or(0, || wasi::FSTFLAGS_MTIM), + ) + } + pub fn read_link(&self, file: &Path) -> io::Result { read_link(&self.fd, file) } diff --git a/library/std/src/sys/wasi/time.rs b/library/std/src/sys/wasi/time.rs index 088585654b948..3d326e49106ca 100644 --- a/library/std/src/sys/wasi/time.rs +++ b/library/std/src/sys/wasi/time.rs @@ -47,6 +47,10 @@ impl SystemTime { SystemTime(Duration::from_nanos(ts)) } + pub fn to_wasi_timestamp_or_panic(&self) -> wasi::Timestamp { + self.0.as_nanos().try_into().expect("time does not fit in WASI timestamp") + } + pub fn sub_time(&self, other: &SystemTime) -> Result { self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) } diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 5469487df1eed..abb471213d251 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -607,7 +607,7 @@ pub struct SOCKADDR { } #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug, Default)] pub struct FILETIME { pub dwLowDateTime: DWORD, pub dwHighDateTime: DWORD, @@ -875,6 +875,12 @@ extern "system" { pub fn GetSystemDirectoryW(lpBuffer: LPWSTR, uSize: UINT) -> UINT; pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL; pub fn SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: DWORD) -> BOOL; + pub fn SetFileTime( + hFile: BorrowedHandle<'_>, + lpCreationTime: Option<&FILETIME>, + lpLastAccessTime: Option<&FILETIME>, + lpLastWriteTime: Option<&FILETIME>, + ) -> BOOL; pub fn SetLastError(dwErrCode: DWORD); pub fn GetCommandLineW() -> LPWSTR; pub fn GetTempPathW(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD; diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 157d8a044d3cd..e3809f3579dfd 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -82,6 +82,12 @@ pub struct FilePermissions { attrs: c::DWORD, } +#[derive(Copy, Clone, Debug, Default)] +pub struct FileTimes { + accessed: c::FILETIME, + modified: c::FILETIME, +} + #[derive(Debug)] pub struct DirBuilder; @@ -550,6 +556,14 @@ impl File { })?; Ok(()) } + + pub fn set_times(&self, times: FileTimes) -> io::Result<()> { + cvt(unsafe { + c::SetFileTime(self.as_handle(), None, Some(×.accessed), Some(×.modified)) + })?; + Ok(()) + } + /// Get only basic file information such as attributes and file times. fn basic_info(&self) -> io::Result { unsafe { @@ -895,6 +909,16 @@ impl FilePermissions { } } +impl FileTimes { + pub fn set_accessed(&mut self, t: SystemTime) { + self.accessed = t.into_inner(); + } + + pub fn set_modified(&mut self, t: SystemTime) { + self.modified = t.into_inner(); + } +} + impl FileType { fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType { FileType { attributes: attrs, reparse_tag } diff --git a/library/std/src/sys/windows/time.rs b/library/std/src/sys/windows/time.rs index 8f46781c75340..b8209a8544585 100644 --- a/library/std/src/sys/windows/time.rs +++ b/library/std/src/sys/windows/time.rs @@ -2,6 +2,7 @@ use crate::cmp::Ordering; use crate::fmt; use crate::mem; use crate::sys::c; +use crate::sys_common::IntoInner; use crate::time::Duration; use core::hash::{Hash, Hasher}; @@ -136,6 +137,12 @@ impl From for SystemTime { } } +impl IntoInner for SystemTime { + fn into_inner(self) -> c::FILETIME { + self.t + } +} + impl Hash for SystemTime { fn hash(&self, state: &mut H) { self.intervals().hash(state) diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs index 7e8bfb2565e45..cbd7832eb7a4c 100644 --- a/library/std/src/sys_common/thread_parker/mod.rs +++ b/library/std/src/sys_common/thread_parker/mod.rs @@ -10,9 +10,10 @@ cfg_if::cfg_if! { ))] { mod futex; pub use futex::Parker; - } else if #[cfg(windows)] { - pub use crate::sys::thread_parker::Parker; - } else if #[cfg(target_family = "unix")] { + } else if #[cfg(target_os = "solid_asp3")] { + mod wait_flag; + pub use wait_flag::Parker; + } else if #[cfg(any(windows, target_family = "unix"))] { pub use crate::sys::thread_parker::Parker; } else { mod generic; diff --git a/library/std/src/sys_common/thread_parker/wait_flag.rs b/library/std/src/sys_common/thread_parker/wait_flag.rs new file mode 100644 index 0000000000000..6561c186655a5 --- /dev/null +++ b/library/std/src/sys_common/thread_parker/wait_flag.rs @@ -0,0 +1,102 @@ +//! A wait-flag-based thread parker. +//! +//! Some operating systems provide low-level parking primitives like wait counts, +//! event flags or semaphores which are not susceptible to race conditions (meaning +//! the wakeup can occur before the wait operation). To implement the `std` thread +//! parker on top of these primitives, we only have to ensure that parking is fast +//! when the thread token is available, the atomic ordering guarantees are maintained +//! and spurious wakeups are minimized. +//! +//! To achieve this, this parker uses an atomic variable with three states: `EMPTY`, +//! `PARKED` and `NOTIFIED`: +//! * `EMPTY` means the token has not been made available, but the thread is not +//! currently waiting on it. +//! * `PARKED` means the token is not available and the thread is parked. +//! * `NOTIFIED` means the token is available. +//! +//! `park` and `park_timeout` change the state from `EMPTY` to `PARKED` and from +//! `NOTIFIED` to `EMPTY`. If the state was `NOTIFIED`, the thread was unparked and +//! execution can continue without calling into the OS. If the state was `EMPTY`, +//! the token is not available and the thread waits on the primitive (here called +//! "wait flag"). +//! +//! `unpark` changes the state to `NOTIFIED`. If the state was `PARKED`, the thread +//! is or will be sleeping on the wait flag, so we raise it. + +use crate::pin::Pin; +use crate::sync::atomic::AtomicI8; +use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; +use crate::sys::wait_flag::WaitFlag; +use crate::time::Duration; + +const EMPTY: i8 = 0; +const PARKED: i8 = -1; +const NOTIFIED: i8 = 1; + +pub struct Parker { + state: AtomicI8, + wait_flag: WaitFlag, +} + +impl Parker { + /// Construct a parker for the current thread. The UNIX parker + /// implementation requires this to happen in-place. + pub unsafe fn new(parker: *mut Parker) { + parker.write(Parker { state: AtomicI8::new(EMPTY), wait_flag: WaitFlag::new() }) + } + + // This implementation doesn't require `unsafe` and `Pin`, but other implementations do. + pub unsafe fn park(self: Pin<&Self>) { + match self.state.fetch_sub(1, Acquire) { + // NOTIFIED => EMPTY + NOTIFIED => return, + // EMPTY => PARKED + EMPTY => (), + _ => panic!("inconsistent park state"), + } + + // Avoid waking up from spurious wakeups (these are quite likely, see below). + loop { + self.wait_flag.wait(); + + match self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed) { + Ok(_) => return, + Err(PARKED) => (), + Err(_) => panic!("inconsistent park state"), + } + } + } + + // This implementation doesn't require `unsafe` and `Pin`, but other implementations do. + pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) { + match self.state.fetch_sub(1, Acquire) { + NOTIFIED => return, + EMPTY => (), + _ => panic!("inconsistent park state"), + } + + self.wait_flag.wait_timeout(dur); + + // Either a wakeup or a timeout occurred. Wakeups may be spurious, as there can be + // a race condition when `unpark` is performed between receiving the timeout and + // resetting the state, resulting in the eventflag being set unnecessarily. `park` + // is protected against this by looping until the token is actually given, but + // here we cannot easily tell. + + // Use `swap` to provide acquire ordering. + match self.state.swap(EMPTY, Acquire) { + NOTIFIED => (), + PARKED => (), + _ => panic!("inconsistent park state"), + } + } + + // This implementation doesn't require `Pin`, but other implementations do. + pub fn unpark(self: Pin<&Self>) { + let state = self.state.swap(NOTIFIED, Release); + + if state == PARKED { + self.wait_flag.raise(); + } + } +} diff --git a/library/std/src/time.rs b/library/std/src/time.rs index b2014f462bd34..759a59e1f98d2 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -38,7 +38,7 @@ use crate::error::Error; use crate::fmt; use crate::ops::{Add, AddAssign, Sub, SubAssign}; use crate::sys::time; -use crate::sys_common::FromInner; +use crate::sys_common::{FromInner, IntoInner}; #[stable(feature = "time", since = "1.3.0")] pub use core::time::Duration; @@ -686,3 +686,9 @@ impl FromInner for SystemTime { SystemTime(time) } } + +impl IntoInner for SystemTime { + fn into_inner(self) -> time::SystemTime { + self.0 + } +} diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index b4b7790eebba1..5d0756d30fb53 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -983,42 +983,51 @@ table, font-weight: normal; } -body.blur > :not(#help) { - filter: blur(8px); - -webkit-filter: blur(8px); - opacity: .7; +.popover { + font-size: 1rem; + position: absolute; + right: 0; + z-index: 2; + display: block; + margin-top: 7px; + border-radius: 3px; + border: 1px solid; + font-size: 1rem; } -#help { - width: 100%; - height: 100vh; - position: fixed; - top: 0; - left: 0; - display: flex; - justify-content: center; - align-items: center; +/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */ +.popover::before { + content: ''; + position: absolute; + right: 11px; + border: solid; + border-width: 1px 1px 0 0; + display: inline-block; + padding: 4px; + transform: rotate(-45deg); + top: -5px; } -#help > div { - flex: 0 0 auto; - box-shadow: 0 0 6px rgba(0,0,0,.2); - width: 550px; - height: auto; - border: 1px solid; + +#help-button .popover { + max-width: 600px; } -#help dt { + +#help-button .popover::before { + right: 48px; +} + +#help-button dt { float: left; clear: left; display: block; margin-right: 0.5rem; } -#help span.top, #help span.bottom { +#help-button span.top, #help-button span.bottom { text-align: center; display: block; font-size: 1.125rem; - } -#help span.top { +#help-button span.top { text-align: center; display: block; margin: 10px 0; @@ -1026,17 +1035,17 @@ body.blur > :not(#help) { padding-bottom: 4px; margin-bottom: 6px; } -#help span.bottom { +#help-button span.bottom { clear: both; border-top: 1px solid; } -#help dd { margin: 5px 35px; } -#help .infos { padding-left: 0; } -#help h1, #help h2 { margin-top: 0; } -#help > div div { +.side-by-side { + text-align: initial; +} +.side-by-side > div { width: 50%; float: left; - padding: 0 20px 20px 17px;; + padding: 0 20px 20px 17px; } .item-info .stab { @@ -1391,7 +1400,7 @@ pre.rust { #copy-path { height: 34px; } -#settings-menu > a, #help-button, #copy-path { +#settings-menu > a, #help-button > button, #copy-path { padding: 5px; width: 33px; border: 1px solid; @@ -1401,9 +1410,8 @@ pre.rust { #settings-menu { padding: 0; } -#settings-menu > a { +#settings-menu > a, #help-button > button { padding: 5px; - width: 100%; height: 100%; display: block; } @@ -1420,7 +1428,7 @@ pre.rust { animation: rotating 2s linear infinite; } -#help-button { +#help-button > button { font-family: "Fira Sans", Arial, sans-serif; text-align: center; /* Rare exception to specifying font sizes in rem. Since this is acting diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index 1cd8e39e03648..e531e6ce6bbde 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -86,27 +86,6 @@ input:checked + .slider:before { display: block; } -div#settings { - position: absolute; - right: 0; - z-index: 1; - display: block; - margin-top: 7px; - border-radius: 3px; - border: 1px solid; -} #settings .setting-line { margin: 1.2em 0.6em; } -/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */ -div#settings::before { - content: ''; - position: absolute; - right: 11px; - border: solid; - border-width: 1px 1px 0 0; - display: inline-block; - padding: 4px; - transform: rotate(-45deg); - top: -5px; -} diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 8e0521d9ad6a1..d27294657192c 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -5,7 +5,7 @@ Original by Dempfi (https://github.com/dempfi/ayu) /* General structure and fonts */ -body, #settings-menu #settings, #settings-menu #settings::before { +body, .popover, .popover::before { background-color: #0f1419; color: #c5c5c5; } @@ -567,7 +567,7 @@ kbd { box-shadow: inset 0 -1px 0 #5c6773; } -#settings-menu > a, #help-button { +#settings-menu > a, #help-button > button { border-color: #5c6773; background-color: #0f1419; color: #fff; @@ -577,7 +577,8 @@ kbd { filter: invert(100); } -#settings-menu #settings, #settings-menu #settings::before { +.popover, .popover::before, +#help-button span.top, #help-button span.bottom { border-color: #5c6773; } @@ -592,7 +593,7 @@ kbd { } #settings-menu > a:hover, #settings-menu > a:focus, -#help-button:hover, #help-button:focus { +#help-button > button:hover, #help-button > button:focus { border-color: #e0e0e0; } diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index 071ad006ed350..48079ea2f3041 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -1,4 +1,4 @@ -body, #settings-menu #settings, #settings-menu #settings::before { +body, .popover, .popover::before { background-color: #353535; color: #ddd; } @@ -442,18 +442,19 @@ kbd { box-shadow: inset 0 -1px 0 #c6cbd1; } -#settings-menu > a, #help-button { +#settings-menu > a, #help-button > button { border-color: #e0e0e0; background: #f0f0f0; color: #000; } #settings-menu > a:hover, #settings-menu > a:focus, -#help-button:hover, #help-button:focus { +#help-button > button:hover, #help-button > button:focus { border-color: #ffb900; } -#settings-menu #settings, #settings-menu #settings::before { +.popover, .popover::before, +#help-button span.top, #help-button span.bottom { border-color: #d2d2d2; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 5c3789bf4630a..f4016be967963 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -1,6 +1,6 @@ /* General structure and fonts */ -body, #settings-menu #settings, #settings-menu #settings::before { +body, .popover, .popover::before { background-color: white; color: black; } @@ -427,17 +427,18 @@ kbd { box-shadow: inset 0 -1px 0 #c6cbd1; } -#settings-menu > a, #help-button { +#settings-menu > a, #help-button > button { border-color: #e0e0e0; background-color: #fff; } #settings-menu > a:hover, #settings-menu > a:focus, -#help-button:hover, #help-button:focus { +#help-button > button:hover, #help-button > button:focus { border-color: #717171; } -#settings-menu #settings, #settings-menu #settings::before { +.popover, .popover::before, +#help-button span.top, #help-button span.bottom { border-color: #DDDDDD; } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index b320db9104612..70dbfd4442540 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -63,6 +63,24 @@ function showMain() { removeClass(document.getElementById(MAIN_ID), "hidden"); } +function elemIsInParent(elem, parent) { + while (elem && elem !== document.body) { + if (elem === parent) { + return true; + } + elem = elem.parentElement; + } + return false; +} + +function blurHandler(event, parentElem, hideCallback) { + if (!elemIsInParent(document.activeElement, parentElem) && + !elemIsInParent(event.relatedTarget, parentElem) + ) { + hideCallback(); + } +} + (function() { window.rootPath = getVar("root-path"); window.currentCrate = getVar("current-crate"); @@ -104,20 +122,21 @@ const MAIN_ID = "main-content"; const SETTINGS_BUTTON_ID = "settings-menu"; const ALTERNATIVE_DISPLAY_ID = "alternative-display"; const NOT_DISPLAYED_ID = "not-displayed"; +const HELP_BUTTON_ID = "help-button"; function getSettingsButton() { return document.getElementById(SETTINGS_BUTTON_ID); } +function getHelpButton() { + return document.getElementById(HELP_BUTTON_ID); +} + // Returns the current URL without any query parameter or hash. function getNakedUrl() { return window.location.href.split("?")[0].split("#")[0]; } -window.hideSettings = () => { - // Does nothing by default. -}; - /** * This function inserts `newNode` after `referenceNode`. It doesn't work if `referenceNode` * doesn't have a parent node. @@ -381,55 +400,16 @@ function loadCss(cssFileName) { openParentDetails(document.getElementById(id)); } - function getHelpElement(build) { - if (build) { - buildHelperPopup(); - } - return document.getElementById("help"); - } - - /** - * Show the help popup. - * - * @param {boolean} display - Whether to show or hide the popup - * @param {Event} ev - The event that triggered this call - * @param {Element} [help] - The help element if it already exists - */ - function displayHelp(display, ev, help) { - if (display) { - help = help ? help : getHelpElement(true); - if (hasClass(help, "hidden")) { - ev.preventDefault(); - removeClass(help, "hidden"); - addClass(document.body, "blur"); - } - } else { - // No need to build the help popup if we want to hide it in case it hasn't been - // built yet... - help = help ? help : getHelpElement(false); - if (help && !hasClass(help, "hidden")) { - ev.preventDefault(); - addClass(help, "hidden"); - removeClass(document.body, "blur"); - } - } - } - function handleEscape(ev) { searchState.clearInputTimeout(); - const help = getHelpElement(false); - if (help && !hasClass(help, "hidden")) { - displayHelp(false, ev, help); - } else { - switchDisplayedElement(null); - if (browserSupportsHistoryApi()) { - history.replaceState(null, window.currentCrate + " - Rust", - getNakedUrl() + window.location.hash); - } - ev.preventDefault(); + switchDisplayedElement(null); + if (browserSupportsHistoryApi()) { + history.replaceState(null, window.currentCrate + " - Rust", + getNakedUrl() + window.location.hash); } + ev.preventDefault(); searchState.defocus(); - window.hideSettings(); + window.hidePopoverMenus(); } const disableShortcuts = getSettingValue("disable-shortcuts") === "true"; @@ -453,7 +433,6 @@ function loadCss(cssFileName) { case "s": case "S": - displayHelp(false, ev); ev.preventDefault(); searchState.focus(); break; @@ -465,7 +444,7 @@ function loadCss(cssFileName) { break; case "?": - displayHelp(true, ev); + showHelp(); break; default: @@ -796,9 +775,6 @@ function loadCss(cssFileName) { elem.addEventListener("click", f); } } - handleClick("help-button", ev => { - displayHelp(true, ev); - }); handleClick(MAIN_ID, () => { hideSidebar(); }); @@ -842,24 +818,16 @@ function loadCss(cssFileName) { }); } - let buildHelperPopup = () => { - const popup = document.createElement("aside"); - addClass(popup, "hidden"); - popup.id = "help"; - - popup.addEventListener("click", ev => { - if (ev.target === popup) { - // Clicked the blurred zone outside the help popup; dismiss help. - displayHelp(false, ev); - } - }); + function helpBlurHandler(event) { + blurHandler(event, getHelpButton(), window.hidePopoverMenus); + } + function buildHelpMenu() { const book_info = document.createElement("span"); book_info.className = "top"; book_info.innerHTML = "You can find more information in \ the rustdoc book."; - const container = document.createElement("div"); const shortcuts = [ ["?", "Show this help dialog"], ["S", "Focus the search field"], @@ -895,24 +863,85 @@ function loadCss(cssFileName) { addClass(div_infos, "infos"); div_infos.innerHTML = "

Search Tricks

" + infos; - container.appendChild(book_info); - container.appendChild(div_shortcuts); - container.appendChild(div_infos); - const rustdoc_version = document.createElement("span"); rustdoc_version.className = "bottom"; const rustdoc_version_code = document.createElement("code"); rustdoc_version_code.innerText = "rustdoc " + getVar("rustdoc-version"); rustdoc_version.appendChild(rustdoc_version_code); + const container = document.createElement("div"); + container.className = "popover"; + container.style.display = "none"; + + const side_by_side = document.createElement("div"); + side_by_side.className = "side-by-side"; + side_by_side.appendChild(div_shortcuts); + side_by_side.appendChild(div_infos); + + container.appendChild(book_info); + container.appendChild(side_by_side); container.appendChild(rustdoc_version); - popup.appendChild(container); - insertAfter(popup, document.querySelector("main")); - // So that it's only built once and then it'll do nothing when called! - buildHelperPopup = () => {}; + const help_button = getHelpButton(); + help_button.appendChild(container); + + container.onblur = helpBlurHandler; + container.onclick = event => { + event.preventDefault(); + }; + help_button.onblur = helpBlurHandler; + help_button.children[0].onblur = helpBlurHandler; + + return container; + } + + /** + * Hide all the popover menus. + */ + window.hidePopoverMenus = function() { + onEachLazy(document.querySelectorAll(".search-container .popover"), elem => { + elem.style.display = "none"; + }); }; + /** + * Returns the help menu element (not the button). + * + * @param {boolean} buildNeeded - If this argument is `false`, the help menu element won't be + * built if it doesn't exist. + * + * @return {HTMLElement} + */ + function getHelpMenu(buildNeeded) { + let menu = getHelpButton().querySelector(".popover"); + if (!menu && buildNeeded) { + menu = buildHelpMenu(); + } + return menu; + } + + /** + * Show the help popup menu. + */ + function showHelp() { + const menu = getHelpMenu(true); + if (menu.style.display === "none") { + menu.style.display = ""; + } + } + + document.querySelector(`#${HELP_BUTTON_ID} > button`).addEventListener("click", event => { + const target = event.target; + if (target.tagName !== "BUTTON" || target.parentElement.id !== HELP_BUTTON_ID) { + return; + } + const menu = getHelpMenu(true); + const shouldShowHelp = menu.style.display === "none"; + if (shouldShowHelp) { + showHelp(); + } + }); + setMobileTopbar(); addSidebarItems(); addSidebarCrates(); diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 41bf0ec895580..797b931afc643 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -1,6 +1,6 @@ // Local js definitions: /* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */ -/* global addClass, removeClass, onEach, onEachLazy */ +/* global addClass, removeClass, onEach, onEachLazy, blurHandler, elemIsInParent */ /* global MAIN_ID, getVar, getSettingsButton */ "use strict"; @@ -209,6 +209,7 @@ const innerHTML = `
${buildSettingsPageSections(settings)}
`; const el = document.createElement(elementKind); el.id = "settings"; + el.className = "popover"; el.innerHTML = innerHTML; if (isSettingsPage) { @@ -226,23 +227,8 @@ settingsMenu.style.display = ""; } - function elemIsInParent(elem, parent) { - while (elem && elem !== document.body) { - if (elem === parent) { - return true; - } - elem = elem.parentElement; - } - return false; - } - - function blurHandler(event) { - const settingsButton = getSettingsButton(); - if (!elemIsInParent(document.activeElement, settingsButton) && - !elemIsInParent(event.relatedTarget, settingsButton) - ) { - window.hideSettings(); - } + function settingsBlurHandler(event) { + blurHandler(event, getSettingsButton(), window.hidePopoverMenus); } if (isSettingsPage) { @@ -254,26 +240,24 @@ // We replace the existing "onclick" callback. const settingsButton = getSettingsButton(); const settingsMenu = document.getElementById("settings"); - window.hideSettings = function() { - settingsMenu.style.display = "none"; - }; settingsButton.onclick = function(event) { if (elemIsInParent(event.target, settingsMenu)) { return; } event.preventDefault(); - if (settingsMenu.style.display !== "none") { - window.hideSettings(); - } else { + const shouldDisplaySettings = settingsMenu.style.display === "none"; + + window.hidePopoverMenus(); + if (shouldDisplaySettings) { displaySettings(); } }; - settingsButton.onblur = blurHandler; - settingsButton.querySelector("a").onblur = blurHandler; + settingsButton.onblur = settingsBlurHandler; + settingsButton.querySelector("a").onblur = settingsBlurHandler; onEachLazy(settingsMenu.querySelectorAll("input"), el => { - el.onblur = blurHandler; + el.onblur = settingsBlurHandler; }); - settingsMenu.onblur = blurHandler; + settingsMenu.onblur = settingsBlurHandler; } // We now wait a bit for the web browser to end re-computing the DOM... diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index c4999e2c74fce..dfb3e4e6a2ccd 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -119,7 +119,9 @@

spellcheck="false" {# -#} placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#} type="search"> {#- -#} - {#- -#} +
{#- -#} + {#- -#} +
{#- -#}
{#- -#} Change settings bb2; // scope 1 at $DIR/derefer_complex_case.rs:4:5: 4:40 - } - - bb8 (cleanup): { - resume; // scope 0 at $DIR/derefer_complex_case.rs:3:1: 5:2 ++ } ++ ++ bb8 (cleanup): { ++ resume; // scope 0 at $DIR/derefer_complex_case.rs:3:1: 5:2 } } diff --git a/src/test/mir-opt/derefer_inline_test.main.Derefer.diff b/src/test/mir-opt/derefer_inline_test.main.Derefer.diff index e131adae2b683..b9bf710d3fdf3 100644 --- a/src/test/mir-opt/derefer_inline_test.main.Derefer.diff +++ b/src/test/mir-opt/derefer_inline_test.main.Derefer.diff @@ -8,7 +8,6 @@ let mut _3: usize; // in scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 let mut _4: *mut u8; // in scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 let mut _5: std::boxed::Box>; // in scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 - let mut _6: (); // in scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 scope 1 { } @@ -25,7 +24,7 @@ bb1: { StorageLive(_5); // scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 _5 = ShallowInitBox(move _4, std::boxed::Box); // scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 - (*_5) = f() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/derefer_inline_test.rs:10:9: 10:12 + (*_5) = f() -> [return: bb2, unwind: bb6]; // scope 0 at $DIR/derefer_inline_test.rs:10:9: 10:12 // mir::Constant // + span: $DIR/derefer_inline_test.rs:10:9: 10:10 // + literal: Const { ty: fn() -> Box {f}, val: Value(Scalar()) } @@ -33,12 +32,12 @@ bb2: { _1 = move _5; // scope 0 at $DIR/derefer_inline_test.rs:10:5: 10:12 - goto -> bb3; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 + drop(_5) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 } bb3: { StorageDead(_5); // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 - drop(_1) -> [return: bb4, unwind: bb6]; // scope 0 at $DIR/derefer_inline_test.rs:10:12: 10:13 + drop(_1) -> bb4; // scope 0 at $DIR/derefer_inline_test.rs:10:12: 10:13 } bb4: { @@ -48,22 +47,15 @@ } bb5 (cleanup): { - goto -> bb8; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 + drop(_1) -> bb7; // scope 0 at $DIR/derefer_inline_test.rs:10:12: 10:13 } bb6 (cleanup): { - resume; // scope 0 at $DIR/derefer_inline_test.rs:9:1: 11:2 + drop(_5) -> bb7; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 } bb7 (cleanup): { - _6 = alloc::alloc::box_free::, std::alloc::Global>(move (_5.0: std::ptr::Unique>), move (_5.1: std::alloc::Global)) -> bb6; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 - // mir::Constant - // + span: $DIR/derefer_inline_test.rs:10:11: 10:12 - // + literal: Const { ty: unsafe fn(Unique>, std::alloc::Global) {alloc::alloc::box_free::, std::alloc::Global>}, val: Value(Scalar()) } - } - - bb8 (cleanup): { - goto -> bb7; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12 + resume; // scope 0 at $DIR/derefer_inline_test.rs:9:1: 11:2 } } diff --git a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff index 8b91a65bf3d7d..cfa3eb3f2d78b 100644 --- a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff +++ b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff @@ -56,12 +56,12 @@ _4 = &_5; // scope 2 at $DIR/derefer_terminator_test.rs:5:15: 5:22 - switchInt((*(*(*(*_4))))) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 + StorageLive(_10); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 -+ _10 = move (*_4); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 ++ _10 = virt (*_4); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 + StorageLive(_11); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 -+ _11 = move (*_10); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 ++ _11 = virt (*_10); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 + StorageDead(_10); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 + StorageLive(_12); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 -+ _12 = move (*_11); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 ++ _12 = virt (*_11); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 + StorageDead(_11); // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 + switchInt((*_12)) -> [false: bb3, otherwise: bb4]; // scope 2 at $DIR/derefer_terminator_test.rs:5:5: 5:22 } @@ -94,10 +94,10 @@ StorageDead(_2); // scope 1 at $DIR/derefer_terminator_test.rs:10:1: 10:2 StorageDead(_1); // scope 0 at $DIR/derefer_terminator_test.rs:10:1: 10:2 return; // scope 0 at $DIR/derefer_terminator_test.rs:10:2: 10:2 - } - - bb6 (cleanup): { - resume; // scope 0 at $DIR/derefer_terminator_test.rs:2:1: 10:2 ++ } ++ ++ bb6 (cleanup): { ++ resume; // scope 0 at $DIR/derefer_terminator_test.rs:2:1: 10:2 } } diff --git a/src/test/mir-opt/derefer_test.main.Derefer.diff b/src/test/mir-opt/derefer_test.main.Derefer.diff index 84476aeed7a6c..589fc4210fc24 100644 --- a/src/test/mir-opt/derefer_test.main.Derefer.diff +++ b/src/test/mir-opt/derefer_test.main.Derefer.diff @@ -34,13 +34,13 @@ StorageLive(_4); // scope 2 at $DIR/derefer_test.rs:5:9: 5:10 - _4 = &mut ((*(_2.1: &mut (i32, i32))).0: i32); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 + StorageLive(_6); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 -+ _6 = move (_2.1: &mut (i32, i32)); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 ++ _6 = virt (_2.1: &mut (i32, i32)); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 + _4 = &mut ((*_6).0: i32); // scope 2 at $DIR/derefer_test.rs:5:13: 5:26 + StorageDead(_6); // scope 3 at $DIR/derefer_test.rs:6:9: 6:10 StorageLive(_5); // scope 3 at $DIR/derefer_test.rs:6:9: 6:10 - _5 = &mut ((*(_2.1: &mut (i32, i32))).1: i32); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 + StorageLive(_7); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 -+ _7 = move (_2.1: &mut (i32, i32)); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 ++ _7 = virt (_2.1: &mut (i32, i32)); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 + _5 = &mut ((*_7).1: i32); // scope 3 at $DIR/derefer_test.rs:6:13: 6:26 + StorageDead(_7); // scope 0 at $DIR/derefer_test.rs:2:11: 7:2 _0 = const (); // scope 0 at $DIR/derefer_test.rs:2:11: 7:2 @@ -49,10 +49,10 @@ StorageDead(_2); // scope 1 at $DIR/derefer_test.rs:7:1: 7:2 StorageDead(_1); // scope 0 at $DIR/derefer_test.rs:7:1: 7:2 return; // scope 0 at $DIR/derefer_test.rs:7:2: 7:2 - } - - bb1 (cleanup): { - resume; // scope 0 at $DIR/derefer_test.rs:2:1: 7:2 ++ } ++ ++ bb1 (cleanup): { ++ resume; // scope 0 at $DIR/derefer_test.rs:2:1: 7:2 } } diff --git a/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff index b8e5a0c328f4d..79734a45dc476 100644 --- a/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff +++ b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff @@ -58,24 +58,24 @@ StorageLive(_8); // scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10 - _8 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 + StorageLive(_10); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 -+ _10 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _10 = virt (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 + StorageLive(_11); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 -+ _11 = move ((*_10).1: &mut (i32, &mut (i32, i32))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _11 = virt ((*_10).1: &mut (i32, &mut (i32, i32))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 + StorageDead(_10); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 + StorageLive(_12); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 -+ _12 = move ((*_11).1: &mut (i32, i32)); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _12 = virt ((*_11).1: &mut (i32, i32)); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 + StorageDead(_11); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 + _8 = &mut ((*_12).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 + StorageDead(_12); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 StorageLive(_9); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 - _9 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + StorageLive(_13); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 -+ _13 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _13 = virt (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + StorageLive(_14); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 -+ _14 = move ((*_13).1: &mut (i32, &mut (i32, i32))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _14 = virt ((*_13).1: &mut (i32, &mut (i32, i32))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + StorageDead(_13); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + StorageLive(_15); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 -+ _15 = move ((*_14).1: &mut (i32, i32)); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _15 = virt ((*_14).1: &mut (i32, i32)); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + StorageDead(_14); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + _9 = &mut ((*_15).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + StorageDead(_15); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2 @@ -87,10 +87,10 @@ StorageDead(_2); // scope 1 at $DIR/derefer_test_multiple.rs:9:1: 9:2 StorageDead(_1); // scope 0 at $DIR/derefer_test_multiple.rs:9:1: 9:2 return; // scope 0 at $DIR/derefer_test_multiple.rs:9:2: 9:2 - } - - bb1 (cleanup): { - resume; // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2 ++ } ++ ++ bb1 (cleanup): { ++ resume; // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2 } } diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff index 67ce0c2aabb1c..9cbc5a4233e93 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff @@ -93,7 +93,7 @@ - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24 StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _34 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _34 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _11 = discriminant((*_34)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -101,7 +101,7 @@ bb1: { StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _35 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _35 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _7 = discriminant((*_35)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -123,7 +123,7 @@ bb3: { StorageLive(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _36 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _36 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _8 = discriminant((*_36)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -131,7 +131,7 @@ bb4: { StorageLive(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _37 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _37 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _9 = discriminant((*_37)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -139,7 +139,7 @@ bb5: { StorageLive(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _38 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _38 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _10 = discriminant((*_38)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -149,14 +149,14 @@ - StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 StorageLive(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 - _39 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + _39 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 - _12 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + _15 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 StorageDead(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 - StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 StorageLive(_40); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 - _40 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + _40 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 - _13 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + _16 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 StorageDead(_40); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 @@ -195,14 +195,14 @@ - StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 StorageLive(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 - _41 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + _41 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 - _17 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + _20 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 StorageDead(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 - StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 StorageLive(_42); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 - _42 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + _42 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 - _18 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + _21 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 StorageDead(_42); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 @@ -241,14 +241,14 @@ - StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 StorageLive(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 - _43 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + _43 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 - _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + _25 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 StorageDead(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 - StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 StorageLive(_44); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 - _44 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + _44 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 - _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + _26 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 StorageDead(_44); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 @@ -287,14 +287,14 @@ - StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 StorageLive(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 - _45 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + _45 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 - _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + _30 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 StorageDead(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 - StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 StorageLive(_46); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 - _46 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + _46 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 - _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + _31 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 StorageDead(_46); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff index c2b00f915a4eb..e52d2865179e5 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -79,7 +79,7 @@ StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24 StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24 StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _34 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _34 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _11 = discriminant((*_34)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -87,7 +87,7 @@ bb1: { StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _35 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _35 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _7 = discriminant((*_35)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -107,7 +107,7 @@ bb3: { StorageLive(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _36 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _36 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _8 = discriminant((*_36)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_36); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -115,7 +115,7 @@ bb4: { StorageLive(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _37 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _37 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _9 = discriminant((*_37)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_37); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -123,7 +123,7 @@ bb5: { StorageLive(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 - _38 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 + _38 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 _10 = discriminant((*_38)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24 StorageDead(_38); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 @@ -132,12 +132,12 @@ bb6: { StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 StorageLive(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 - _39 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 + _39 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 _12 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 StorageDead(_39); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 StorageLive(_40); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 - _40 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 + _40 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 _13 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 StorageDead(_40); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49 @@ -160,12 +160,12 @@ bb7: { StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 StorageLive(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 - _41 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + _41 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 _17 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 StorageDead(_41); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 StorageLive(_42); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 - _42 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + _42 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 _18 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 StorageDead(_42); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 @@ -188,12 +188,12 @@ bb8: { StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 StorageLive(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 - _43 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 + _43 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:16: 24:19 StorageDead(_43); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 StorageLive(_44); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 - _44 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 + _44 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:28: 24:33 StorageDead(_44); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55 @@ -216,12 +216,12 @@ bb9: { StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 StorageLive(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 - _45 = move (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + _45 = virt (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 StorageDead(_45); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 StorageLive(_46); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 - _46 = move (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + _46 = virt (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 StorageDead(_46); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff index 982dd7a27bc6b..e40ef981a4e8c 100644 --- a/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff @@ -17,7 +17,7 @@ bb1: { StorageLive(_4); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 - _4 = move (((*_1) as Some).0: &E); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 + _4 = virt (((*_1) as Some).0: &E); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 _2 = discriminant((*_4)); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 StorageDead(_4); // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 switchInt(move _2) -> [1_isize: bb2, otherwise: bb3]; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir index c6b49b66dc5c0..80d8d3b1c7b96 100644 --- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir @@ -46,12 +46,12 @@ fn foo(_1: T, _2: i32) -> (i32, T) { _9 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 StorageLive(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 StorageLive(_12); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 - _12 = move ((*_6).0: &i32); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 + _12 = virt ((*_6).0: &i32); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 _10 = (*_12); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 StorageDead(_12); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 StorageLive(_11); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 StorageLive(_13); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 - _13 = move ((*_6).1: &T); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 + _13 = virt ((*_6).1: &T); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 _11 = (*_13); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 StorageDead(_13); // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 Deinit(_0); // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 diff --git a/src/test/mir-opt/inline/inline_generator.main.Inline.diff b/src/test/mir-opt/inline/inline_generator.main.Inline.diff index 3e1c4a4670143..51c2688da4709 100644 --- a/src/test/mir-opt/inline/inline_generator.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_generator.main.Inline.diff @@ -77,7 +77,7 @@ + StorageLive(_11); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 + StorageLive(_12); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 + StorageLive(_13); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 -+ _13 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 ++ _13 = virt (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 + _12 = discriminant((*_13)); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 + StorageDead(_13); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 + switchInt(move _12) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41 @@ -125,7 +125,7 @@ + ((_1 as Yielded).0: i32) = move _8; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 + discriminant(_1) = 0; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 + StorageLive(_14); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 -+ _14 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 ++ _14 = virt (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 + discriminant((*_14)) = 3; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 + StorageDead(_14); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39 + goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:11: 15:39 @@ -139,7 +139,7 @@ + ((_1 as Complete).0: bool) = move _10; // scope 6 at $DIR/inline-generator.rs:15:41: 15:41 + discriminant(_1) = 1; // scope 6 at $DIR/inline-generator.rs:15:41: 15:41 + StorageLive(_15); // scope 6 at $DIR/inline-generator.rs:15:41: 15:41 -+ _15 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:41: 15:41 ++ _15 = virt (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:41: 15:41 + discriminant((*_15)) = 1; // scope 6 at $DIR/inline-generator.rs:15:41: 15:41 + StorageDead(_15); // scope 6 at $DIR/inline-generator.rs:15:41: 15:41 + goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:41: 15:41 diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir index 11a205eb41580..a0b23b43ef467 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir @@ -22,7 +22,7 @@ fn b(_1: &mut Box) -> &mut T { StorageLive(_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageLive(_6); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageLive(_7); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - _7 = move (*_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _7 = virt (*_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageLive(_8); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL _8 = (((_7.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const T); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL _6 = &mut (*_8); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir index b04a91d7c9590..91acf2d2c5c4e 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir @@ -16,7 +16,7 @@ fn d(_1: &Box) -> &T { StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 StorageLive(_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - _4 = move (*_3); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _4 = virt (*_3); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL StorageLive(_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL _5 = (((_4.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const T); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL _2 = &(*_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/src/test/rustdoc-gui/escape-key.goml b/src/test/rustdoc-gui/escape-key.goml index 8713bf65c8432..d083b0ae0c931 100644 --- a/src/test/rustdoc-gui/escape-key.goml +++ b/src/test/rustdoc-gui/escape-key.goml @@ -21,17 +21,6 @@ wait-for: "#alternative-display #search" assert-attribute: ("#main-content", {"class": "content hidden"}) assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH) -// Now let's check that when the help popup is displayed and we press Escape, it doesn't -// hide the search results too. -click: "#help-button" -assert-document-property: ({"URL": "index.html?search=test"}, [ENDS_WITH]) -assert-attribute: ("#help", {"class": ""}) -press-key: "Escape" -wait-for: "#alternative-display #search" -assert-attribute: ("#help", {"class": "hidden"}) -assert-attribute: ("#main-content", {"class": "content hidden"}) -assert-document-property: ({"URL": "index.html?search=test"}, [ENDS_WITH]) - // Check that Escape hides the search results when a search result is focused. focus: ".search-input" assert: ".search-input:focus" @@ -39,7 +28,6 @@ press-key: "ArrowDown" assert-false: ".search-input:focus" assert: "#results a:focus" press-key: "Escape" -assert-attribute: ("#help", {"class": "hidden"}) wait-for: "#not-displayed #search" assert-false: "#alternative-display #search" assert-attribute: ("#main-content", {"class": "content"}) diff --git a/src/test/rustdoc-gui/pocket-menu.goml b/src/test/rustdoc-gui/pocket-menu.goml new file mode 100644 index 0000000000000..ba2986e969a35 --- /dev/null +++ b/src/test/rustdoc-gui/pocket-menu.goml @@ -0,0 +1,72 @@ +// This test ensures that the "pocket menus" are working as expected. +goto: file://|DOC_PATH|/test_docs/index.html +// First we check that the help menu doesn't exist yet. +assert-false: "#help-button .popover" +// Then we display the help menu. +click: "#help-button" +assert: "#help-button .popover" +assert-css: ("#help-button .popover", {"display": "block"}) + +// Now we click somewhere else on the page to ensure it is handling the blur event +// correctly. +click: ".sidebar" +assert-css: ("#help-button .popover", {"display": "none"}) + +// Now we will check that we cannot have two "pocket menus" displayed at the same time. +click: "#help-button" +assert-css: ("#help-button .popover", {"display": "block"}) +click: "#settings-menu" +assert-css: ("#help-button .popover", {"display": "none"}) +assert-css: ("#settings-menu .popover", {"display": "block"}) + +// Now the other way. +click: "#help-button" +assert-css: ("#help-button .popover", {"display": "block"}) +assert-css: ("#settings-menu .popover", {"display": "none"}) + +// We check the borders color now: + +// Ayu theme +local-storage: { + "rustdoc-theme": "ayu", + "rustdoc-use-system-theme": "false", +} +reload: + +click: "#help-button" +assert-css: ( + "#help-button .popover", + {"display": "block", "border-color": "rgb(92, 103, 115)"}, +) +compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"]) +compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) + +// Dark theme +local-storage: { + "rustdoc-theme": "dark", + "rustdoc-use-system-theme": "false", +} +reload: + +click: "#help-button" +assert-css: ( + "#help-button .popover", + {"display": "block", "border-color": "rgb(210, 210, 210)"}, +) +compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"]) +compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) + +// Light theme +local-storage: { + "rustdoc-theme": "light", + "rustdoc-use-system-theme": "false", +} +reload: + +click: "#help-button" +assert-css: ( + "#help-button .popover", + {"display": "block", "border-color": "rgb(221, 221, 221)"}, +) +compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"]) +compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) diff --git a/src/test/rustdoc-gui/shortcuts.goml b/src/test/rustdoc-gui/shortcuts.goml index 37a7c1662949d..1f20a0eaa9982 100644 --- a/src/test/rustdoc-gui/shortcuts.goml +++ b/src/test/rustdoc-gui/shortcuts.goml @@ -8,7 +8,6 @@ press-key: "Escape" assert-false: "input.search-input:focus" // We now check for the help popup. press-key: "?" -assert-css: ("#help", {"display": "flex"}) -assert-false: "#help.hidden" +assert-css: ("#help-button .popover", {"display": "block"}) press-key: "Escape" -assert-css: ("#help.hidden", {"display": "none"}) +assert-css: ("#help-button .popover", {"display": "none"}) diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.rs b/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.rs deleted file mode 100644 index 1db9d33c72aee..0000000000000 --- a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.rs +++ /dev/null @@ -1,9 +0,0 @@ -// check-pass -// compile-flags: -Z unpretty=expanded - -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] - -fn main() { - let elem = 1i32; - assert!(elem == 1); -} diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.stdout b/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.stdout deleted file mode 100644 index a590eb3223254..0000000000000 --- a/src/test/ui/macros/rfc-2011-nicer-assert-messages/codegen.stdout +++ /dev/null @@ -1,29 +0,0 @@ -#![feature(prelude_import)] -#![no_std] -// check-pass -// compile-flags: -Z unpretty=expanded - -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] -#[prelude_import] -use ::std::prelude::rust_2015::*; -#[macro_use] -extern crate std; - -fn main() { - let elem = 1i32; - { - #[allow(unused_imports)] - use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; - let mut __capture0 = ::core::asserting::Capture::new(); - let __local_bind0 = &elem; - if !(*{ - (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); - __local_bind0 - } == 1) { - { - ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n elem = ", - "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) - } - } - }; -} diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs new file mode 100644 index 0000000000000..5ec84b08ff808 --- /dev/null +++ b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs @@ -0,0 +1,32 @@ +// check-pass +// compile-flags: -Z unpretty=expanded + +#![feature(core_intrinsics, generic_assert, generic_assert_internals)] + +fn arbitrary_consuming_method_for_demonstration_purposes() { + let elem = 1i32; + assert!(elem as usize); +} + +fn addr_of() { + let elem = 1i32; + assert!(&elem); +} + +fn binary() { + let elem = 1i32; + assert!(elem == 1); + assert!(elem >= 1); + assert!(elem > 0); + assert!(elem < 3); + assert!(elem <= 3); + assert!(elem != 3); +} + +fn unary() { + let elem = &1i32; + assert!(*elem); +} + +fn main() { +} diff --git a/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout new file mode 100644 index 0000000000000..90f858f80e6b5 --- /dev/null +++ b/src/test/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout @@ -0,0 +1,147 @@ +#![feature(prelude_import)] +#![no_std] +// check-pass +// compile-flags: -Z unpretty=expanded + +#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; + +fn arbitrary_consuming_method_for_demonstration_purposes() { + let elem = 1i32; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*{ + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + __local_bind0 + } as usize)) { + + + + + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem as usize\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; +} +fn addr_of() { + let elem = 1i32; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!&*__local_bind0) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: &elem\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; +} +fn binary() { + let elem = 1i32; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 == 1)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 >= 1)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem >= 1\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 > 0)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem > 0\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 < 3)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem < 3\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 <= 3)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem <= 3\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!(*__local_bind0 != 3)) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem != 3\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; +} +fn unary() { + let elem = &1i32; + { + #[allow(unused_imports)] + use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable}; + let mut __capture0 = ::core::asserting::Capture::new(); + let __local_bind0 = &elem; + if ::core::intrinsics::unlikely(!**__local_bind0) { + (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); + { + ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: *elem\nWith captures:\n elem = ", + "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)])) + } + } + }; +} +fn main() {} diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 498dcbb89006d..53fa2ccdcc138 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -124,6 +124,7 @@ fn check_rvalue<'tcx>( Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { check_place(tcx, *place, span, body) }, + Rvalue::VirtualRef(place) => check_place(tcx, *place, span, body), Rvalue::Repeat(operand, _) | Rvalue::Use(operand) | Rvalue::Cast(