Auto merge of #104646 - matthiaskrgr:rollup-7xnhzf0, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #104537 (fix std::thread docs are unclear regarding stack sizes) - #104558 (Don't assume `FILE_ID_BOTH_DIR_INFO` will be aligned) - #104564 (interpret: use Either over Result when it is not representing an error condition) - #104568 (clarify that realloc refreshes pointer provenance even when the allocation remains in-place) - #104611 (rustdoc: use real buttons for scrape examples controls) - #104640 (Migrate kdb style to CSS variables) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a28f3c88e5
36 changed files with 291 additions and 145 deletions
|
@ -3433,6 +3433,7 @@ dependencies = [
|
|||
name = "rustc_const_eval"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rustc_apfloat",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
|
@ -3927,6 +3928,7 @@ dependencies = [
|
|||
name = "rustc_mir_build"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
|
@ -3973,6 +3975,7 @@ name = "rustc_mir_transform"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"coverage_test_macros",
|
||||
"either",
|
||||
"itertools",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
|
|
|
@ -7,6 +7,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
tracing = "0.1"
|
||||
either = "1"
|
||||
rustc_apfloat = { path = "../rustc_apfloat" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr};
|
||||
use crate::interpret::eval_nullary_intrinsic;
|
||||
use crate::interpret::{
|
||||
intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId,
|
||||
Immediate, InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy,
|
||||
RefTracking, StackPopCleanup,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use either::{Left, Right};
|
||||
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_middle::mir;
|
||||
|
@ -16,8 +13,14 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
|
|||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_target::abi::{self, Abi};
|
||||
use std::borrow::Cow;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr};
|
||||
use crate::interpret::eval_nullary_intrinsic;
|
||||
use crate::interpret::{
|
||||
intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId,
|
||||
Immediate, InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy,
|
||||
RefTracking, StackPopCleanup,
|
||||
};
|
||||
|
||||
const NOTE_ON_UNDEFINED_BEHAVIOR_ERROR: &str = "The rules on what exactly is undefined behavior aren't clear, \
|
||||
so this check might be overzealous. Please open an issue on the rustc \
|
||||
|
@ -135,14 +138,14 @@ pub(super) fn op_to_const<'tcx>(
|
|||
_ => false,
|
||||
};
|
||||
let immediate = if try_as_immediate {
|
||||
Err(ecx.read_immediate(op).expect("normalization works on validated constants"))
|
||||
Right(ecx.read_immediate(op).expect("normalization works on validated constants"))
|
||||
} else {
|
||||
// It is guaranteed that any non-slice scalar pair is actually ByRef here.
|
||||
// When we come back from raw const eval, we are always by-ref. The only way our op here is
|
||||
// by-val is if we are in destructure_mir_constant, i.e., if this is (a field of) something that we
|
||||
// "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or
|
||||
// structs containing such.
|
||||
op.try_as_mplace()
|
||||
op.as_mplace_or_imm()
|
||||
};
|
||||
|
||||
debug!(?immediate);
|
||||
|
@ -168,9 +171,9 @@ pub(super) fn op_to_const<'tcx>(
|
|||
}
|
||||
};
|
||||
match immediate {
|
||||
Ok(ref mplace) => to_const_value(mplace),
|
||||
Left(ref mplace) => to_const_value(mplace),
|
||||
// see comment on `let try_as_immediate` above
|
||||
Err(imm) => match *imm {
|
||||
Right(imm) => match *imm {
|
||||
_ if imm.layout.is_zst() => ConstValue::ZeroSized,
|
||||
Immediate::Scalar(x) => ConstValue::Scalar(x),
|
||||
Immediate::ScalarPair(a, b) => {
|
||||
|
|
|
@ -2,6 +2,8 @@ use std::cell::Cell;
|
|||
use std::fmt;
|
||||
use std::mem;
|
||||
|
||||
use either::{Either, Left, Right};
|
||||
|
||||
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_middle::mir;
|
||||
|
@ -121,13 +123,12 @@ pub struct Frame<'mir, 'tcx, Prov: Provenance = AllocId, Extra = ()> {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Current position within the function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// If this is `Err`, we are not currently executing any particular statement in
|
||||
/// If this is `Right`, we are not currently executing any particular statement in
|
||||
/// this frame (can happen e.g. during frame initialization, and during unwinding on
|
||||
/// frames without cleanup code).
|
||||
/// We basically abuse `Result` as `Either`.
|
||||
///
|
||||
/// Needs to be public because ConstProp does unspeakable things to it.
|
||||
pub loc: Result<mir::Location, Span>,
|
||||
pub loc: Either<mir::Location, Span>,
|
||||
}
|
||||
|
||||
/// What we store about a frame in an interpreter backtrace.
|
||||
|
@ -227,25 +228,24 @@ impl<'mir, 'tcx, Prov: Provenance> Frame<'mir, 'tcx, Prov> {
|
|||
impl<'mir, 'tcx, Prov: Provenance, Extra> Frame<'mir, 'tcx, Prov, Extra> {
|
||||
/// Get the current location within the Frame.
|
||||
///
|
||||
/// If this is `Err`, we are not currently executing any particular statement in
|
||||
/// If this is `Left`, we are not currently executing any particular statement in
|
||||
/// this frame (can happen e.g. during frame initialization, and during unwinding on
|
||||
/// frames without cleanup code).
|
||||
/// We basically abuse `Result` as `Either`.
|
||||
///
|
||||
/// Used by priroda.
|
||||
pub fn current_loc(&self) -> Result<mir::Location, Span> {
|
||||
pub fn current_loc(&self) -> Either<mir::Location, Span> {
|
||||
self.loc
|
||||
}
|
||||
|
||||
/// Return the `SourceInfo` of the current instruction.
|
||||
pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
|
||||
self.loc.ok().map(|loc| self.body.source_info(loc))
|
||||
self.loc.left().map(|loc| self.body.source_info(loc))
|
||||
}
|
||||
|
||||
pub fn current_span(&self) -> Span {
|
||||
match self.loc {
|
||||
Ok(loc) => self.body.source_info(loc).span,
|
||||
Err(span) => span,
|
||||
Left(loc) => self.body.source_info(loc).span,
|
||||
Right(span) => span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -679,7 +679,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// first push a stack frame so we have access to the local substs
|
||||
let pre_frame = Frame {
|
||||
body,
|
||||
loc: Err(body.span), // Span used for errors caused during preamble.
|
||||
loc: Right(body.span), // Span used for errors caused during preamble.
|
||||
return_to_block,
|
||||
return_place: return_place.clone(),
|
||||
// empty local array, we fill it in below, after we are inside the stack frame and
|
||||
|
@ -713,7 +713,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// done
|
||||
self.frame_mut().locals = locals;
|
||||
M::after_stack_push(self)?;
|
||||
self.frame_mut().loc = Ok(mir::Location::START);
|
||||
self.frame_mut().loc = Left(mir::Location::START);
|
||||
|
||||
let span = info_span!("frame", "{}", instance);
|
||||
self.frame_mut().tracing_span.enter(span);
|
||||
|
@ -724,7 +724,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
/// Jump to the given block.
|
||||
#[inline]
|
||||
pub fn go_to_block(&mut self, target: mir::BasicBlock) {
|
||||
self.frame_mut().loc = Ok(mir::Location { block: target, statement_index: 0 });
|
||||
self.frame_mut().loc = Left(mir::Location { block: target, statement_index: 0 });
|
||||
}
|
||||
|
||||
/// *Return* to the given `target` basic block.
|
||||
|
@ -750,8 +750,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
/// unwinding, and doing so is UB.
|
||||
pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx> {
|
||||
self.frame_mut().loc = match target {
|
||||
StackPopUnwind::Cleanup(block) => Ok(mir::Location { block, statement_index: 0 }),
|
||||
StackPopUnwind::Skip => Err(self.frame_mut().body.span),
|
||||
StackPopUnwind::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }),
|
||||
StackPopUnwind::Skip => Right(self.frame_mut().body.span),
|
||||
StackPopUnwind::NotAllowed => {
|
||||
throw_ub_format!("unwinding past a stack frame that does not allow unwinding")
|
||||
}
|
||||
|
@ -783,8 +783,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
assert_eq!(
|
||||
unwinding,
|
||||
match self.frame().loc {
|
||||
Ok(loc) => self.body().basic_blocks[loc.block].is_cleanup,
|
||||
Err(_) => true,
|
||||
Left(loc) => self.body().basic_blocks[loc.block].is_cleanup,
|
||||
Right(_) => true,
|
||||
}
|
||||
);
|
||||
if unwinding && self.frame_idx() == 0 {
|
||||
|
|
|
@ -19,8 +19,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
debug!("find_closest_untracked_caller_location: checking frame {:?}", frame.instance);
|
||||
|
||||
// Assert that the frame we look at is actually executing code currently
|
||||
// (`loc` is `Err` when we are unwinding and the frame does not require cleanup).
|
||||
let loc = frame.loc.unwrap();
|
||||
// (`loc` is `Right` when we are unwinding and the frame does not require cleanup).
|
||||
let loc = frame.loc.left().unwrap();
|
||||
|
||||
// This could be a non-`Call` terminator (such as `Drop`), or not a terminator at all
|
||||
// (such as `box`). Use the normal span by default.
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
//! Functions concerning immediate values and operands, and reading from operands.
|
||||
//! All high-level functions to read from memory work on operands as sources.
|
||||
|
||||
use either::{Either, Left, Right};
|
||||
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
|
||||
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
|
||||
|
@ -261,9 +263,9 @@ impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> {
|
|||
layout: TyAndLayout<'tcx>,
|
||||
cx: &impl HasDataLayout,
|
||||
) -> InterpResult<'tcx, Self> {
|
||||
match self.try_as_mplace() {
|
||||
Ok(mplace) => Ok(mplace.offset_with_meta(offset, meta, layout, cx)?.into()),
|
||||
Err(imm) => {
|
||||
match self.as_mplace_or_imm() {
|
||||
Left(mplace) => Ok(mplace.offset_with_meta(offset, meta, layout, cx)?.into()),
|
||||
Right(imm) => {
|
||||
assert!(
|
||||
matches!(*imm, Immediate::Uninit),
|
||||
"Scalar/ScalarPair cannot be offset into"
|
||||
|
@ -353,8 +355,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
|
||||
/// Try returning an immediate for the operand. If the layout does not permit loading this as an
|
||||
/// immediate, return where in memory we can find the data.
|
||||
/// Note that for a given layout, this operation will either always fail or always
|
||||
/// succeed! Whether it succeeds depends on whether the layout can be represented
|
||||
/// Note that for a given layout, this operation will either always return Left or Right!
|
||||
/// succeed! Whether it returns Left depends on whether the layout can be represented
|
||||
/// in an `Immediate`, not on which data is stored there currently.
|
||||
///
|
||||
/// This is an internal function that should not usually be used; call `read_immediate` instead.
|
||||
|
@ -362,16 +364,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
pub fn read_immediate_raw(
|
||||
&self,
|
||||
src: &OpTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::Provenance>, MPlaceTy<'tcx, M::Provenance>>> {
|
||||
Ok(match src.try_as_mplace() {
|
||||
Ok(ref mplace) => {
|
||||
) -> InterpResult<'tcx, Either<MPlaceTy<'tcx, M::Provenance>, ImmTy<'tcx, M::Provenance>>> {
|
||||
Ok(match src.as_mplace_or_imm() {
|
||||
Left(ref mplace) => {
|
||||
if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? {
|
||||
Ok(val)
|
||||
Right(val)
|
||||
} else {
|
||||
Err(*mplace)
|
||||
Left(*mplace)
|
||||
}
|
||||
}
|
||||
Err(val) => Ok(val),
|
||||
Right(val) => Right(val),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -390,7 +392,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
) {
|
||||
span_bug!(self.cur_span(), "primitive read not possible for type: {:?}", op.layout.ty);
|
||||
}
|
||||
let imm = self.read_immediate_raw(op)?.unwrap();
|
||||
let imm = self.read_immediate_raw(op)?.right().unwrap();
|
||||
if matches!(*imm, Immediate::Uninit) {
|
||||
throw_ub!(InvalidUninitBytes(None));
|
||||
}
|
||||
|
@ -432,9 +434,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// Basically we just transmute this place into an array following simd_size_and_type.
|
||||
// This only works in memory, but repr(simd) types should never be immediates anyway.
|
||||
assert!(op.layout.ty.is_simd());
|
||||
match op.try_as_mplace() {
|
||||
Ok(mplace) => self.mplace_to_simd(&mplace),
|
||||
Err(imm) => match *imm {
|
||||
match op.as_mplace_or_imm() {
|
||||
Left(mplace) => self.mplace_to_simd(&mplace),
|
||||
Right(imm) => match *imm {
|
||||
Immediate::Uninit => {
|
||||
throw_ub!(InvalidUninitBytes(None))
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
//! into a place.
|
||||
//! All high-level functions to write to memory work on places as destinations.
|
||||
|
||||
use either::{Either, Left, Right};
|
||||
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty;
|
||||
|
@ -252,36 +254,36 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> {
|
|||
// These are defined here because they produce a place.
|
||||
impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> {
|
||||
#[inline(always)]
|
||||
pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> {
|
||||
pub fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> {
|
||||
match **self {
|
||||
Operand::Indirect(mplace) => {
|
||||
Ok(MPlaceTy { mplace, layout: self.layout, align: self.align.unwrap() })
|
||||
Left(MPlaceTy { mplace, layout: self.layout, align: self.align.unwrap() })
|
||||
}
|
||||
Operand::Immediate(imm) => Err(ImmTy::from_immediate(imm, self.layout)),
|
||||
Operand::Immediate(imm) => Right(ImmTy::from_immediate(imm, self.layout)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
|
||||
pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Prov> {
|
||||
self.try_as_mplace().unwrap()
|
||||
self.as_mplace_or_imm().left().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> {
|
||||
/// A place is either an mplace or some local.
|
||||
#[inline]
|
||||
pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Prov>, (usize, mir::Local)> {
|
||||
pub fn as_mplace_or_local(&self) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local)> {
|
||||
match **self {
|
||||
Place::Ptr(mplace) => Ok(MPlaceTy { mplace, layout: self.layout, align: self.align }),
|
||||
Place::Local { frame, local } => Err((frame, local)),
|
||||
Place::Ptr(mplace) => Left(MPlaceTy { mplace, layout: self.layout, align: self.align }),
|
||||
Place::Local { frame, local } => Right((frame, local)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
|
||||
pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Prov> {
|
||||
self.try_as_mplace().unwrap()
|
||||
self.as_mplace_or_local().left().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -569,9 +571,9 @@ where
|
|||
}
|
||||
|
||||
pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
|
||||
let mplace = match dest.try_as_mplace() {
|
||||
Ok(mplace) => mplace,
|
||||
Err((frame, local)) => {
|
||||
let mplace = match dest.as_mplace_or_local() {
|
||||
Left(mplace) => mplace,
|
||||
Right((frame, local)) => {
|
||||
match M::access_local_mut(self, frame, local)? {
|
||||
Operand::Immediate(local) => {
|
||||
*local = Immediate::Uninit;
|
||||
|
@ -639,7 +641,7 @@ where
|
|||
// Let us see if the layout is simple so we take a shortcut,
|
||||
// avoid force_allocation.
|
||||
let src = match self.read_immediate_raw(src)? {
|
||||
Ok(src_val) => {
|
||||
Right(src_val) => {
|
||||
// FIXME(const_prop): Const-prop can possibly evaluate an
|
||||
// unsized copy operation when it thinks that the type is
|
||||
// actually sized, due to a trivially false where-clause
|
||||
|
@ -669,7 +671,7 @@ where
|
|||
)
|
||||
};
|
||||
}
|
||||
Err(mplace) => mplace,
|
||||
Left(mplace) => mplace,
|
||||
};
|
||||
// Slow path, this does not fit into an immediate. Just memcpy.
|
||||
trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
//! but we still need to do bounds checking and adjust the layout. To not duplicate that with MPlaceTy, we actually
|
||||
//! implement the logic on OpTy, and MPlaceTy calls that.
|
||||
|
||||
use either::{Left, Right};
|
||||
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
|
@ -84,13 +86,13 @@ where
|
|||
base: &OpTy<'tcx, M::Provenance>,
|
||||
field: usize,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||
let base = match base.try_as_mplace() {
|
||||
Ok(ref mplace) => {
|
||||
let base = match base.as_mplace_or_imm() {
|
||||
Left(ref mplace) => {
|
||||
// We can reuse the mplace field computation logic for indirect operands.
|
||||
let field = self.mplace_field(mplace, field)?;
|
||||
return Ok(field.into());
|
||||
}
|
||||
Err(value) => value,
|
||||
Right(value) => value,
|
||||
};
|
||||
|
||||
let field_layout = base.layout.field(self, field);
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
//!
|
||||
//! The main entry point is the `step` method.
|
||||
|
||||
use either::Either;
|
||||
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::{InterpResult, Scalar};
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
|
@ -46,7 +48,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
return Ok(false);
|
||||
}
|
||||
|
||||
let Ok(loc) = self.frame().loc else {
|
||||
let Either::Left(loc) = self.frame().loc else {
|
||||
// We are unwinding and this fn has no cleanup code.
|
||||
// Just go on unwinding.
|
||||
trace!("unwinding: skipping frame");
|
||||
|
@ -61,7 +63,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// Make sure we are not updating `statement_index` of the wrong frame.
|
||||
assert_eq!(old_frames, self.frame_idx());
|
||||
// Advance the program counter.
|
||||
self.frame_mut().loc.as_mut().unwrap().statement_index += 1;
|
||||
self.frame_mut().loc.as_mut().left().unwrap().statement_index += 1;
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
|
@ -305,7 +307,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
|
||||
self.eval_terminator(terminator)?;
|
||||
if !self.stack().is_empty() {
|
||||
if let Ok(loc) = self.frame().loc {
|
||||
if let Either::Left(loc) = self.frame().loc {
|
||||
info!("// executing {:?}", loc.block);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ use std::convert::TryFrom;
|
|||
use std::fmt::{Display, Write};
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
use either::{Left, Right};
|
||||
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
|
@ -852,9 +854,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
|||
return Ok(());
|
||||
}
|
||||
// Now that we definitely have a non-ZST array, we know it lives in memory.
|
||||
let mplace = match op.try_as_mplace() {
|
||||
Ok(mplace) => mplace,
|
||||
Err(imm) => match *imm {
|
||||
let mplace = match op.as_mplace_or_imm() {
|
||||
Left(mplace) => mplace,
|
||||
Right(imm) => match *imm {
|
||||
Immediate::Uninit =>
|
||||
throw_validation_failure!(self.path, { "uninitialized bytes" }),
|
||||
Immediate::Scalar(..) | Immediate::ScalarPair(..) =>
|
||||
|
|
|
@ -11,6 +11,8 @@ use std::hash;
|
|||
use std::ops::Range;
|
||||
use std::ptr;
|
||||
|
||||
use either::{Left, Right};
|
||||
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
@ -503,11 +505,11 @@ impl<Prov: Provenance, Extra> Allocation<Prov, Extra> {
|
|||
// `to_bits_or_ptr_internal` is the right method because we just want to store this data
|
||||
// as-is into memory.
|
||||
let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size)? {
|
||||
Err(val) => {
|
||||
let (provenance, offset) = val.into_parts();
|
||||
Right(ptr) => {
|
||||
let (provenance, offset) = ptr.into_parts();
|
||||
(u128::from(offset.bytes()), Some(provenance))
|
||||
}
|
||||
Ok(data) => (data, None),
|
||||
Left(data) => (data, None),
|
||||
};
|
||||
|
||||
let endian = cx.data_layout().endian;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use std::convert::{TryFrom, TryInto};
|
||||
use std::fmt;
|
||||
|
||||
use either::{Either, Left, Right};
|
||||
|
||||
use rustc_apfloat::{
|
||||
ieee::{Double, Single},
|
||||
Float,
|
||||
|
@ -293,10 +295,10 @@ impl<Prov> Scalar<Prov> {
|
|||
pub fn to_bits_or_ptr_internal(
|
||||
self,
|
||||
target_size: Size,
|
||||
) -> Result<Result<u128, Pointer<Prov>>, ScalarSizeMismatch> {
|
||||
) -> Result<Either<u128, Pointer<Prov>>, ScalarSizeMismatch> {
|
||||
assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
|
||||
Ok(match self {
|
||||
Scalar::Int(int) => Ok(int.to_bits(target_size).map_err(|size| {
|
||||
Scalar::Int(int) => Left(int.to_bits(target_size).map_err(|size| {
|
||||
ScalarSizeMismatch { target_size: target_size.bytes(), data_size: size.bytes() }
|
||||
})?),
|
||||
Scalar::Ptr(ptr, sz) => {
|
||||
|
@ -306,7 +308,7 @@ impl<Prov> Scalar<Prov> {
|
|||
data_size: sz.into(),
|
||||
});
|
||||
}
|
||||
Err(ptr)
|
||||
Right(ptr)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -318,8 +320,8 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
|
|||
.to_bits_or_ptr_internal(cx.pointer_size())
|
||||
.map_err(|s| err_ub!(ScalarSizeMismatch(s)))?
|
||||
{
|
||||
Err(ptr) => Ok(ptr.into()),
|
||||
Ok(bits) => {
|
||||
Right(ptr) => Ok(ptr.into()),
|
||||
Left(bits) => {
|
||||
let addr = u64::try_from(bits).unwrap();
|
||||
Ok(Pointer::from_addr(addr))
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
rustc_arena = { path = "../rustc_arena" }
|
||||
tracing = "0.1"
|
||||
either = "1"
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_apfloat = { path = "../rustc_apfloat" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
|
|
|
@ -42,16 +42,17 @@
|
|||
//! wildcards, see [`SplitWildcard`]; for integer ranges, see [`SplitIntRange`]; for slices, see
|
||||
//! [`SplitVarLenSlice`].
|
||||
|
||||
use self::Constructor::*;
|
||||
use self::SliceKind::*;
|
||||
use std::cell::Cell;
|
||||
use std::cmp::{self, max, min, Ordering};
|
||||
use std::fmt;
|
||||
use std::iter::{once, IntoIterator};
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
use super::compare_const_vals;
|
||||
use super::usefulness::{MatchCheckCtxt, PatCtxt};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_index::vec::Idx;
|
||||
|
||||
use rustc_hir::{HirId, RangeEnd};
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_middle::mir::{self, Field};
|
||||
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
|
@ -61,12 +62,11 @@ use rustc_session::lint;
|
|||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::{Integer, Size, VariantIdx};
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::cell::Cell;
|
||||
use std::cmp::{self, max, min, Ordering};
|
||||
use std::fmt;
|
||||
use std::iter::{once, IntoIterator};
|
||||
use std::ops::RangeInclusive;
|
||||
use self::Constructor::*;
|
||||
use self::SliceKind::*;
|
||||
|
||||
use super::compare_const_vals;
|
||||
use super::usefulness::{MatchCheckCtxt, PatCtxt};
|
||||
|
||||
/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
|
||||
fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
|
||||
|
@ -147,11 +147,7 @@ impl IntRange {
|
|||
// straight to the result, after doing a bit of checking. (We
|
||||
// could remove this branch and just fall through, which
|
||||
// is more general but much slower.)
|
||||
if let Ok(Ok(bits)) = scalar.to_bits_or_ptr_internal(target_size) {
|
||||
return Some(bits);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
return scalar.to_bits_or_ptr_internal(target_size).unwrap().left();
|
||||
}
|
||||
mir::ConstantKind::Ty(c) => match c.kind() {
|
||||
ty::ConstKind::Value(_) => bug!(
|
||||
|
|
|
@ -9,6 +9,7 @@ edition = "2021"
|
|||
itertools = "0.10.1"
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
tracing = "0.1"
|
||||
either = "1"
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
use std::cell::Cell;
|
||||
|
||||
use either::Right;
|
||||
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::def::DefKind;
|
||||
|
@ -429,7 +431,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
// Try to read the local as an immediate so that if it is representable as a scalar, we can
|
||||
// handle it as such, but otherwise, just return the value as is.
|
||||
Some(match self.ecx.read_immediate_raw(&op) {
|
||||
Ok(Ok(imm)) => imm.into(),
|
||||
Ok(Right(imm)) => imm.into(),
|
||||
_ => op,
|
||||
})
|
||||
}
|
||||
|
@ -743,7 +745,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
// FIXME> figure out what to do when read_immediate_raw fails
|
||||
let imm = self.use_ecx(|this| this.ecx.read_immediate_raw(value));
|
||||
|
||||
if let Some(Ok(imm)) = imm {
|
||||
if let Some(Right(imm)) = imm {
|
||||
match *imm {
|
||||
interpret::Immediate::Scalar(scalar) => {
|
||||
*rval = Rvalue::Use(self.operand_from_scalar(
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
//! Propagates constants for early reporting of statically known
|
||||
//! assertion failures
|
||||
|
||||
use crate::const_prop::CanConstProp;
|
||||
use crate::const_prop::ConstPropMachine;
|
||||
use crate::const_prop::ConstPropMode;
|
||||
use crate::MirLint;
|
||||
use std::cell::Cell;
|
||||
|
||||
use either::{Left, Right};
|
||||
|
||||
use rustc_const_eval::interpret::Immediate;
|
||||
use rustc_const_eval::interpret::{
|
||||
self, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, Scalar, StackPopCleanup,
|
||||
|
@ -26,12 +26,17 @@ use rustc_session::lint;
|
|||
use rustc_span::Span;
|
||||
use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
|
||||
use rustc_trait_selection::traits;
|
||||
use std::cell::Cell;
|
||||
|
||||
use crate::const_prop::CanConstProp;
|
||||
use crate::const_prop::ConstPropMachine;
|
||||
use crate::const_prop::ConstPropMode;
|
||||
use crate::MirLint;
|
||||
|
||||
/// The maximum number of bytes that we'll allocate space for a local or the return value.
|
||||
/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
|
||||
/// Severely regress performance.
|
||||
const MAX_ALLOC_LIMIT: u64 = 1024;
|
||||
|
||||
pub struct ConstProp;
|
||||
|
||||
impl<'tcx> MirLint<'tcx> for ConstProp {
|
||||
|
@ -243,7 +248,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
// Try to read the local as an immediate so that if it is representable as a scalar, we can
|
||||
// handle it as such, but otherwise, just return the value as is.
|
||||
Some(match self.ecx.read_immediate_raw(&op) {
|
||||
Ok(Ok(imm)) => imm.into(),
|
||||
Ok(Left(imm)) => imm.into(),
|
||||
_ => op,
|
||||
})
|
||||
}
|
||||
|
@ -266,7 +271,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
F: FnOnce(&mut Self) -> InterpResult<'tcx, T>,
|
||||
{
|
||||
// Overwrite the PC -- whatever the interpreter does to it does not make any sense anyway.
|
||||
self.ecx.frame_mut().loc = Err(source_info.span);
|
||||
self.ecx.frame_mut().loc = Right(source_info.span);
|
||||
match f(self) {
|
||||
Ok(val) => Some(val),
|
||||
Err(error) => {
|
||||
|
|
|
@ -208,9 +208,11 @@ pub unsafe trait GlobalAlloc {
|
|||
///
|
||||
/// If this returns a non-null pointer, then ownership of the memory block
|
||||
/// referenced by `ptr` has been transferred to this allocator.
|
||||
/// The memory may or may not have been deallocated, and should be
|
||||
/// considered unusable. The new memory block is allocated with `layout`,
|
||||
/// but with the `size` updated to `new_size`. This new layout should be
|
||||
/// Any access to the old `ptr` is Undefined Behavior, even if the
|
||||
/// allocation remained in-place. The newly returned pointer is the only valid pointer
|
||||
/// for accessing this memory now.
|
||||
/// The new memory block is allocated with `layout`,
|
||||
/// but with the `size` updated to `new_size`. This new layout must be
|
||||
/// used when deallocating the new memory block with `dealloc`. The range
|
||||
/// `0..min(layout.size(), new_size)` of the new memory block is
|
||||
/// guaranteed to have the same values as the original block.
|
||||
|
|
|
@ -169,8 +169,9 @@ pub unsafe trait Allocator {
|
|||
/// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout.
|
||||
///
|
||||
/// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
|
||||
/// transferred to this allocator. The memory may or may not have been freed, and should be
|
||||
/// considered unusable.
|
||||
/// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the
|
||||
/// allocation was grown in-place. The newly returned pointer is the only valid pointer
|
||||
/// for accessing this memory now.
|
||||
///
|
||||
/// If this method returns `Err`, then ownership of the memory block has not been transferred to
|
||||
/// this allocator, and the contents of the memory block are unaltered.
|
||||
|
@ -295,8 +296,9 @@ pub unsafe trait Allocator {
|
|||
/// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout.
|
||||
///
|
||||
/// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
|
||||
/// transferred to this allocator. The memory may or may not have been freed, and should be
|
||||
/// considered unusable.
|
||||
/// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the
|
||||
/// allocation was shrunk in-place. The newly returned pointer is the only valid pointer
|
||||
/// for accessing this memory now.
|
||||
///
|
||||
/// If this method returns `Err`, then ownership of the memory block has not been transferred to
|
||||
/// this allocator, and the contents of the memory block are unaltered.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::os::windows::prelude::*;
|
||||
|
||||
use crate::borrow::Cow;
|
||||
use crate::ffi::OsString;
|
||||
use crate::fmt;
|
||||
use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
|
||||
|
@ -719,7 +720,7 @@ impl<'a> DirBuffIter<'a> {
|
|||
}
|
||||
}
|
||||
impl<'a> Iterator for DirBuffIter<'a> {
|
||||
type Item = (&'a [u16], bool);
|
||||
type Item = (Cow<'a, [u16]>, bool);
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
use crate::mem::size_of;
|
||||
let buffer = &self.buffer?[self.cursor..];
|
||||
|
@ -734,15 +735,19 @@ impl<'a> Iterator for DirBuffIter<'a> {
|
|||
// `FileNameLength` bytes)
|
||||
let (name, is_directory, next_entry) = unsafe {
|
||||
let info = buffer.as_ptr().cast::<c::FILE_ID_BOTH_DIR_INFO>();
|
||||
// Guaranteed to be aligned in documentation for
|
||||
// While this is guaranteed to be aligned in documentation for
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_id_both_dir_info
|
||||
assert!(info.is_aligned());
|
||||
let next_entry = (*info).NextEntryOffset as usize;
|
||||
let name = crate::slice::from_raw_parts(
|
||||
// it does not seem that reality is so kind, and assuming this
|
||||
// caused crashes in some cases (https://github.com/rust-lang/rust/issues/104530)
|
||||
// presumably, this can be blamed on buggy filesystem drivers, but who knows.
|
||||
let next_entry = ptr::addr_of!((*info).NextEntryOffset).read_unaligned() as usize;
|
||||
let length = ptr::addr_of!((*info).FileNameLength).read_unaligned() as usize;
|
||||
let attrs = ptr::addr_of!((*info).FileAttributes).read_unaligned();
|
||||
let name = from_maybe_unaligned(
|
||||
ptr::addr_of!((*info).FileName).cast::<u16>(),
|
||||
(*info).FileNameLength as usize / size_of::<u16>(),
|
||||
length / size_of::<u16>(),
|
||||
);
|
||||
let is_directory = ((*info).FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
let is_directory = (attrs & c::FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
|
||||
(name, is_directory, next_entry)
|
||||
};
|
||||
|
@ -755,13 +760,21 @@ impl<'a> Iterator for DirBuffIter<'a> {
|
|||
|
||||
// Skip `.` and `..` pseudo entries.
|
||||
const DOT: u16 = b'.' as u16;
|
||||
match name {
|
||||
match &name[..] {
|
||||
[DOT] | [DOT, DOT] => self.next(),
|
||||
_ => Some((name, is_directory)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn from_maybe_unaligned<'a>(p: *const u16, len: usize) -> Cow<'a, [u16]> {
|
||||
if p.is_aligned() {
|
||||
Cow::Borrowed(crate::slice::from_raw_parts(p, len))
|
||||
} else {
|
||||
Cow::Owned((0..len).map(|i| p.add(i).read_unaligned()).collect())
|
||||
}
|
||||
}
|
||||
|
||||
/// Open a link relative to the parent directory, ensure no symlinks are followed.
|
||||
fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result<File> {
|
||||
// This is implemented using the lower level `NtCreateFile` function as
|
||||
|
@ -1117,13 +1130,13 @@ fn remove_dir_all_iterative(f: &File, delete: fn(&File) -> io::Result<()>) -> io
|
|||
if is_directory {
|
||||
let child_dir = open_link_no_reparse(
|
||||
&dir,
|
||||
name,
|
||||
&name,
|
||||
c::SYNCHRONIZE | c::DELETE | c::FILE_LIST_DIRECTORY,
|
||||
)?;
|
||||
dirlist.push(child_dir);
|
||||
} else {
|
||||
for i in 1..=MAX_RETRIES {
|
||||
let result = open_link_no_reparse(&dir, name, c::SYNCHRONIZE | c::DELETE);
|
||||
let result = open_link_no_reparse(&dir, &name, c::SYNCHRONIZE | c::DELETE);
|
||||
match result {
|
||||
Ok(f) => delete(&f)?,
|
||||
// Already deleted, so skip.
|
||||
|
|
|
@ -124,9 +124,8 @@
|
|||
//!
|
||||
//! ## Stack size
|
||||
//!
|
||||
//! The default stack size for spawned threads is 2 MiB, though this particular stack size is
|
||||
//! subject to change in the future. There are two ways to manually specify the stack size for
|
||||
//! spawned threads:
|
||||
//! The default stack size is platform-dependent and subject to change. Currently it is 2MB on all
|
||||
//! Tier-1 platforms. There are two ways to manually specify the stack size for spawned threads:
|
||||
//!
|
||||
//! * Build the thread with [`Builder`] and pass the desired stack size to [`Builder::stack_size`].
|
||||
//! * Set the `RUST_MIN_STACK` environment variable to an integer representing the desired stack
|
||||
|
|
|
@ -1011,6 +1011,8 @@ impl Step for RustdocGUI {
|
|||
// instead of hard-coding this test
|
||||
if entry.file_name() == "link_to_definition" {
|
||||
cargo.env("RUSTDOCFLAGS", "-Zunstable-options --generate-link-to-definition");
|
||||
} else if entry.file_name() == "scrape_examples" {
|
||||
cargo.arg("-Zrustdoc-scrape-examples=examples");
|
||||
}
|
||||
builder.run(&mut cargo);
|
||||
}
|
||||
|
|
|
@ -2915,7 +2915,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
|
|||
);
|
||||
|
||||
if line_ranges.len() > 1 {
|
||||
write!(w, r#"<span class="prev">≺</span> <span class="next">≻</span>"#);
|
||||
write!(w, r#"<button class="prev">≺</button> <button class="next">≻</button>"#);
|
||||
}
|
||||
|
||||
// Look for the example file in the source map if it exists, otherwise return a dummy span
|
||||
|
|
|
@ -287,8 +287,11 @@ pub(crate) fn print_src(
|
|||
}
|
||||
}
|
||||
SourceContext::Embedded { offset, needs_expansion } => {
|
||||
extra =
|
||||
if needs_expansion { Some(r#"<span class="expand">↕</span>"#) } else { None };
|
||||
extra = if needs_expansion {
|
||||
Some(r#"<button class="expand">↕</button>"#)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
for line_number in 1..=lines {
|
||||
let line = line_number + offset;
|
||||
writeln!(line_numbers, "<span>{line}</span>")
|
||||
|
|
|
@ -1431,6 +1431,9 @@ kbd {
|
|||
border: solid 1px var(--border-color);
|
||||
border-radius: 3px;
|
||||
cursor: default;
|
||||
color: var(--kbd--color);
|
||||
background-color: var(--kbd-background);
|
||||
box-shadow: inset 0 -1px 0 var(--kbd-box-shadow-color);
|
||||
}
|
||||
|
||||
ul.all-items > li {
|
||||
|
@ -1965,6 +1968,12 @@ in storage.js
|
|||
top: 0.25em;
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
background: none;
|
||||
border: none;
|
||||
/* iOS button gradient: https://stackoverflow.com/q/5438567 */
|
||||
-webkit-appearance: none;
|
||||
opacity: 1;
|
||||
}
|
||||
.scraped-example .code-wrapper .prev {
|
||||
right: 2.25em;
|
||||
|
|
|
@ -69,6 +69,9 @@ Original by Dempfi (https://github.com/dempfi/ayu)
|
|||
--target-border-color: rgba(255, 180, 76, 0.85);
|
||||
--tooltip-background-color: #314559;
|
||||
--tooltip-color: #c5c5c5;
|
||||
--kbd-color: #c5c5c5;
|
||||
--kbd-background: #314559;
|
||||
--kbd-box-shadow-color: #5c6773;
|
||||
--rust-logo-filter: drop-shadow(1px 0 0px #fff)
|
||||
drop-shadow(0 1px 0 #fff)
|
||||
drop-shadow(-1px 0 0 #fff)
|
||||
|
@ -195,12 +198,6 @@ pre.rust .kw {}
|
|||
pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, pre.rust .attribute {}
|
||||
pre.rust .kw-2, pre.rust .prelude-ty {}
|
||||
|
||||
kbd {
|
||||
color: #c5c5c5;
|
||||
background-color: #314559;
|
||||
box-shadow: inset 0 -1px 0 #5c6773;
|
||||
}
|
||||
|
||||
#settings-menu > a img {
|
||||
filter: invert(100);
|
||||
}
|
||||
|
|
|
@ -64,6 +64,9 @@
|
|||
--target-border-color: #bb7410;
|
||||
--tooltip-background-color: #000;
|
||||
--tooltip-color: #fff;
|
||||
--kbd-color: #000;
|
||||
--kbd-background: #fafbfc;
|
||||
--kbd-box-shadow-color: #c6cbd1;
|
||||
--rust-logo-filter: drop-shadow(1px 0 0px #fff)
|
||||
drop-shadow(0 1px 0 #fff)
|
||||
drop-shadow(-1px 0 0 #fff)
|
||||
|
@ -100,12 +103,6 @@ details.rustdoc-toggle > summary::before {
|
|||
color: #888;
|
||||
}
|
||||
|
||||
kbd {
|
||||
color: #000;
|
||||
background-color: #fafbfc;
|
||||
box-shadow: inset 0 -1px 0 #c6cbd1;
|
||||
}
|
||||
|
||||
.search-results .result-name span.alias {
|
||||
color: #fff;
|
||||
}
|
||||
|
|
|
@ -64,6 +64,9 @@
|
|||
--target-border-color: #ad7c37;
|
||||
--tooltip-background-color: #fdffd3;
|
||||
--tooltip-color: #fff;
|
||||
--kbd-color: #000;
|
||||
--kbd-background: #fafbfc;
|
||||
--kbd-box-shadow-color: #c6cbd1;
|
||||
--rust-logo-filter: initial;
|
||||
/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
|
||||
--crate-search-div-filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg)
|
||||
|
@ -93,12 +96,6 @@ body.source .example-wrap pre.rust a {
|
|||
color: #888;
|
||||
}
|
||||
|
||||
kbd {
|
||||
color: #000;
|
||||
background-color: #fafbfc;
|
||||
box-shadow: inset 0 -1px 0 #c6cbd1;
|
||||
}
|
||||
|
||||
.search-results .result-name span.alias {
|
||||
color: #000;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
{%- endif -%}
|
||||
<script defer src="{{static_root_path|safe}}{{files.main_js}}"></script> {#- -#}
|
||||
{%- if layout.scrape_examples_extension -%}
|
||||
<script defer src="{{page.root_path|safe}}{{files.scrape_examples_js}}"></script> {#- -#}
|
||||
<script defer src="{{static_root_path|safe}}{{files.scrape_examples_js}}"></script> {#- -#}
|
||||
{%- endif -%}
|
||||
<noscript> {#- -#}
|
||||
<link rel="stylesheet" {# -#}
|
||||
|
|
|
@ -13,6 +13,44 @@ assert-css: ("#help", {"display": "block"})
|
|||
compare-elements-property: (".sub", "#help", ["offsetWidth"])
|
||||
compare-elements-position: (".sub", "#help", ("x"))
|
||||
|
||||
// Checking the color of the elements of the help menu.
|
||||
show-text: true
|
||||
define-function: (
|
||||
"check-colors",
|
||||
(theme, color, background, box_shadow),
|
||||
[
|
||||
// Setting the theme.
|
||||
("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
|
||||
// We reload the page so the local storage settings are being used.
|
||||
("reload"),
|
||||
("assert-css", ("#help kbd", {
|
||||
"color": |color|,
|
||||
"background-color": |background|,
|
||||
"box-shadow": |box_shadow| + " 0px -1px 0px 0px inset",
|
||||
"cursor": "default",
|
||||
}, ALL)),
|
||||
],
|
||||
)
|
||||
|
||||
call-function: ("check-colors", {
|
||||
"theme": "ayu",
|
||||
"color": "rgb(197, 197, 197)",
|
||||
"background": "rgb(49, 69, 89)",
|
||||
"box_shadow": "rgb(92, 103, 115)",
|
||||
})
|
||||
call-function: ("check-colors", {
|
||||
"theme": "dark",
|
||||
"color": "rgb(221, 221, 221)",
|
||||
"background": "rgb(250, 251, 252)",
|
||||
"box_shadow": "rgb(198, 203, 209)",
|
||||
})
|
||||
call-function: ("check-colors", {
|
||||
"theme": "light",
|
||||
"color": "rgb(0, 0, 0)",
|
||||
"background": "rgb(250, 251, 252)",
|
||||
"box_shadow": "rgb(198, 203, 209)",
|
||||
})
|
||||
|
||||
// This test ensures that opening the help popover without switching pages works.
|
||||
goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
|
||||
size: (1000, 1000) // Only supported on desktop.
|
||||
|
|
14
src/test/rustdoc-gui/scrape-examples-button-focus.goml
Normal file
14
src/test/rustdoc-gui/scrape-examples-button-focus.goml
Normal file
|
@ -0,0 +1,14 @@
|
|||
goto: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html"
|
||||
store-property: (smallOffsetHeight, ".scraped-example-list > .scraped-example pre", "offsetHeight")
|
||||
assert-property-false: (".scraped-example-list > .scraped-example pre", {
|
||||
"scrollHeight": |smallOffsetHeight|
|
||||
})
|
||||
focus: ".scraped-example-list > .scraped-example .expand"
|
||||
press-key: "Enter"
|
||||
assert-property-false: (".scraped-example-list > .scraped-example pre", {
|
||||
"offsetHeight": |smallOffsetHeight|
|
||||
})
|
||||
store-property: (fullOffsetHeight, ".scraped-example-list > .scraped-example pre", "offsetHeight")
|
||||
assert-property: (".scraped-example-list > .scraped-example pre", {
|
||||
"scrollHeight": |fullOffsetHeight|
|
||||
})
|
|
@ -28,7 +28,7 @@ assert: "//*[@class='dir-entry' and @open]/*[text()='sub_mod']"
|
|||
// Only "another_folder" should be "open" in "lib2".
|
||||
assert: "//*[@class='dir-entry' and not(@open)]/*[text()='another_mod']"
|
||||
// All other trees should be collapsed.
|
||||
assert-count: ("//*[@id='source-sidebar']/details[not(text()='lib2') and not(@open)]", 6)
|
||||
assert-count: ("//*[@id='source-sidebar']/details[not(text()='lib2') and not(@open)]", 7)
|
||||
|
||||
// We now switch to mobile mode.
|
||||
size: (600, 600)
|
||||
|
|
7
src/test/rustdoc-gui/src/scrape_examples/Cargo.lock
Normal file
7
src/test/rustdoc-gui/src/scrape_examples/Cargo.lock
Normal file
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "scrape_examples"
|
||||
version = "0.1.0"
|
8
src/test/rustdoc-gui/src/scrape_examples/Cargo.toml
Normal file
8
src/test/rustdoc-gui/src/scrape_examples/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "scrape_examples"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
25
src/test/rustdoc-gui/src/scrape_examples/examples/check.rs
Normal file
25
src/test/rustdoc-gui/src/scrape_examples/examples/check.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
fn main() {
|
||||
for i in 0..9 {
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
}
|
||||
scrape_examples::test();
|
||||
for i in 0..9 {
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
println!("hello world!");
|
||||
}
|
||||
}
|
7
src/test/rustdoc-gui/src/scrape_examples/src/lib.rs
Normal file
7
src/test/rustdoc-gui/src/scrape_examples/src/lib.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// test();
|
||||
/// test();
|
||||
/// ```
|
||||
pub fn test() {}
|
Loading…
Add table
Reference in a new issue