Auto merge of #66121 - pietroalbini:rollup-8zrwe7l, r=pietroalbini

Rollup of 8 pull requests

Successful merges:

 - #65948 (Improve MaybeUninit::get_{ref,mut} documentation)
 - #65953 (Allow specifying LLVM's MCTargetOptions::ABIName in target specification files)
 - #66012 (De-querify `trivial_dropck_outlives`.)
 - #66025 (`Span` cannot represent `span.hi < span.lo`)
 - #66047 (Don't double-count `simd_shuffle` promotion candidates)
 - #66053 (when Miri tests are not passing, do not add Miri component)
 - #66082 (clean highlightSourceLines code)
 - #66091 (Implemented the home_dir for VxWorks)

Failed merges:

r? @ghost
This commit is contained in:
bors 2019-11-05 20:22:27 +00:00
commit 1423bec54c
21 changed files with 267 additions and 102 deletions

View file

@ -208,6 +208,7 @@ name = "build-manifest"
version = "0.1.0"
dependencies = [
"serde",
"serde_json",
"toml",
]

View file

@ -509,32 +509,183 @@ impl<T> MaybeUninit<T> {
self.as_ptr().read()
}
/// Gets a reference to the contained value.
/// Gets a shared reference to the contained value.
///
/// This can be useful when we want to access a `MaybeUninit` that has been
/// initialized but don't have ownership of the `MaybeUninit` (preventing the use
/// of `.assume_init()`).
///
/// # Safety
///
/// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
/// state. Calling this when the content is not yet fully initialized causes undefined
/// behavior.
/// Calling this when the content is not yet fully initialized causes undefined
/// behavior: it is up to the caller to guarantee that the `MaybeUninit<T>` really
/// is in an initialized state.
///
/// # Examples
///
/// ### Correct usage of this method:
///
/// ```rust
/// #![feature(maybe_uninit_ref)]
/// use std::mem::MaybeUninit;
///
/// let mut x = MaybeUninit::<Vec<u32>>::uninit();
/// // Initialize `x`:
/// unsafe { x.as_mut_ptr().write(vec![1, 2, 3]); }
/// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to
/// // create a shared reference to it:
/// let x: &Vec<u32> = unsafe {
/// // Safety: `x` has been initialized.
/// x.get_ref()
/// };
/// assert_eq!(x, &vec![1, 2, 3]);
/// ```
///
/// ### *Incorrect* usages of this method:
///
/// ```rust,no_run
/// #![feature(maybe_uninit_ref)]
/// use std::mem::MaybeUninit;
///
/// let x = MaybeUninit::<Vec<u32>>::uninit();
/// let x_vec: &Vec<u32> = unsafe { x.get_ref() };
/// // We have created a reference to an uninitialized vector! This is undefined behavior.
/// ```
///
/// ```rust,no_run
/// #![feature(maybe_uninit_ref)]
/// use std::{cell::Cell, mem::MaybeUninit};
///
/// let b = MaybeUninit::<Cell<bool>>::uninit();
/// // Initialize the `MaybeUninit` using `Cell::set`:
/// unsafe {
/// b.get_ref().set(true);
/// // ^^^^^^^^^^^
/// // Reference to an uninitialized `Cell<bool>`: UB!
/// }
/// ```
#[unstable(feature = "maybe_uninit_ref", issue = "63568")]
#[inline(always)]
pub unsafe fn get_ref(&self) -> &T {
intrinsics::panic_if_uninhabited::<T>();
&*self.value
}
/// Gets a mutable reference to the contained value.
/// Gets a mutable (unique) reference to the contained value.
///
/// This can be useful when we want to access a `MaybeUninit` that has been
/// initialized but don't have ownership of the `MaybeUninit` (preventing the use
/// of `.assume_init()`).
///
/// # Safety
///
/// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
/// state. Calling this when the content is not yet fully initialized causes undefined
/// behavior.
/// Calling this when the content is not yet fully initialized causes undefined
/// behavior: it is up to the caller to guarantee that the `MaybeUninit<T>` really
/// is in an initialized state. For instance, `.get_mut()` cannot be used to
/// initialize a `MaybeUninit`.
///
/// # Examples
///
/// ### Correct usage of this method:
///
/// ```rust
/// #![feature(maybe_uninit_ref)]
/// use std::mem::MaybeUninit;
///
/// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 2048]) { *buf = [0; 2048] }
/// # #[cfg(FALSE)]
/// extern "C" {
/// /// Initializes *all* the bytes of the input buffer.
/// fn initialize_buffer(buf: *mut [u8; 2048]);
/// }
///
/// let mut buf = MaybeUninit::<[u8; 2048]>::uninit();
///
/// // Initialize `buf`:
/// unsafe { initialize_buffer(buf.as_mut_ptr()); }
/// // Now we know that `buf` has been initialized, so we could `.assume_init()` it.
/// // However, using `.assume_init()` may trigger a `memcpy` of the 2048 bytes.
/// // To assert our buffer has been initialized without copying it, we upgrade
/// // the `&mut MaybeUninit<[u8; 2048]>` to a `&mut [u8; 2048]`:
/// let buf: &mut [u8; 2048] = unsafe {
/// // Safety: `buf` has been initialized.
/// buf.get_mut()
/// };
///
/// // Now we can use `buf` as a normal slice:
/// buf.sort_unstable();
/// assert!(
/// buf.chunks(2).all(|chunk| chunk[0] <= chunk[1]),
/// "buffer is sorted",
/// );
/// ```
///
/// ### *Incorrect* usages of this method:
///
/// You cannot use `.get_mut()` to initialize a value:
///
/// ```rust,no_run
/// #![feature(maybe_uninit_ref)]
/// use std::mem::MaybeUninit;
///
/// let mut b = MaybeUninit::<bool>::uninit();
/// unsafe {
/// *b.get_mut() = true;
/// // We have created a (mutable) reference to an uninitialized `bool`!
/// // This is undefined behavior.
/// }
/// ```
///
/// For instance, you cannot [`Read`] into an uninitialized buffer:
///
/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
///
/// ```rust,no_run
/// #![feature(maybe_uninit_ref)]
/// use std::{io, mem::MaybeUninit};
///
/// fn read_chunk (reader: &'_ mut dyn io::Read) -> io::Result<[u8; 64]>
/// {
/// let mut buffer = MaybeUninit::<[u8; 64]>::uninit();
/// reader.read_exact(unsafe { buffer.get_mut() })?;
/// // ^^^^^^^^^^^^^^^^
/// // (mutable) reference to uninitialized memory!
/// // This is undefined behavior.
/// Ok(unsafe { buffer.assume_init() })
/// }
/// ```
///
/// Nor can you use direct field access to do field-by-field gradual initialization:
///
/// ```rust,no_run
/// #![feature(maybe_uninit_ref)]
/// use std::{mem::MaybeUninit, ptr};
///
/// struct Foo {
/// a: u32,
/// b: u8,
/// }
///
/// let foo: Foo = unsafe {
/// let mut foo = MaybeUninit::<Foo>::uninit();
/// ptr::write(&mut foo.get_mut().a as *mut u32, 1337);
/// // ^^^^^^^^^^^^^
/// // (mutable) reference to uninitialized memory!
/// // This is undefined behavior.
/// ptr::write(&mut foo.get_mut().b as *mut u8, 42);
/// // ^^^^^^^^^^^^^
/// // (mutable) reference to uninitialized memory!
/// // This is undefined behavior.
/// foo.assume_init()
/// };
/// ```
// FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references
// to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make
// a final decision about the rules before stabilization.
#[unstable(feature = "maybe_uninit_ref", issue = "63568")]
#[inline(always)]
pub unsafe fn get_mut(&mut self) -> &mut T {
intrinsics::panic_if_uninhabited::<T>();
&mut *self.value
}

View file

@ -309,11 +309,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for Span {
// position that belongs to it, as opposed to hashing the first
// position past it.
let span = self.data();
if span.hi < span.lo {
return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
}
let (file_lo, line_lo, col_lo) = match hcx.source_map()
.byte_pos_to_line_and_col(span.lo) {
Some(pos) => pos,

View file

@ -228,12 +228,6 @@ rustc_queries! {
cycle_delay_bug
}
query trivial_dropck_outlives(ty: Ty<'tcx>) -> bool {
anon
no_force
desc { "checking if `{:?}` has trivial dropck", ty }
}
query adt_dtorck_constraint(
_: DefId
) -> Result<DtorckConstraint<'tcx>, NoSolution> {}

View file

@ -5,7 +5,6 @@ use std::iter::FromIterator;
use syntax::source_map::Span;
use crate::ty::subst::GenericArg;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::query::Providers;
impl<'cx, 'tcx> At<'cx, 'tcx> {
/// Given a type `ty` of some value being dropped, computes a set
@ -34,7 +33,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> {
// Quick check: there are a number of cases that we know do not require
// any destructor.
let tcx = self.infcx.tcx;
if tcx.trivial_dropck_outlives(ty) {
if trivial_dropck_outlives(tcx, ty) {
return InferOk {
value: vec![],
obligations: vec![],
@ -208,15 +207,15 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
| ty::Error => true,
// [T; N] and [T] have same properties as T.
ty::Array(ty, _) | ty::Slice(ty) => tcx.trivial_dropck_outlives(ty),
ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty),
// (T1..Tn) and closures have same properties as T1..Tn --
// check if *any* of those are trivial.
ty::Tuple(ref tys) => tys.iter().all(|t| tcx.trivial_dropck_outlives(t.expect_ty())),
ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())),
ty::Closure(def_id, ref substs) => substs
.as_closure()
.upvar_tys(def_id, tcx)
.all(|t| tcx.trivial_dropck_outlives(t)),
.all(|t| trivial_dropck_outlives(tcx, t)),
ty::Adt(def, _) => {
if Some(def.did) == tcx.lang_items().manually_drop() {
@ -244,10 +243,3 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
}
}
crate fn provide(p: &mut Providers<'_>) {
*p = Providers {
trivial_dropck_outlives,
..*p
};
}

View file

@ -1,5 +1,5 @@
use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
use crate::traits::query::dropck_outlives::DropckOutlivesResult;
use crate::traits::query::dropck_outlives::{DropckOutlivesResult, trivial_dropck_outlives};
use crate::traits::query::Fallible;
use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
@ -21,7 +21,7 @@ impl super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
tcx: TyCtxt<'tcx>,
key: &ParamEnvAnd<'tcx, Self>,
) -> Option<Self::QueryResponse> {
if tcx.trivial_dropck_outlives(key.value.dropped_ty) {
if trivial_dropck_outlives(tcx, key.value.dropped_ty) {
Some(DropckOutlivesResult::default())
} else {
None

View file

@ -3407,7 +3407,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
layout::provide(providers);
util::provide(providers);
constness::provide(providers);
crate::traits::query::dropck_outlives::provide(providers);
*providers = ty::query::Providers {
asyncness,
associated_item,

View file

@ -796,11 +796,6 @@ where
}
let span_data = span.data();
if span_data.hi < span_data.lo {
return TAG_INVALID_SPAN.encode(self);
}
let (file_lo, line_lo, col_lo) = match self.source_map
.byte_pos_to_line_and_col(span_data.lo) {
Some(pos) => pos,

View file

@ -161,6 +161,7 @@ pub fn target_machine_factory(sess: &Session, optlvl: config::OptLevel, find_fea
let cpu = SmallCStr::new(llvm_util::target_cpu(sess));
let features = features.join(",");
let features = CString::new(features).unwrap();
let abi = SmallCStr::new(&sess.target.target.options.llvm_abiname);
let is_pie_binary = !find_features && is_pie_binary(sess);
let trap_unreachable = sess.target.target.options.trap_unreachable;
let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes;
@ -170,7 +171,7 @@ pub fn target_machine_factory(sess: &Session, optlvl: config::OptLevel, find_fea
Arc::new(move || {
let tm = unsafe {
llvm::LLVMRustCreateTargetMachine(
triple.as_ptr(), cpu.as_ptr(), features.as_ptr(),
triple.as_ptr(), cpu.as_ptr(), features.as_ptr(), abi.as_ptr(),
code_model,
reloc_model,
opt_level,

View file

@ -1684,6 +1684,7 @@ extern "C" {
pub fn LLVMRustCreateTargetMachine(Triple: *const c_char,
CPU: *const c_char,
Features: *const c_char,
Abi: *const c_char,
Model: CodeModel,
Reloc: RelocMode,
Level: CodeGenOptLevel,

View file

@ -199,6 +199,8 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
bb: location.block,
index: 2,
});
return; // Don't double count `simd_shuffle` candidates
}
}

View file

@ -793,7 +793,10 @@ pub struct TargetOptions {
pub merge_functions: MergeFunctions,
/// Use platform dependent mcount function
pub target_mcount: String
pub target_mcount: String,
/// LLVM ABI name, corresponds to the '-mabi' parameter available in multilib C compilers
pub llvm_abiname: String,
}
impl Default for TargetOptions {
@ -880,6 +883,7 @@ impl Default for TargetOptions {
override_export_symbols: None,
merge_functions: MergeFunctions::Aliases,
target_mcount: "mcount".to_string(),
llvm_abiname: "".to_string(),
}
}
}
@ -1196,6 +1200,7 @@ impl Target {
key!(override_export_symbols, opt_list);
key!(merge_functions, MergeFunctions)?;
key!(target_mcount);
key!(llvm_abiname);
if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
for name in array.iter().filter_map(|abi| abi.as_string()) {
@ -1414,6 +1419,7 @@ impl ToJson for Target {
target_option_val!(override_export_symbols);
target_option_val!(merge_functions);
target_option_val!(target_mcount);
target_option_val!(llvm_abiname);
if default.abi_blacklist != self.options.abi_blacklist {
d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()

View file

@ -1,6 +1,7 @@
use rustc::hir::def_id::DefId;
use rustc::infer::canonical::{Canonical, QueryResponse};
use rustc::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint};
use rustc::traits::query::dropck_outlives::trivial_dropck_outlives;
use rustc::traits::query::{CanonicalTyGoal, NoSolution};
use rustc::traits::{TraitEngine, Normalized, ObligationCause, TraitEngineExt};
use rustc::ty::query::Providers;
@ -172,7 +173,7 @@ fn dtorck_constraint_for_ty<'tcx>(
return Ok(());
}
if tcx.trivial_dropck_outlives(ty) {
if trivial_dropck_outlives(tcx, ty) {
return Ok(());
}

View file

@ -163,59 +163,71 @@ function getSearchElement() {
var main = document.getElementById("main");
function highlightSourceLines(ev) {
// If we're in mobile mode, we should add the sidebar in any case.
function onHashChange(ev) {
// If we're in mobile mode, we should hide the sidebar in any case.
hideSidebar();
var elem;
var search = getSearchElement();
var i, from, to, match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
var match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
if (match) {
from = parseInt(match[1], 10);
to = from;
if (typeof match[2] !== "undefined") {
to = parseInt(match[2], 10);
}
if (to < from) {
var tmp = to;
to = from;
from = tmp;
}
elem = document.getElementById(from);
if (!elem) {
return;
}
if (ev === null) {
var x = document.getElementById(from);
if (x) {
x.scrollIntoView();
}
}
onEachLazy(document.getElementsByClassName("line-numbers"), function(e) {
onEachLazy(e.getElementsByTagName("span"), function(i_e) {
removeClass(i_e, "line-highlighted");
});
});
for (i = from; i <= to; ++i) {
elem = document.getElementById(i);
if (!elem) {
break;
}
addClass(elem, "line-highlighted");
}
} else if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) {
return highlightSourceLines(match, ev);
}
var search = getSearchElement();
if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) {
addClass(search, "hidden");
removeClass(main, "hidden");
var hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
if (browserSupportsHistoryApi()) {
history.replaceState(hash, "", "?search=#" + hash);
}
elem = document.getElementById(hash);
var elem = document.getElementById(hash);
if (elem) {
elem.scrollIntoView();
}
}
}
function highlightSourceLines(match, ev) {
if (typeof match === "undefined") {
// If we're in mobile mode, we should hide the sidebar in any case.
hideSidebar();
match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
}
if (!match) {
return;
}
var from = parseInt(match[1], 10);
var to = from;
if (typeof match[2] !== "undefined") {
to = parseInt(match[2], 10);
}
if (to < from) {
var tmp = to;
to = from;
from = tmp;
}
var elem = document.getElementById(from);
if (!elem) {
return;
}
if (!ev) {
var x = document.getElementById(from);
if (x) {
x.scrollIntoView();
}
}
onEachLazy(document.getElementsByClassName("line-numbers"), function(e) {
onEachLazy(e.getElementsByTagName("span"), function(i_e) {
removeClass(i_e, "line-highlighted");
});
});
for (var i = from; i <= to; ++i) {
elem = document.getElementById(i);
if (!elem) {
break;
}
addClass(elem, "line-highlighted");
}
}
function expandSection(id) {
var elem = document.getElementById(id);
if (elem && isHidden(elem)) {
@ -234,8 +246,8 @@ function getSearchElement() {
}
}
highlightSourceLines(null);
window.onhashchange = highlightSourceLines;
highlightSourceLines();
window.onhashchange = onHashChange;
// Gets the human-readable string for the virtual-key code of the
// given KeyboardEvent, ev.
@ -358,7 +370,7 @@ function getSearchElement() {
var set_fragment = function(name) {
if (browserSupportsHistoryApi()) {
history.replaceState(null, null, "#" + name);
highlightSourceLines(null);
highlightSourceLines();
} else {
location.replace("#" + name);
}

View file

@ -287,7 +287,8 @@ pub fn temp_dir() -> PathBuf {
}
pub fn home_dir() -> Option<PathBuf> {
None
crate::env::var_os("HOME").or_else(|| None
).map(PathBuf::from)
}
pub fn exit(code: i32) -> ! {

View file

@ -68,7 +68,7 @@ impl<'a> StringReader<'a> {
let end = sess.source_map().lookup_byte_offset(span.hi());
// Make the range zero-length if the span is invalid.
if span.lo() > span.hi() || begin.sf.start_pos != end.sf.start_pos {
if begin.sf.start_pos != end.sf.start_pos {
span = span.shrink_to_lo();
}

View file

@ -498,10 +498,6 @@ impl SourceMap {
pub fn span_to_lines(&self, sp: Span) -> FileLinesResult {
debug!("span_to_lines(sp={:?})", sp);
if sp.lo() > sp.hi() {
return Err(SpanLinesError::IllFormedSpan(sp));
}
let lo = self.lookup_char_pos(sp.lo());
debug!("span_to_lines: lo={:?}", lo);
let hi = self.lookup_char_pos(sp.hi());
@ -549,10 +545,6 @@ impl SourceMap {
fn span_to_source<F>(&self, sp: Span, extract_source: F) -> Result<String, SpanSnippetError>
where F: Fn(&str, usize, usize) -> Result<String, SpanSnippetError>
{
if sp.lo() > sp.hi() {
return Err(SpanSnippetError::IllFormedSpan(sp));
}
let local_begin = self.lookup_byte_offset(sp.lo());
let local_end = self.lookup_byte_offset(sp.hi());
@ -762,14 +754,14 @@ impl SourceMap {
/// Finds the width of a character, either before or after the provided span.
fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
// Disregard malformed spans and assume a one-byte wide character.
if sp.lo() >= sp.hi() {
debug!("find_width_of_character_at_span: early return malformed span");
let sp = sp.data();
if sp.lo == sp.hi {
debug!("find_width_of_character_at_span: early return empty span");
return 1;
}
let local_begin = self.lookup_byte_offset(sp.lo());
let local_end = self.lookup_byte_offset(sp.hi());
let local_begin = self.lookup_byte_offset(sp.lo);
let local_end = self.lookup_byte_offset(sp.hi);
debug!("find_width_of_character_at_span: local_begin=`{:?}`, local_end=`{:?}`",
local_begin, local_end);

View file

@ -1512,7 +1512,6 @@ pub type FileLinesResult = Result<FileLines, SpanLinesError>;
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum SpanLinesError {
IllFormedSpan(Span),
DistinctSources(DistinctSources),
}

View file

@ -343,7 +343,7 @@ extern "C" const char* LLVMRustGetHostCPUName(size_t *len) {
extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
const char *TripleStr, const char *CPU, const char *Feature,
LLVMRustCodeModel RustCM, LLVMRustRelocMode RustReloc,
const char *ABIStr, LLVMRustCodeModel RustCM, LLVMRustRelocMode RustReloc,
LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat,
bool PositionIndependentExecutable, bool FunctionSections,
bool DataSections,
@ -374,6 +374,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
Options.FunctionSections = FunctionSections;
Options.MCOptions.AsmVerbose = AsmComments;
Options.MCOptions.PreserveAsmComments = AsmComments;
Options.MCOptions.ABIName = ABIStr;
if (TrapUnreachable) {
// Tell LLVM to codegen `unreachable` into an explicit trap instruction.

View file

@ -7,3 +7,4 @@ edition = "2018"
[dependencies]
toml = "0.5"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

View file

@ -11,10 +11,11 @@ use serde::Serialize;
use std::collections::BTreeMap;
use std::env;
use std::fs;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::{PathBuf, Path};
use std::process::{Command, Stdio};
use std::collections::HashMap;
static HOSTS: &[&str] = &[
"aarch64-unknown-linux-gnu",
@ -366,6 +367,7 @@ impl Builder {
self.lldb_git_commit_hash = self.git_commit_hash("lldb", "x86_64-unknown-linux-gnu");
self.miri_git_commit_hash = self.git_commit_hash("miri", "x86_64-unknown-linux-gnu");
self.check_toolstate();
self.digest_and_sign();
let manifest = self.build_manifest();
self.write_channel_files(&self.rust_release, &manifest);
@ -375,6 +377,25 @@ impl Builder {
}
}
/// If a tool does not pass its tests, don't ship it.
/// Right now, we do this only for Miri.
fn check_toolstate(&mut self) {
let toolstates: Option<HashMap<String, String>> =
File::open(self.input.join("toolstates-linux.json")).ok()
.and_then(|f| serde_json::from_reader(&f).ok());
let toolstates = toolstates.unwrap_or_else(|| {
println!("WARNING: `toolstates-linux.json` missing/malformed; \
assuming all tools failed");
HashMap::default() // Use empty map if anything went wrong.
});
// Mark some tools as missing based on toolstate.
if toolstates.get("miri").map(|s| &*s as &str) != Some("test-pass") {
println!("Miri tests are not passing, removing component");
self.miri_version = None;
self.miri_git_commit_hash = None;
}
}
/// Hash all files, compute their signatures, and collect the hashes in `self.digests`.
fn digest_and_sign(&mut self) {
for file in t!(self.input.read_dir()).map(|e| t!(e).path()) {