Auto merge of #64510 - Centril:rollup-m03zsq8, r=Centril

Rollup of 10 pull requests

Successful merges:

 - #63955 (Make sure interned constants are immutable)
 - #64028 (Stabilize `Vec::new` and `String::new` as `const fn`s)
 - #64119 (ci: ensure all tool maintainers are assignable on issues)
 - #64444 (fix building libstd without backtrace feature)
 - #64446 (Fix build script sanitizer check.)
 - #64451 (when Miri tests are not passing, do not add Miri component)
 - #64467 (Hide diagnostics emitted during --cfg parsing)
 - #64497 (Don't print the "total" `-Ztime-passes` output if `--prints=...` is also given)
 - #64499 (Use `Symbol` in two more functions.)
 - #64504 (use println!() instead of println!(""))

Failed merges:

r? @ghost
This commit is contained in:
bors 2019-09-16 15:35:48 +00:00
commit a44881d892
39 changed files with 478 additions and 247 deletions

View File

@ -201,7 +201,9 @@ dependencies = [
name = "build-manifest"
version = "0.1.0"
dependencies = [
"reqwest",
"serde",
"serde_json",
"toml",
]

View File

@ -2000,6 +2000,8 @@ impl Step for HashSign {
}
fn run(self, builder: &Builder<'_>) {
// This gets called by `promote-release`
// (https://github.com/rust-lang/rust-central-station/tree/master/promote-release).
let mut cmd = builder.tool_cmd(Tool::BuildManifest);
if builder.config.dry_run {
return;
@ -2010,10 +2012,14 @@ impl Step for HashSign {
let addr = builder.config.dist_upload_addr.as_ref().unwrap_or_else(|| {
panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n")
});
let pass = if env::var("BUILD_MANIFEST_DISABLE_SIGNING").is_err() {
let file = builder.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| {
panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n")
});
let pass = t!(fs::read_to_string(&file));
t!(fs::read_to_string(&file))
} else {
String::new()
};
let today = output(Command::new("date").arg("+%Y-%m-%d"));

View File

@ -147,8 +147,15 @@ steps:
git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git
cd rust-toolstate
python2.7 "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "" ""
# Only check maintainers if this build is supposed to publish toolstate.
# Builds that are not supposed to publish don't have the access token.
if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then
TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python2.7 "${BUILD_SOURCESDIRECTORY}/src/tools/publish_toolstate.py"
fi
cd ..
rm -rf rust-toolstate
env:
TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN)
condition: and(succeeded(), not(variables.SKIP_JOB), eq(variables['IMAGE'], 'mingw-check'))
displayName: Verify the publish_toolstate script works

View File

@ -117,7 +117,7 @@
#![feature(allocator_internals)]
#![feature(on_unimplemented)]
#![feature(rustc_const_unstable)]
#![feature(const_vec_new)]
#![cfg_attr(bootstrap, feature(const_vec_new))]
#![feature(slice_partition_dedup)]
#![feature(maybe_uninit_extra, maybe_uninit_slice)]
#![feature(alloc_layout_extra)]

View File

@ -113,13 +113,38 @@ impl<T, A: Alloc> RawVec<T, A> {
}
impl<T> RawVec<T, Global> {
/// HACK(Centril): This exists because `#[unstable]` `const fn`s needn't conform
/// to `min_const_fn` and so they cannot be called in `min_const_fn`s either.
///
/// If you change `RawVec<T>::new` or dependencies, please take care to not
/// introduce anything that would truly violate `min_const_fn`.
///
/// NOTE: We could avoid this hack and check conformance with some
/// `#[rustc_force_min_const_fn]` attribute which requires conformance
/// with `min_const_fn` but does not necessarily allow calling it in
/// `stable(...) const fn` / user code not enabling `foo` when
/// `#[rustc_const_unstable(feature = "foo", ..)]` is present.
pub const NEW: Self = Self::new();
/// Creates the biggest possible `RawVec` (on the system heap)
/// without allocating. If `T` has positive size, then this makes a
/// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a
/// `RawVec` with capacity `usize::MAX`. Useful for implementing
/// delayed allocation.
pub const fn new() -> Self {
Self::new_in(Global)
// FIXME(Centril): Reintegrate this with `fn new_in` when we can.
// `!0` is `usize::MAX`. This branch should be stripped at compile time.
// FIXME(mark-i-m): use this line when `if`s are allowed in `const`:
//let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
// `Unique::empty()` doubles as "unallocated" and "zero-sized allocation".
RawVec {
ptr: Unique::empty(),
// FIXME(mark-i-m): use `cap` when ifs are allowed in const
cap: [0, !0][(mem::size_of::<T>() == 0) as usize],
a: Global,
}
}
/// Creates a `RawVec` (on the system heap) with exactly the

View File

@ -369,7 +369,7 @@ impl String {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_string_new")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_string_new"))]
pub const fn new() -> String {
String { vec: Vec::new() }
}

View File

@ -314,10 +314,10 @@ impl<T> Vec<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_vec_new")]
#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_vec_new"))]
pub const fn new() -> Vec<T> {
Vec {
buf: RawVec::new(),
buf: RawVec::NEW,
len: 0,
}
}

View File

@ -7,6 +7,7 @@ use crate::session::{early_error, early_warn, Session};
use crate::session::search_paths::SearchPath;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
use rustc_target::spec::{Target, TargetTriple};
@ -19,6 +20,7 @@ use syntax::parse::{ParseSess, new_parser_from_source_str};
use syntax::parse::token;
use syntax::symbol::{sym, Symbol};
use syntax::feature_gate::UnstableFeatures;
use syntax::source_map::SourceMap;
use errors::emitter::HumanReadableErrorType;
use errors::{ColorConfig, FatalError, Handler};
@ -1850,11 +1852,20 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
opts
}
struct NullEmitter;
impl errors::emitter::Emitter for NullEmitter {
fn emit_diagnostic(&mut self, _: &errors::DiagnosticBuilder<'_>) {}
}
// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
syntax::with_default_globals(move || {
let cfg = cfgspecs.into_iter().map(|s| {
let sess = ParseSess::new(FilePathMapping::empty());
let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
let handler = Handler::with_emitter(false, None, Box::new(NullEmitter));
let sess = ParseSess::with_span_handler(handler, cm);
let filename = FileName::cfg_spec_source_code(&s);
let mut parser = new_parser_from_source_str(&sess, filename, s.to_string());

View File

@ -4,6 +4,7 @@ use build_helper::sanitizer_lib_boilerplate;
use cmake::Config;
fn main() {
println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS");
if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
return;
}

View File

@ -226,21 +226,21 @@ impl CodegenBackend for LlvmCodegenBackend {
for &(name, _) in back::write::RELOC_MODEL_ARGS.iter() {
println!(" {}", name);
}
println!("");
println!();
}
PrintRequest::CodeModels => {
println!("Available code models:");
for &(name, _) in back::write::CODE_GEN_MODEL_ARGS.iter(){
println!(" {}", name);
}
println!("");
println!();
}
PrintRequest::TlsModels => {
println!("Available TLS models:");
for &(name, _) in back::write::TLS_MODEL_ARGS.iter(){
println!(" {}", name);
}
println!("");
println!();
}
req => llvm_util::print(req, sess),
}

View File

@ -134,8 +134,11 @@ pub struct TimePassesCallbacks {
impl Callbacks for TimePassesCallbacks {
fn config(&mut self, config: &mut interface::Config) {
// If a --prints=... option has been given, we don't print the "total"
// time because it will mess up the --prints output. See #64339.
self.time_passes =
config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time;
config.opts.prints.is_empty() &&
(config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time);
}
}

View File

@ -4,6 +4,7 @@ use build_helper::sanitizer_lib_boilerplate;
use cmake::Config;
fn main() {
println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS");
if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
return;
}

View File

@ -134,9 +134,8 @@ fn eval_body_using_ecx<'mir, 'tcx>(
ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
cid: GlobalId<'tcx>,
body: &'mir mir::Body<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
debug!("eval_body_using_ecx: {:?}, {:?}", cid, param_env);
debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env);
let tcx = ecx.tcx.tcx;
let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?;
assert!(!layout.is_unsized());
@ -162,7 +161,6 @@ fn eval_body_using_ecx<'mir, 'tcx>(
ecx,
cid.instance.def_id(),
ret,
param_env,
)?;
debug!("eval_body_using_ecx done: {:?}", *ret);
@ -658,7 +656,7 @@ pub fn const_eval_raw_provider<'tcx>(
let res = ecx.load_mir(cid.instance.def, cid.promoted);
res.and_then(
|body| eval_body_using_ecx(&mut ecx, cid, body, key.param_env)
|body| eval_body_using_ecx(&mut ecx, cid, body)
).and_then(|place| {
Ok(RawConst {
alloc_id: place.ptr.assert_ptr().alloc_id,

View File

@ -3,7 +3,7 @@
//! After a const evaluation has computed a value, before we destroy the const evaluator's session
//! memory, we need to extract all memory allocations to the global memory pool so they stay around.
use rustc::ty::{Ty, TyCtxt, ParamEnv, self};
use rustc::ty::{Ty, self};
use rustc::mir::interpret::{InterpResult, ErrorHandled};
use rustc::hir;
use rustc::hir::def_id::DefId;
@ -11,32 +11,29 @@ use super::validity::RefTracking;
use rustc_data_structures::fx::FxHashSet;
use syntax::ast::Mutability;
use syntax_pos::Span;
use super::{
ValueVisitor, MemoryKind, Pointer, AllocId, MPlaceTy, Scalar,
ValueVisitor, MemoryKind, AllocId, MPlaceTy, Scalar,
};
use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext};
struct InternVisitor<'rt, 'mir, 'tcx> {
/// previously encountered safe references
ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>,
/// The ectx from which we intern.
ecx: &'rt mut CompileTimeEvalContext<'mir, 'tcx>,
param_env: ParamEnv<'tcx>,
/// Previously encountered safe references.
ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>,
/// A list of all encountered allocations. After type-based interning, we traverse this list to
/// also intern allocations that are only referenced by a raw pointer or inside a union.
leftover_allocations: &'rt mut FxHashSet<AllocId>,
/// The root node of the value that we're looking at. This field is never mutated and only used
/// for sanity assertions that will ICE when `const_qualif` screws up.
mode: InternMode,
/// This field stores the mutability of the value *currently* being checked.
/// It is set to mutable when an `UnsafeCell` is encountered
/// When recursing across a reference, we don't recurse but store the
/// value to be checked in `ref_tracking` together with the mutability at which we are checking
/// the value.
/// When encountering an immutable reference, we treat everything as immutable that is behind
/// it.
/// When encountering a mutable reference, we determine the pointee mutability
/// taking into account the mutability of the context: `& &mut i32` is entirely immutable,
/// despite the nested mutable reference!
/// The field gets updated when an `UnsafeCell` is encountered.
mutability: Mutability,
/// A list of all encountered relocations. After type-based interning, we traverse this list to
/// also intern allocations that are only referenced by a raw pointer or inside a union.
leftover_relocations: &'rt mut FxHashSet<AllocId>,
}
#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
@ -45,9 +42,10 @@ enum InternMode {
/// `static`. In a `static mut` we start out as mutable and thus can also contain further `&mut`
/// that will actually be treated as mutable.
Static,
/// UnsafeCell is OK in the value of a constant, but not behind references in a constant
/// UnsafeCell is OK in the value of a constant: `const FOO = Cell::new(0)` creates
/// a new cell every time it is used.
ConstBase,
/// `UnsafeCell` ICEs
/// `UnsafeCell` ICEs.
Const,
}
@ -55,28 +53,37 @@ enum InternMode {
/// into the memory of other constants or statics
struct IsStaticOrFn;
impl<'rt, 'mir, 'tcx> InternVisitor<'rt, 'mir, 'tcx> {
/// Intern an allocation without looking at its children
fn intern_shallow(
&mut self,
ptr: Pointer,
/// Intern an allocation without looking at its children.
/// `mode` is the mode of the environment where we found this pointer.
/// `mutablity` is the mutability of the place to be interned; even if that says
/// `immutable` things might become mutable if `ty` is not frozen.
/// `ty` can be `None` if there is no potential interior mutability
/// to account for (e.g. for vtables).
fn intern_shallow<'rt, 'mir, 'tcx>(
ecx: &'rt mut CompileTimeEvalContext<'mir, 'tcx>,
leftover_allocations: &'rt mut FxHashSet<AllocId>,
mode: InternMode,
alloc_id: AllocId,
mutability: Mutability,
ty: Option<Ty<'tcx>>,
) -> InterpResult<'tcx, Option<IsStaticOrFn>> {
trace!(
"InternVisitor::intern {:?} with {:?}",
ptr, mutability,
alloc_id, mutability,
);
// remove allocation
let tcx = self.ecx.tcx;
let memory = self.ecx.memory_mut();
let (kind, mut alloc) = match memory.alloc_map.remove(&ptr.alloc_id) {
let tcx = ecx.tcx;
let memory = ecx.memory_mut();
let (kind, mut alloc) = match memory.alloc_map.remove(&alloc_id) {
Some(entry) => entry,
None => {
// if the pointer is dangling (neither in local nor global memory), we leave it
// Pointer not found in local memory map. It is either a pointer to the global
// map, or dangling.
// If the pointer is dangling (neither in local nor global memory), we leave it
// to validation to error. The `delay_span_bug` ensures that we don't forget such
// a check in validation.
if tcx.alloc_map.lock().get(ptr.alloc_id).is_none() {
tcx.sess.delay_span_bug(self.ecx.tcx.span, "tried to intern dangling pointer");
if tcx.alloc_map.lock().get(alloc_id).is_none() {
tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer");
}
// treat dangling pointers like other statics
// just to stop trying to recurse into them
@ -88,16 +95,59 @@ impl<'rt, 'mir, 'tcx> InternVisitor<'rt, 'mir, 'tcx> {
match kind {
MemoryKind::Stack | MemoryKind::Vtable => {},
}
// Ensure llvm knows to only put this into immutable memory if the value is immutable either
// by being behind a reference or by being part of a static or const without interior
// mutability
alloc.mutability = mutability;
// Set allocation mutability as appropriate. This is used by LLVM to put things into
// read-only memory, and also by Miri when evluating other constants/statics that
// access this one.
if mode == InternMode::Static {
// When `ty` is `None`, we assume no interior mutability.
let frozen = ty.map_or(true, |ty| ty.is_freeze(
ecx.tcx.tcx,
ecx.param_env,
ecx.tcx.span,
));
// For statics, allocation mutability is the combination of the place mutability and
// the type mutability.
// The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere.
if mutability == Mutability::Immutable && frozen {
alloc.mutability = Mutability::Immutable;
} else {
// Just making sure we are not "upgrading" an immutable allocation to mutable.
assert_eq!(alloc.mutability, Mutability::Mutable);
}
} else {
// We *could* be non-frozen at `ConstBase`, for constants like `Cell::new(0)`.
// But we still intern that as immutable as the memory cannot be changed once the
// initial value was computed.
// Constants are never mutable.
assert_eq!(
mutability, Mutability::Immutable,
"Something went very wrong: mutability requested for a constant"
);
alloc.mutability = Mutability::Immutable;
};
// link the alloc id to the actual allocation
let alloc = tcx.intern_const_alloc(alloc);
self.leftover_relocations.extend(alloc.relocations().iter().map(|&(_, ((), reloc))| reloc));
tcx.alloc_map.lock().set_alloc_id_memory(ptr.alloc_id, alloc);
leftover_allocations.extend(alloc.relocations().iter().map(|&(_, ((), reloc))| reloc));
tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc);
Ok(None)
}
impl<'rt, 'mir, 'tcx> InternVisitor<'rt, 'mir, 'tcx> {
fn intern_shallow(
&mut self,
alloc_id: AllocId,
mutability: Mutability,
ty: Option<Ty<'tcx>>,
) -> InterpResult<'tcx, Option<IsStaticOrFn>> {
intern_shallow(
self.ecx,
self.leftover_allocations,
self.mode,
alloc_id,
mutability,
ty,
)
}
}
impl<'rt, 'mir, 'tcx>
@ -119,14 +169,16 @@ for
) -> InterpResult<'tcx> {
if let Some(def) = mplace.layout.ty.ty_adt_def() {
if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() {
// We are crossing over an `UnsafeCell`, we can mutate again
// We are crossing over an `UnsafeCell`, we can mutate again. This means that
// References we encounter inside here are interned as pointing to mutable
// allocations.
let old = std::mem::replace(&mut self.mutability, Mutability::Mutable);
assert_ne!(
self.mode, InternMode::Const,
"UnsafeCells are not allowed behind references in constants. This should have \
been prevented statically by const qualification. If this were allowed one \
would be able to change a constant at one use site and other use sites may \
arbitrarily decide to change, too.",
would be able to change a constant at one use site and other use sites could \
observe that mutation.",
);
let walked = self.walk_aggregate(mplace, fields);
self.mutability = old;
@ -145,12 +197,13 @@ for
// Handle trait object vtables
if let Ok(meta) = value.to_meta() {
if let ty::Dynamic(..) =
self.ecx.tcx.struct_tail_erasing_lifetimes(referenced_ty, self.param_env).sty
self.ecx.tcx.struct_tail_erasing_lifetimes(
referenced_ty, self.ecx.param_env).sty
{
if let Ok(vtable) = meta.unwrap().to_ptr() {
// explitly choose `Immutable` here, since vtables are immutable, even
// if the reference of the fat pointer is mutable
self.intern_shallow(vtable, Mutability::Immutable)?;
self.intern_shallow(vtable.alloc_id, Mutability::Immutable, None)?;
}
}
}
@ -177,7 +230,7 @@ for
(InternMode::Const, hir::Mutability::MutMutable) => {
match referenced_ty.sty {
ty::Array(_, n)
if n.eval_usize(self.ecx.tcx.tcx, self.param_env) == 0 => {}
if n.eval_usize(self.ecx.tcx.tcx, self.ecx.param_env) == 0 => {}
ty::Slice(_)
if value.to_meta().unwrap().unwrap().to_usize(self.ecx)? == 0 => {}
_ => bug!("const qualif failed to prevent mutable references"),
@ -195,21 +248,13 @@ for
(Mutability::Mutable, hir::Mutability::MutMutable) => Mutability::Mutable,
_ => Mutability::Immutable,
};
// Compute the mutability of the allocation
let intern_mutability = intern_mutability(
self.ecx.tcx.tcx,
self.param_env,
mplace.layout.ty,
self.ecx.tcx.span,
mutability,
);
// Recursing behind references changes the intern mode for constants in order to
// cause assertions to trigger if we encounter any `UnsafeCell`s.
let mode = match self.mode {
InternMode::ConstBase => InternMode::Const,
other => other,
};
match self.intern_shallow(ptr, intern_mutability)? {
match self.intern_shallow(ptr.alloc_id, mutability, Some(mplace.layout.ty))? {
// No need to recurse, these are interned already and statics may have
// cycles, so we don't want to recurse there
Some(IsStaticOrFn) => {},
@ -224,69 +269,45 @@ for
}
}
/// Figure out the mutability of the allocation.
/// Mutable if it has interior mutability *anywhere* in the type.
fn intern_mutability<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
mutability: Mutability,
) -> Mutability {
let has_interior_mutability = !ty.is_freeze(tcx, param_env, span);
if has_interior_mutability {
Mutability::Mutable
} else {
mutability
}
}
pub fn intern_const_alloc_recursive(
ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
def_id: DefId,
ret: MPlaceTy<'tcx>,
// FIXME(oli-obk): can we scrap the param env? I think we can, the final value of a const eval
// must always be monomorphic, right?
param_env: ty::ParamEnv<'tcx>,
) -> InterpResult<'tcx> {
let tcx = ecx.tcx;
// this `mutability` is the mutability of the place, ignoring the type
let (mutability, base_intern_mode) = match tcx.static_mutability(def_id) {
let (base_mutability, base_intern_mode) = match tcx.static_mutability(def_id) {
Some(hir::Mutability::MutImmutable) => (Mutability::Immutable, InternMode::Static),
None => (Mutability::Immutable, InternMode::ConstBase),
// `static mut` doesn't care about interior mutability, it's mutable anyway
Some(hir::Mutability::MutMutable) => (Mutability::Mutable, InternMode::Static),
// consts, promoteds. FIXME: what about array lengths, array initializers?
None => (Mutability::Immutable, InternMode::ConstBase),
};
// type based interning
let mut ref_tracking = RefTracking::new((ret, mutability, base_intern_mode));
let leftover_relocations = &mut FxHashSet::default();
// This mutability is the combination of the place mutability and the type mutability. If either
// is mutable, `alloc_mutability` is mutable. This exists because the entire allocation needs
// to be mutable if it contains an `UnsafeCell` anywhere. The other `mutability` exists so that
// the visitor does not treat everything outside the `UnsafeCell` as mutable.
let alloc_mutability = intern_mutability(
tcx.tcx, param_env, ret.layout.ty, tcx.span, mutability,
);
// Type based interning.
// `ref_tracking` tracks typed references we have seen and still need to crawl for
// more typed information inside them.
// `leftover_allocations` collects *all* allocations we see, because some might not
// be available in a typed way. They get interned at the end.
let mut ref_tracking = RefTracking::new((ret, base_mutability, base_intern_mode));
let leftover_allocations = &mut FxHashSet::default();
// start with the outermost allocation
InternVisitor {
ref_tracking: &mut ref_tracking,
intern_shallow(
ecx,
mode: base_intern_mode,
leftover_relocations,
param_env,
mutability,
}.intern_shallow(ret.ptr.to_ptr()?, alloc_mutability)?;
leftover_allocations,
base_intern_mode,
ret.ptr.to_ptr()?.alloc_id,
base_mutability,
Some(ret.layout.ty)
)?;
while let Some(((mplace, mutability, mode), _)) = ref_tracking.todo.pop() {
let interned = InternVisitor {
ref_tracking: &mut ref_tracking,
ecx,
mode,
leftover_relocations,
param_env,
leftover_allocations,
mutability,
}.visit_value(mplace);
if let Err(error) = interned {
@ -309,15 +330,23 @@ pub fn intern_const_alloc_recursive(
// Intern the rest of the allocations as mutable. These might be inside unions, padding, raw
// pointers, ... So we can't intern them according to their type rules
let mut todo: Vec<_> = leftover_relocations.iter().cloned().collect();
let mut todo: Vec<_> = leftover_allocations.iter().cloned().collect();
while let Some(alloc_id) = todo.pop() {
if let Some((_, alloc)) = ecx.memory_mut().alloc_map.remove(&alloc_id) {
// We can't call the `intern` method here, as its logic is tailored to safe references.
// So we hand-roll the interning logic here again
if let Some((_, mut alloc)) = ecx.memory_mut().alloc_map.remove(&alloc_id) {
// We can't call the `intern_shallow` method here, as its logic is tailored to safe
// references and a `leftover_allocations` set (where we only have a todo-list here).
// So we hand-roll the interning logic here again.
if base_intern_mode != InternMode::Static {
// If it's not a static, it *must* be immutable.
// We cannot have mutable memory inside a constant.
// FIXME: ideally we would assert that they already are immutable, to double-
// check our static checks.
alloc.mutability = Mutability::Immutable;
}
let alloc = tcx.intern_const_alloc(alloc);
tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc);
for &(_, ((), reloc)) in alloc.relocations().iter() {
if leftover_relocations.insert(reloc) {
if leftover_allocations.insert(reloc) {
todo.push(reloc);
}
}

View File

@ -4,6 +4,7 @@ use build_helper::sanitizer_lib_boilerplate;
use cmake::Config;
fn main() {
println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS");
if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
return;
}

View File

@ -4,6 +4,7 @@ use build_helper::sanitizer_lib_boilerplate;
use cmake::Config;
fn main() {
println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS");
if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
return;
}

View File

@ -25,17 +25,11 @@ profiler_builtins = { path = "../libprofiler_builtins", optional = true }
unwind = { path = "../libunwind" }
hashbrown = { version = "0.5.0", features = ['rustc-dep-of-std'] }
[dependencies.backtrace]
[dependencies.backtrace_rs]
package = "backtrace"
version = "0.3.37"
default-features = false # don't use coresymbolication on OSX
features = [
"rustc-dep-of-std", # enable build support for integrating into libstd
"dbghelp", # backtrace/symbolize on MSVC
"libbacktrace", # symbolize on most platforms
"libunwind", # backtrace on most platforms
"dladdr", # symbolize on platforms w/o libbacktrace
]
optional = true
default-features = false # without the libstd `backtrace` feature, stub out everything
features = [ "rustc-dep-of-std" ] # enable build support for integrating into libstd
[dev-dependencies]
rand = "0.7"
@ -65,6 +59,13 @@ cc = "1.0"
[features]
default = ["std_detect_file_io", "std_detect_dlsym_getauxval"]
backtrace = [
"backtrace_rs/dbghelp", # backtrace/symbolize on MSVC
"backtrace_rs/libbacktrace", # symbolize on most platforms
"backtrace_rs/libunwind", # backtrace on most platforms
"backtrace_rs/dladdr", # symbolize on platforms w/o libbacktrace
]
panic-unwind = ["panic_unwind"]
profiler = ["profiler_builtins"]
compiler-builtins-c = ["alloc/compiler-builtins-c"]

View File

@ -97,6 +97,7 @@ use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use crate::sync::Mutex;
use crate::sys_common::backtrace::{output_filename, lock};
use crate::vec::Vec;
use backtrace_rs as backtrace;
use backtrace::BytesOrWideString;
/// A captured OS thread stack backtrace.

View File

@ -17,8 +17,7 @@ use crate::ptr;
use crate::raw;
use crate::sys::stdio::panic_output;
use crate::sys_common::rwlock::RWLock;
use crate::sys_common::thread_info;
use crate::sys_common::util;
use crate::sys_common::{thread_info, util, backtrace};
use crate::thread;
#[cfg(not(test))]
@ -157,20 +156,18 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
}
fn default_hook(info: &PanicInfo<'_>) {
#[cfg(feature = "backtrace")]
use crate::sys_common::{backtrace as backtrace_mod};
// If this is a double panic, make sure that we print a backtrace
// for this panic. Otherwise only print it if logging is enabled.
#[cfg(feature = "backtrace")]
let log_backtrace = {
let log_backtrace = if cfg!(feature = "backtrace") {
let panics = update_panic_count(0);
if panics >= 2 {
Some(backtrace::PrintFmt::Full)
Some(backtrace_rs::PrintFmt::Full)
} else {
backtrace_mod::log_enabled()
backtrace::log_enabled()
}
} else {
None
};
// The current implementation always returns `Some`.
@ -190,14 +187,13 @@ fn default_hook(info: &PanicInfo<'_>) {
let _ = writeln!(err, "thread '{}' panicked at '{}', {}",
name, msg, location);
#[cfg(feature = "backtrace")]
{
if cfg!(feature = "backtrace") {
use crate::sync::atomic::{AtomicBool, Ordering};
static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
if let Some(format) = log_backtrace {
let _ = backtrace_mod::print(err, format);
let _ = backtrace::print(err, format);
} else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
let _ = writeln!(err, "note: run with `RUST_BACKTRACE=1` \
environment variable to display a backtrace.");

View File

@ -422,7 +422,7 @@ impl fmt::Debug for ChildStderr {
/// // Execute `ls` in the current directory of the program.
/// list_dir.status().expect("process failed to execute");
///
/// println!("");
/// println!();
///
/// // Change `ls` to execute in the root directory.
/// list_dir.current_dir("/");

View File

@ -7,10 +7,9 @@ use crate::io;
use crate::borrow::Cow;
use crate::io::prelude::*;
use crate::path::{self, Path, PathBuf};
use crate::sync::atomic::{self, Ordering};
use crate::sys::mutex::Mutex;
use backtrace::{BacktraceFmt, BytesOrWideString, PrintFmt};
use backtrace_rs::{BacktraceFmt, BytesOrWideString, PrintFmt};
/// Max number of frames to print.
const MAX_NB_FRAMES: usize = 100;
@ -74,14 +73,14 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
bt_fmt.add_context()?;
let mut idx = 0;
let mut res = Ok(());
backtrace::trace_unsynchronized(|frame| {
backtrace_rs::trace_unsynchronized(|frame| {
if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
return false;
}
let mut hit = false;
let mut stop = false;
backtrace::resolve_frame_unsynchronized(frame, |symbol| {
backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
hit = true;
if print_fmt == PrintFmt::Short {
if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
@ -130,6 +129,8 @@ where
// For now logging is turned off by default, and this function checks to see
// whether the magical environment variable is present to see if it's turned on.
pub fn log_enabled() -> Option<PrintFmt> {
use crate::sync::atomic::{self, Ordering};
// Setting environment variables for Fuchsia components isn't a standard
// or easily supported workflow. For now, always display backtraces.
if cfg!(target_os = "fuchsia") {

View File

@ -41,7 +41,6 @@ macro_rules! rtunwrap {
pub mod alloc;
pub mod at_exit_imp;
#[cfg(feature = "backtrace")]
pub mod backtrace;
pub mod condvar;
pub mod io;

View File

@ -877,9 +877,9 @@ fn check_matcher_core(
// Now `last` holds the complete set of NT tokens that could
// end the sequence before SUFFIX. Check that every one works with `suffix`.
'each_last: for token in &last.tokens {
if let TokenTree::MetaVarDecl(_, ref name, ref frag_spec) = *token {
if let TokenTree::MetaVarDecl(_, name, frag_spec) = *token {
for next_token in &suffix_first.tokens {
match is_in_follow(next_token, &frag_spec.as_str()) {
match is_in_follow(next_token, frag_spec.name) {
IsInFollow::Invalid(msg, help) => {
sess.span_diagnostic
.struct_span_err(next_token.span(), &msg)
@ -948,7 +948,7 @@ fn check_matcher_core(
fn token_can_be_followed_by_any(tok: &quoted::TokenTree) -> bool {
if let quoted::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok {
frag_can_be_followed_by_any(&frag_spec.as_str())
frag_can_be_followed_by_any(frag_spec.name)
} else {
// (Non NT's can always be followed by anthing in matchers.)
true
@ -963,15 +963,15 @@ fn token_can_be_followed_by_any(tok: &quoted::TokenTree) -> bool {
/// specifier which consumes at most one token tree can be followed by
/// a fragment specifier (indeed, these fragments can be followed by
/// ANYTHING without fear of future compatibility hazards).
fn frag_can_be_followed_by_any(frag: &str) -> bool {
fn frag_can_be_followed_by_any(frag: Symbol) -> bool {
match frag {
"item" | // always terminated by `}` or `;`
"block" | // exactly one token tree
"ident" | // exactly one token tree
"literal" | // exactly one token tree
"meta" | // exactly one token tree
"lifetime" | // exactly one token tree
"tt" => // exactly one token tree
sym::item | // always terminated by `}` or `;`
sym::block | // exactly one token tree
sym::ident | // exactly one token tree
sym::literal | // exactly one token tree
sym::meta | // exactly one token tree
sym::lifetime | // exactly one token tree
sym::tt => // exactly one token tree
true,
_ =>
@ -993,7 +993,7 @@ enum IsInFollow {
/// break macros that were relying on that binary operator as a
/// separator.
// when changing this do not forget to update doc/book/macros.md!
fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> IsInFollow {
fn is_in_follow(tok: &quoted::TokenTree, frag: Symbol) -> IsInFollow {
use quoted::TokenTree;
if let TokenTree::Token(Token { kind: token::CloseDelim(_), .. }) = *tok {
@ -1002,17 +1002,17 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> IsInFollow {
IsInFollow::Yes
} else {
match frag {
"item" => {
sym::item => {
// since items *must* be followed by either a `;` or a `}`, we can
// accept anything after them
IsInFollow::Yes
}
"block" => {
sym::block => {
// anything can follow block, the braces provide an easy boundary to
// maintain
IsInFollow::Yes
}
"stmt" | "expr" => {
sym::stmt | sym::expr => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
match tok {
TokenTree::Token(token) => match token.kind {
@ -1022,7 +1022,7 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> IsInFollow {
_ => IsInFollow::No(TOKENS),
}
}
"pat" => {
sym::pat => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
match tok {
TokenTree::Token(token) => match token.kind {
@ -1033,7 +1033,7 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> IsInFollow {
_ => IsInFollow::No(TOKENS),
}
}
"path" | "ty" => {
sym::path | sym::ty => {
const TOKENS: &[&str] = &[
"`{`", "`[`", "`=>`", "`,`", "`>`", "`=`", "`:`", "`;`", "`|`", "`as`",
"`where`",
@ -1061,20 +1061,20 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> IsInFollow {
_ => IsInFollow::No(TOKENS),
}
}
"ident" | "lifetime" => {
sym::ident | sym::lifetime => {
// being a single token, idents and lifetimes are harmless
IsInFollow::Yes
}
"literal" => {
sym::literal => {
// literals may be of a single token, or two tokens (negative numbers)
IsInFollow::Yes
}
"meta" | "tt" => {
sym::meta | sym::tt => {
// being either a single token or a delimited sequence, tt is
// harmless
IsInFollow::Yes
}
"vis" => {
sym::vis => {
// Explicitly disallow `priv`, on the off chance it comes back.
const TOKENS: &[&str] = &["`,`", "an ident", "a type"];
match tok {
@ -1099,7 +1099,7 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> IsInFollow {
_ => IsInFollow::No(TOKENS),
}
}
"" => IsInFollow::Yes, // kw::Invalid
kw::Invalid => IsInFollow::Yes,
_ => IsInFollow::Invalid(
format!("invalid fragment specifier `{}`", frag),
VALID_FRAGMENT_NAMES_MSG,

View File

@ -242,12 +242,12 @@ fn non_immediate_args(a: BigStruct, b: BigStruct) {
fn binding(a: i64, b: u64, c: f64) {
let x = 0; // #break
println!("")
println!()
}
fn assignment(mut a: u64, b: u64, c: f64) {
a = b; // #break
println!("")
println!()
}
fn function_call(x: u64, y: u64, z: f64) {

View File

@ -1,15 +1,11 @@
// run-pass
// check-pass
#![allow(dead_code)]
// Test several functions can be used for constants
// 1. Vec::new()
// 2. String::new()
#![feature(const_vec_new)]
#![feature(const_string_new)]
const MY_VEC: Vec<usize> = Vec::new();
const MY_STRING: String = String::new();
pub fn main() {}
fn main() {}

View File

@ -0,0 +1,3 @@
// compile-flags: --cfg a{
// error-pattern: invalid `--cfg` argument: `a{` (expected `key` or `key="value"`)
fn main() {}

View File

@ -0,0 +1,2 @@
error: invalid `--cfg` argument: `a{` (expected `key` or `key="value"`)

View File

@ -14,8 +14,9 @@ trait Bar<T, U: Foo<T>> {
impl Foo<u32> for () {
const X: u32 = 42;
}
impl Foo<Vec<u32>> for String {
const X: Vec<u32> = Vec::new(); //~ ERROR not yet stable as a const fn
const X: Vec<u32> = Vec::new();
}
impl Bar<u32, ()> for () {}

View File

@ -4,13 +4,5 @@ error[E0493]: destructors cannot be evaluated at compile-time
LL | const F: u32 = (U::X, 42).1;
| ^^^^^^^^^^ constants cannot evaluate destructors
error: `std::vec::Vec::<T>::new` is not yet stable as a const fn
--> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:18:25
|
LL | const X: Vec<u32> = Vec::new();
| ^^^^^^^^^^
|
= help: add `#![feature(const_vec_new)]` to the crate attributes to enable
error: aborting due to 2 previous errors
error: aborting due to previous error

View File

@ -0,0 +1,20 @@
// compile-flags: -Zunleash-the-miri-inside-of-you
#![feature(const_raw_ptr_deref)]
#![deny(const_err)]
use std::cell::UnsafeCell;
// make sure we do not just intern this as mutable
const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
const MUTATING_BEHIND_RAW: () = {
// Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time.
unsafe {
*MUTABLE_BEHIND_RAW = 99 //~ WARN skipping const checks
//~^ ERROR any use of this value will cause an error
//~^^ tried to modify constant memory
}
};
fn main() {}

View File

@ -0,0 +1,27 @@
warning: skipping const checks
--> $DIR/mutable_const.rs:14:9
|
LL | *MUTABLE_BEHIND_RAW = 99
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: any use of this value will cause an error
--> $DIR/mutable_const.rs:14:9
|
LL | / const MUTATING_BEHIND_RAW: () = {
LL | | // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time.
LL | | unsafe {
LL | | *MUTABLE_BEHIND_RAW = 99
| | ^^^^^^^^^^^^^^^^^^^^^^^^ tried to modify constant memory
... |
LL | | }
LL | | };
| |__-
|
note: lint level defined here
--> $DIR/mutable_const.rs:4:9
|
LL | #![deny(const_err)]
| ^^^^^^^^^
error: aborting due to previous error

View File

@ -6,7 +6,7 @@ LL | *MUH.x.get() = 99;
thread 'rustc' panicked at 'assertion failed: `(left != right)`
left: `Const`,
right: `Const`: UnsafeCells are not allowed behind references in constants. This should have been prevented statically by const qualification. If this were allowed one would be able to change a constant at one use site and other use sites may arbitrarily decide to change, too.', src/librustc_mir/interpret/intern.rs:LL:CC
right: `Const`: UnsafeCells are not allowed behind references in constants. This should have been prevented statically by const qualification. If this were allowed one would be able to change a constant at one use site and other use sites could observe that mutation.', src/librustc_mir/interpret/intern.rs:LL:CC
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
error: internal compiler error: unexpected panic

View File

@ -143,7 +143,7 @@ pub fn main() {
v[0].descend_into_self(&mut c);
assert!(!c.saw_prev_marked); // <-- different from below, b/c acyclic above
if PRINT { println!(""); }
if PRINT { println!(); }
// Cycle 1: { v[0] -> v[1], v[1] -> v[0] };
// does not exercise `v` itself
@ -158,7 +158,7 @@ pub fn main() {
v[0].descend_into_self(&mut c);
assert!(c.saw_prev_marked);
if PRINT { println!(""); }
if PRINT { println!(); }
// Cycle 2: { v[0] -> v, v[1] -> v }
let v: V = Named::new("v");
@ -171,7 +171,7 @@ pub fn main() {
v.descend_into_self(&mut c);
assert!(c.saw_prev_marked);
if PRINT { println!(""); }
if PRINT { println!(); }
// Cycle 3: { hk0 -> hv0, hv0 -> hk0, hk1 -> hv1, hv1 -> hk1 };
// does not exercise `h` itself
@ -193,7 +193,7 @@ pub fn main() {
assert!(c.saw_prev_marked);
}
if PRINT { println!(""); }
if PRINT { println!(); }
// Cycle 4: { h -> (hmk0,hmv0,hmk1,hmv1), {hmk0,hmv0,hmk1,hmv1} -> h }
@ -216,7 +216,7 @@ pub fn main() {
// break;
}
if PRINT { println!(""); }
if PRINT { println!(); }
// Cycle 5: { vd[0] -> vd[1], vd[1] -> vd[0] };
// does not exercise vd itself
@ -232,7 +232,7 @@ pub fn main() {
vd[0].descend_into_self(&mut c);
assert!(c.saw_prev_marked);
if PRINT { println!(""); }
if PRINT { println!(); }
// Cycle 6: { vd -> (vd0, vd1), {vd0, vd1} -> vd }
let mut vd: VecDeque<VD> = VecDeque::new();
@ -247,7 +247,7 @@ pub fn main() {
vd[0].descend_into_self(&mut c);
assert!(c.saw_prev_marked);
if PRINT { println!(""); }
if PRINT { println!(); }
// Cycle 7: { vm -> (vm0, vm1), {vm0, vm1} -> vm }
let mut vm: HashMap<usize, VM> = HashMap::new();
@ -262,7 +262,7 @@ pub fn main() {
vm[&0].descend_into_self(&mut c);
assert!(c.saw_prev_marked);
if PRINT { println!(""); }
if PRINT { println!(); }
// Cycle 8: { ll -> (ll0, ll1), {ll0, ll1} -> ll }
let mut ll: LinkedList<LL> = LinkedList::new();
@ -282,7 +282,7 @@ pub fn main() {
// break;
}
if PRINT { println!(""); }
if PRINT { println!(); }
// Cycle 9: { bh -> (bh0, bh1), {bh0, bh1} -> bh }
let mut bh: BinaryHeap<BH> = BinaryHeap::new();
@ -302,7 +302,7 @@ pub fn main() {
// break;
}
if PRINT { println!(""); }
if PRINT { println!(); }
// Cycle 10: { btm -> (btk0, btv1), {bt0, bt1} -> btm }
let mut btm: BTreeMap<BTM, BTM> = BTreeMap::new();
@ -323,7 +323,7 @@ pub fn main() {
// break;
}
if PRINT { println!(""); }
if PRINT { println!(); }
// Cycle 10: { bts -> (bts0, bts1), {bts0, bts1} -> btm }
let mut bts: BTreeSet<BTS> = BTreeSet::new();
@ -343,7 +343,7 @@ pub fn main() {
// break;
}
if PRINT { println!(""); }
if PRINT { println!(); }
// Cycle 11: { rc0 -> (rc1, rc2), rc1 -> (), rc2 -> rc0 }
let (rc0, rc1, rc2): (RCRC, RCRC, RCRC);
@ -361,7 +361,7 @@ pub fn main() {
rc0.descend_into_self(&mut c);
assert!(c.saw_prev_marked);
if PRINT { println!(""); }
if PRINT { println!(); }
// We want to take the previous Rc case and generalize it to Arc.
//
@ -395,7 +395,7 @@ pub fn main() {
arc0.descend_into_self(&mut c);
assert!(c.saw_prev_marked);
if PRINT { println!(""); }
if PRINT { println!(); }
// Cycle 13: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, rwlocks
let (arc0, arc1, arc2): (ARCRW, ARCRW, ARCRW);
@ -413,7 +413,7 @@ pub fn main() {
arc0.descend_into_self(&mut c);
assert!(c.saw_prev_marked);
if PRINT { println!(""); }
if PRINT { println!(); }
// Cycle 14: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, mutexs
let (arc0, arc1, arc2): (ARCM, ARCM, ARCM);

View File

@ -6,6 +6,6 @@ fn main() {
//~| NOTE `&str` is not an iterator
//~| HELP the trait `std::iter::Iterator` is not implemented for `&str`
//~| NOTE required by `std::iter::IntoIterator::into_iter`
println!("");
println!();
}
}

View File

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

View File

@ -1,12 +1,19 @@
//! Build a dist manifest, hash and sign everything.
//! This gets called by `promote-release`
//! (https://github.com/rust-lang/rust-central-station/tree/master/promote-release)
//! via `x.py dist hash-and-sign`; the cmdline arguments are set up
//! by rustbuild (in `src/bootstrap/dist.rs`).
use toml;
use serde::Serialize;
use std::collections::BTreeMap;
use std::env;
use std::fs;
use std::io::{self, Read, Write};
use std::io::{self, Read, Write, BufRead, BufReader};
use std::path::{PathBuf, Path};
use std::process::{Command, Stdio};
use std::collections::HashMap;
static HOSTS: &[&str] = &[
"aarch64-unknown-linux-gnu",
@ -146,6 +153,9 @@ static MINGW: &[&str] = &[
"x86_64-pc-windows-gnu",
];
static TOOLSTATE: &str =
"https://raw.githubusercontent.com/rust-lang-nursery/rust-toolstate/master/history/linux.tsv";
#[derive(Serialize)]
#[serde(rename_all = "kebab-case")]
struct Manifest {
@ -270,6 +280,7 @@ fn main() {
// Do not ask for a passphrase while manually testing
let mut passphrase = String::new();
if should_sign {
// `x.py` passes the passphrase via stdin.
t!(io::stdin().read_to_string(&mut passphrase));
}
@ -353,6 +364,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);
@ -362,6 +374,37 @@ 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) {
// Get the toolstate for this rust revision.
let rev = self.rust_git_commit_hash.as_ref().expect("failed to determine rust git hash");
let toolstates = reqwest::get(TOOLSTATE).expect("failed to get toolstates");
let toolstates = BufReader::new(toolstates);
let toolstate = toolstates.lines()
.find_map(|line| {
let line = line.expect("failed to read toolstate lines");
let mut pieces = line.splitn(2, '\t');
let commit = pieces.next().expect("malformed toolstate line");
if commit != rev {
// Not the right commit.
return None;
}
// Return the 2nd piece, the JSON.
Some(pieces.next().expect("malformed toolstate line").to_owned())
})
.expect("failed to find toolstate for rust commit");
let toolstate: HashMap<String, String> =
serde_json::from_str(&toolstate).expect("toolstate is malformed JSON");
// Mark some tools as missing based on toolstate.
if toolstate.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()) {
let filename = file.file_name().unwrap().to_str().unwrap();
@ -532,19 +575,20 @@ impl Builder {
.as_ref()
.cloned()
.map(|version| (version, true))
.unwrap_or_default();
.unwrap_or_default(); // `is_present` defaults to `false` here.
// miri needs to build std with xargo, which doesn't allow stable/beta:
// <https://github.com/japaric/xargo/pull/204#issuecomment-374888868>
// Miri is nightly-only; never ship it for other trains.
if pkgname == "miri-preview" && self.rust_release != "nightly" {
is_present = false; // ignore it
is_present = false; // Pretend the component is entirely missing.
}
let targets = targets.iter().map(|name| {
if is_present {
// The component generally exists, but it might still be missing for this target.
let filename = self.filename(pkgname, name);
let digest = match self.digests.remove(&filename) {
Some(digest) => digest,
// This component does not exist for this target -- skip it.
None => return (name.to_string(), Target::unavailable()),
};
let xz_filename = filename.replace(".tar.gz", ".tar.xz");

View File

@ -253,7 +253,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
println!("{}", opts.usage(&message));
println!("");
println!();
panic!()
}
@ -265,7 +265,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
if matches.opt_present("h") || matches.opt_present("help") {
let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
println!("{}", opts.usage(&message));
println!("");
println!();
panic!()
}

View File

@ -2593,7 +2593,7 @@ impl<'test> TestCx<'test> {
" actual: {}",
codegen_units_to_str(&actual_item.codegen_units)
);
println!("");
println!();
}
}
@ -3526,7 +3526,7 @@ impl<'test> TestCx<'test> {
}
}
}
println!("");
println!();
}
}
}

View File

@ -7,6 +7,8 @@
## It is set as callback for `src/ci/docker/x86_64-gnu-tools/repo.sh` by the CI scripts
## when a new commit lands on `master` (i.e., after it passed all checks on `auto`).
from __future__ import print_function
import sys
import re
import os
@ -20,21 +22,26 @@ except ImportError:
import urllib.request as urllib2
# List of people to ping when the status of a tool or a book changed.
# These should be collaborators of the rust-lang/rust repository (with at least
# read privileges on it). CI will fail otherwise.
MAINTAINERS = {
'miri': '@oli-obk @RalfJung @eddyb',
'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk @phansch @flip1995 @yaahc',
'rls': '@Xanewok',
'rustfmt': '@topecongiro',
'book': '@carols10cents @steveklabnik',
'nomicon': '@frewsxcv @Gankro',
'reference': '@steveklabnik @Havvy @matthewjasper @ehuss',
'rust-by-example': '@steveklabnik @marioidival @projektir',
'embedded-book': (
'@adamgreig @andre-richter @jamesmunns @korken89 '
'@ryankurte @thejpster @therealprof'
),
'edition-guide': '@ehuss @Centril @steveklabnik',
'rustc-guide': '@mark-i-m @spastorino @amanjeev'
'miri': {'oli-obk', 'RalfJung', 'eddyb'},
'clippy-driver': {
'Manishearth', 'llogiq', 'mcarton', 'oli-obk', 'phansch', 'flip1995',
'yaahc',
},
'rls': {'Xanewok'},
'rustfmt': {'topecongiro'},
'book': {'carols10cents', 'steveklabnik'},
'nomicon': {'frewsxcv', 'Gankra'},
'reference': {'steveklabnik', 'Havvy', 'matthewjasper', 'ehuss'},
'rust-by-example': {'steveklabnik', 'marioidival'},
'embedded-book': {
'adamgreig', 'andre-richter', 'jamesmunns', 'korken89',
'ryankurte', 'thejpster', 'therealprof',
},
'edition-guide': {'ehuss', 'Centril', 'steveklabnik'},
'rustc-guide': {'mark-i-m', 'spastorino', 'amanjeev'},
}
REPOS = {
@ -52,6 +59,50 @@ REPOS = {
}
def validate_maintainers(repo, github_token):
'''Ensure all maintainers are assignable on a GitHub repo'''
next_link_re = re.compile(r'<([^>]+)>; rel="next"')
# Load the list of assignable people in the GitHub repo
assignable = []
url = 'https://api.github.com/repos/%s/collaborators?per_page=100' % repo
while url is not None:
response = urllib2.urlopen(urllib2.Request(url, headers={
'Authorization': 'token ' + github_token,
# Properly load nested teams.
'Accept': 'application/vnd.github.hellcat-preview+json',
}))
assignable.extend(user['login'] for user in json.load(response))
# Load the next page if available
url = None
link_header = response.headers.get('Link')
if link_header:
matches = next_link_re.match(link_header)
if matches is not None:
url = matches.group(1)
errors = False
for tool, maintainers in MAINTAINERS.items():
for maintainer in maintainers:
if maintainer not in assignable:
errors = True
print(
"error: %s maintainer @%s is not assignable in the %s repo"
% (tool, maintainer, repo),
)
if errors:
print()
print(" To be assignable, a person needs to be explicitly listed as a")
print(" collaborator in the repository settings. The simple way to")
print(" fix this is to ask someone with 'admin' privileges on the repo")
print(" to add the person or whole team as a collaborator with 'read'")
print(" privileges. Those privileges don't grant any extra permissions")
print(" so it's safe to apply them.")
print()
print("The build will fail due to this.")
exit(1)
def read_current_status(current_commit, path):
'''Reads build status of `current_commit` from content of `history/*.tsv`
'''
@ -73,13 +124,12 @@ def maybe_delink(message):
def issue(
tool,
status,
maintainers,
assignees,
relevant_pr_number,
relevant_pr_user,
pr_reviewer,
):
# Open an issue about the toolstate failure.
assignees = [x.strip() for x in maintainers.split('@') if x != '']
if status == 'test-fail':
status_description = 'has failing tests'
else:
@ -100,7 +150,7 @@ def issue(
REPOS.get(tool), relevant_pr_user, pr_reviewer
)),
'title': '`{}` no longer builds after {}'.format(tool, relevant_pr_number),
'assignees': assignees,
'assignees': list(assignees),
'labels': ['T-compiler', 'I-nominated'],
})
print("Creating issue:\n{}".format(request))
@ -150,18 +200,19 @@ def update_latest(
old = status[os]
new = s.get(tool, old)
status[os] = new
maintainers = ' '.join('@'+name for name in MAINTAINERS[tool])
if new > old: # comparing the strings, but they are ordered appropriately!
# things got fixed or at least the status quo improved
changed = True
message += '🎉 {} on {}: {}{} (cc {}, @rust-lang/infra).\n' \
.format(tool, os, old, new, MAINTAINERS.get(tool))
.format(tool, os, old, new, maintainers)
elif new < old:
# tests or builds are failing and were not failing before
changed = True
title = '💔 {} on {}: {}{}' \
.format(tool, os, old, new)
message += '{} (cc {}, @rust-lang/infra).\n' \
.format(title, MAINTAINERS.get(tool))
.format(title, maintainers)
# Most tools only create issues for build failures.
# Other failures can be spurious.
if new == 'build-fail' or (tool == 'miri' and new == 'test-fail'):
@ -200,6 +251,16 @@ def update_latest(
if __name__ == '__main__':
repo = os.environ.get('TOOLSTATE_VALIDATE_MAINTAINERS_REPO')
if repo:
github_token = os.environ.get('TOOLSTATE_REPO_ACCESS_TOKEN')
if github_token:
validate_maintainers(repo, github_token)
else:
print('skipping toolstate maintainers validation since no GitHub token is present')
# When validating maintainers don't run the full script.
exit(0)
cur_commit = sys.argv[1]
cur_datetime = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
cur_commit_msg = sys.argv[2]