Skip to content

Rollup of 11 pull requests #83283

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 31 commits into from
Closed
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f45fe94
Add license metadata for std dependencies
clehner Feb 20, 2021
2cbea9f
Reuse `std::sys::unsupported::pipe` on `hermit`
CDirkx Feb 24, 2021
8c718bd
Attempt to gather similar stats as rusage on Windows
rylev Mar 4, 2021
0201e2b
Add more windows specific numbers
rylev Mar 5, 2021
a2571cf
Implement String::remove_matches
jcotton42 Mar 5, 2021
302867c
Clean up handling of child process
rylev Mar 11, 2021
5e788f2
Add Linux-specific pidfd process extensions
Aaron1011 Sep 16, 2020
3426bf7
Typo fix
joshtriplett Oct 18, 2020
704d6c5
Add PidFd type and seal traits
voidc Feb 6, 2021
766cc25
Add tracking issue and link to man-page
voidc Mar 10, 2021
d850f6b
Update libc dependency to 0.2.89
voidc Mar 15, 2021
5ac8a31
Fix test header and imports
voidc Mar 16, 2021
a266bd8
Split do_fork into two
voidc Mar 16, 2021
cfb2d72
Make do_fork unsafe
voidc Mar 16, 2021
620ecc0
Move some test-only code to test files
jyn514 Mar 17, 2021
b1de9d4
Fix gitattibutes for old git versions
Mar 16, 2021
cfb4ad4
Remove unwrap_none/expect_none from compiler/.
m-ou-se Mar 4, 2021
390d1ef
Extend `proc_macro_back_compat` lint to `actix-web`
Aaron1011 Mar 16, 2021
99b2054
Fix typo/inaccuracy in the documentation of Iterator::skip_while
steffahn Mar 18, 2021
9dfda62
Clarify docs for Read::read's return value
jix Mar 8, 2021
e1fd230
Rollup merge of #71780 - jcotton42:string_remove_matches, r=joshtriplett
Dylan-DPC Mar 18, 2021
fe230b1
Rollup merge of #81825 - voidc:pidfd, r=joshtriplett
Dylan-DPC Mar 18, 2021
b0ac545
Rollup merge of #82374 - clehner:licenses, r=joshtriplett
Dylan-DPC Mar 18, 2021
4c3abdc
Rollup merge of #82500 - CDirkx:hermit-pipe, r=joshtriplett
Dylan-DPC Mar 18, 2021
6417d4d
Rollup merge of #82754 - rylev:rusage-windows, r=pnkfelix
Dylan-DPC Mar 18, 2021
05984bc
Rollup merge of #82759 - m-ou-se:remove-unwrap-none, r=petrochenkov
Dylan-DPC Mar 18, 2021
0f15079
Rollup merge of #82892 - jix:clarify-read-read, r=joshtriplett
Dylan-DPC Mar 18, 2021
3f4b7ec
Rollup merge of #83179 - Aaron1011:actix-web-lint, r=petrochenkov
Dylan-DPC Mar 18, 2021
8dbc59d
Rollup merge of #83197 - jyn514:cfg-test-dead-code, r=joshtriplett
Dylan-DPC Mar 18, 2021
d12cfc9
Rollup merge of #83208 - jethrogb:jb/gitignore, r=Xanewok
Dylan-DPC Mar 18, 2021
d97769e
Rollup merge of #83270 - steffahn:missing_word_in_skip_while_doc, r=j…
Dylan-DPC Mar 18, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -7,11 +7,11 @@
*.fixed linguist-language=Rust
*.mir linguist-language=Rust
src/etc/installer/gfx/* binary
*.woff binary
*.woff2 binary
src/vendor/** -text
Cargo.lock linguist-generated=false

# Older git versions try to fix line endings on images, this prevents it.
# Older git versions try to fix line endings on images and fonts, this prevents it.
*.png binary
*.ico binary
*.woff binary
*.woff2 binary
4 changes: 2 additions & 2 deletions Cargo.lock
Original file line number Diff line number Diff line change
@@ -1895,9 +1895,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"

[[package]]
name = "libc"
version = "0.2.88"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a"
checksum = "538c092e5586f4cdd7dd8078c4a79220e3e168880218124dcbce860f0ea938c6"
dependencies = [
"rustc-std-workspace-core",
]
16 changes: 0 additions & 16 deletions compiler/rustc_arena/src/lib.rs
Original file line number Diff line number Diff line change
@@ -298,22 +298,6 @@ impl<T> TypedArena<T> {
}
}

/// Clears the arena. Deallocates all but the longest chunk which may be reused.
pub fn clear(&mut self) {
unsafe {
// Clear the last chunk, which is partially filled.
let mut chunks_borrow = self.chunks.borrow_mut();
if let Some(mut last_chunk) = chunks_borrow.last_mut() {
self.clear_last_chunk(&mut last_chunk);
let len = chunks_borrow.len();
// If `T` is ZST, code below has no effect.
for mut chunk in chunks_borrow.drain(..len - 1) {
chunk.destroy(chunk.entries);
}
}
}
}

// Drops the contents of the last chunk. The last chunk is partially empty, unlike all other
// chunks.
fn clear_last_chunk(&self, last_chunk: &mut TypedArenaChunk<T>) {
18 changes: 18 additions & 0 deletions compiler/rustc_arena/src/tests.rs
Original file line number Diff line number Diff line change
@@ -11,6 +11,24 @@ struct Point {
z: i32,
}

impl<T> TypedArena<T> {
/// Clears the arena. Deallocates all but the longest chunk which may be reused.
fn clear(&mut self) {
unsafe {
// Clear the last chunk, which is partially filled.
let mut chunks_borrow = self.chunks.borrow_mut();
if let Some(mut last_chunk) = chunks_borrow.last_mut() {
self.clear_last_chunk(&mut last_chunk);
let len = chunks_borrow.len();
// If `T` is ZST, code below has no effect.
for mut chunk in chunks_borrow.drain(..len - 1) {
chunk.destroy(chunk.entries);
}
}
}
}
}

#[test]
pub fn test_unused() {
let arena: TypedArena<Point> = TypedArena::default();
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(assert_matches)]
#![feature(bool_to_option)]
#![feature(option_expect_none)]
#![feature(box_patterns)]
#![feature(drain_filter)]
#![feature(try_blocks)]
14 changes: 2 additions & 12 deletions compiler/rustc_data_structures/src/tiny_list.rs
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@
mod tests;

#[derive(Clone)]
pub struct TinyList<T: PartialEq> {
pub struct TinyList<T> {
head: Option<Element<T>>,
}

@@ -56,20 +56,10 @@ impl<T: PartialEq> TinyList<T> {
}
false
}

#[inline]
pub fn len(&self) -> usize {
let (mut elem, mut count) = (self.head.as_ref(), 0);
while let Some(ref e) = elem {
count += 1;
elem = e.next.as_deref();
}
count
}
}

#[derive(Clone)]
struct Element<T: PartialEq> {
struct Element<T> {
data: T,
next: Option<Box<Element<T>>>,
}
11 changes: 11 additions & 0 deletions compiler/rustc_data_structures/src/tiny_list/tests.rs
Original file line number Diff line number Diff line change
@@ -3,6 +3,17 @@ use super::*;
extern crate test;
use test::{black_box, Bencher};

impl<T> TinyList<T> {
fn len(&self) -> usize {
let (mut elem, mut count) = (self.head.as_ref(), 0);
while let Some(ref e) = elem {
count += 1;
elem = e.next.as_deref();
}
count
}
}

#[test]
fn test_contains_and_insert() {
fn do_insert(i: u32) -> bool {
10 changes: 2 additions & 8 deletions compiler/rustc_data_structures/src/transitive_relation.rs
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ use std::mem;
mod tests;

#[derive(Clone, Debug)]
pub struct TransitiveRelation<T: Eq + Hash> {
pub struct TransitiveRelation<T> {
// List of elements. This is used to map from a T to a usize.
elements: FxIndexSet<T>,

@@ -49,7 +49,7 @@ struct Edge {
target: Index,
}

impl<T: Clone + Debug + Eq + Hash> TransitiveRelation<T> {
impl<T: Eq + Hash> TransitiveRelation<T> {
pub fn is_empty(&self) -> bool {
self.edges.is_empty()
}
@@ -322,12 +322,6 @@ impl<T: Clone + Debug + Eq + Hash> TransitiveRelation<T> {
.collect()
}

/// A "best" parent in some sense. See `parents` and
/// `postdom_upper_bound` for more details.
pub fn postdom_parent(&self, a: &T) -> Option<&T> {
self.mutual_immediate_postdominator(self.parents(a))
}

fn with_closure<OP, R>(&self, op: OP) -> R
where
OP: FnOnce(&BitMatrix<usize, usize>) -> R,
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
use super::*;

impl<T: Eq + Hash> TransitiveRelation<T> {
/// A "best" parent in some sense. See `parents` and
/// `postdom_upper_bound` for more details.
fn postdom_parent(&self, a: &T) -> Option<&T> {
self.mutual_immediate_postdominator(self.parents(a))
}
}

#[test]
fn test_one_step() {
let mut relation = TransitiveRelation::default();
46 changes: 29 additions & 17 deletions compiler/rustc_expand/src/proc_macro_server.rs
Original file line number Diff line number Diff line change
@@ -53,11 +53,11 @@ impl ToInternal<token::DelimToken> for Delimiter {
}
}

impl FromInternal<(TreeAndSpacing, &'_ ParseSess, &'_ mut Vec<Self>)>
impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_>)>
for TokenTree<Group, Punct, Ident, Literal>
{
fn from_internal(
((tree, spacing), sess, stack): (TreeAndSpacing, &ParseSess, &mut Vec<Self>),
((tree, spacing), stack, rustc): (TreeAndSpacing, &mut Vec<Self>, &mut Rustc<'_>),
) -> Self {
use rustc_ast::token::*;

@@ -146,10 +146,10 @@ impl FromInternal<(TreeAndSpacing, &'_ ParseSess, &'_ mut Vec<Self>)>
SingleQuote => op!('\''),

Ident(name, false) if name == kw::DollarCrate => tt!(Ident::dollar_crate()),
Ident(name, is_raw) => tt!(Ident::new(sess, name, is_raw)),
Ident(name, is_raw) => tt!(Ident::new(rustc.sess, name, is_raw)),
Lifetime(name) => {
let ident = symbol::Ident::new(name, span).without_first_quote();
stack.push(tt!(Ident::new(sess, ident.name, false)));
stack.push(tt!(Ident::new(rustc.sess, ident.name, false)));
tt!(Punct::new('\'', true))
}
Literal(lit) => tt!(Literal { lit }),
@@ -179,15 +179,15 @@ impl FromInternal<(TreeAndSpacing, &'_ ParseSess, &'_ mut Vec<Self>)>
}

Interpolated(nt) => {
if let Some((name, is_raw)) = ident_name_compatibility_hack(&nt, span, sess) {
TokenTree::Ident(Ident::new(sess, name.name, is_raw, name.span))
if let Some((name, is_raw)) = ident_name_compatibility_hack(&nt, span, rustc) {
TokenTree::Ident(Ident::new(rustc.sess, name.name, is_raw, name.span))
} else {
let stream = nt_to_tokenstream(&nt, sess, CanSynthesizeMissingTokens::No);
let stream = nt_to_tokenstream(&nt, rustc.sess, CanSynthesizeMissingTokens::No);
TokenTree::Group(Group {
delimiter: Delimiter::None,
stream,
span: DelimSpan::from_single(span),
flatten: crate::base::pretty_printing_compatibility_hack(&nt, sess),
flatten: crate::base::pretty_printing_compatibility_hack(&nt, rustc.sess),
})
}
}
@@ -449,7 +449,7 @@ impl server::TokenStreamIter for Rustc<'_> {
loop {
let tree = iter.stack.pop().or_else(|| {
let next = iter.cursor.next_with_spacing()?;
Some(TokenTree::from_internal((next, self.sess, &mut iter.stack)))
Some(TokenTree::from_internal((next, &mut iter.stack, self)))
})?;
// A hack used to pass AST fragments to attribute and derive macros
// as a single nonterminal token instead of a token stream.
@@ -719,11 +719,11 @@ impl server::Span for Rustc<'_> {
fn ident_name_compatibility_hack(
nt: &Nonterminal,
orig_span: Span,
sess: &ParseSess,
rustc: &mut Rustc<'_>,
) -> Option<(rustc_span::symbol::Ident, bool)> {
if let NtIdent(ident, is_raw) = nt {
if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind {
let source_map = sess.source_map();
let source_map = rustc.sess.source_map();
let filename = source_map.span_to_filename(orig_span);
if let FileName::Real(RealFileName::Named(path)) = filename {
let matches_prefix = |prefix, filename| {
@@ -745,7 +745,7 @@ fn ident_name_compatibility_hack(
let snippet = source_map.span_to_snippet(orig_span);
if snippet.as_deref() == Ok("$name") {
if time_macros_impl {
sess.buffer_lint_with_diagnostic(
rustc.sess.buffer_lint_with_diagnostic(
&PROC_MACRO_BACK_COMPAT,
orig_span,
ast::CRATE_NODE_ID,
@@ -759,13 +759,25 @@ fn ident_name_compatibility_hack(
}
}

if macro_name == sym::tuple_from_req
&& (matches_prefix("actix-web", "extract.rs")
|| matches_prefix("actori-web", "extract.rs"))
{
if macro_name == sym::tuple_from_req && matches_prefix("actix-web", "extract.rs") {
let snippet = source_map.span_to_snippet(orig_span);
if snippet.as_deref() == Ok("$T") {
return Some((*ident, *is_raw));
if let FileName::Real(RealFileName::Named(macro_path)) =
source_map.span_to_filename(rustc.def_site)
{
if macro_path.to_string_lossy().contains("pin-project-internal-0.") {
rustc.sess.buffer_lint_with_diagnostic(
&PROC_MACRO_BACK_COMPAT,
orig_span,
ast::CRATE_NODE_ID,
"using an old version of `actix-web`",
BuiltinLintDiagnostics::ProcMacroBackCompat(
"the version of `actix-web` you are using might stop compiling in future versions of Rust; \
please update to the latest version of the `actix-web` crate to avoid breakage".to_string())
);
return Some((*ident, *is_raw));
}
}
}
}
}
6 changes: 5 additions & 1 deletion compiler/rustc_middle/src/ich/impls_syntax.rs
Original file line number Diff line number Diff line change
@@ -45,7 +45,11 @@ impl<'ctx> rustc_ast::HashStableContext for StableHashingContext<'ctx> {
item.hash_stable(self, hasher);
style.hash_stable(self, hasher);
span.hash_stable(self, hasher);
tokens.as_ref().expect_none("Tokens should have been removed during lowering!");
assert_matches!(
tokens.as_ref(),
None,
"Tokens should have been removed during lowering!"
);
} else {
unreachable!();
}
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/lib.rs
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(array_windows)]
#![feature(assert_matches)]
#![feature(assoc_char_funcs)]
#![feature(backtrace)]
#![feature(bool_to_option)]
@@ -38,7 +39,6 @@
#![feature(extern_types)]
#![feature(nll)]
#![feature(once_cell)]
#![feature(option_expect_none)]
#![feature(or_patterns)]
#![feature(min_specialization)]
#![feature(trusted_len)]
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/mir/interpret/allocation.rs
Original file line number Diff line number Diff line change
@@ -339,7 +339,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
for dest in bytes {
*dest = src.next().expect("iterator was shorter than it said it would be");
}
src.next().expect_none("iterator was longer than it said it would be");
assert_matches!(src.next(), None, "iterator was longer than it said it would be");
Ok(())
}

14 changes: 11 additions & 3 deletions compiler/rustc_mir/src/interpret/memory.rs
Original file line number Diff line number Diff line change
@@ -854,7 +854,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
Some(ptr) => ptr,
None => {
// zero-sized access
src.next().expect_none("iterator said it was empty but returned an element");
assert_matches!(
src.next(),
None,
"iterator said it was empty but returned an element"
);
return Ok(());
}
};
@@ -880,7 +884,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
Some(ptr) => ptr,
None => {
// zero-sized access
src.next().expect_none("iterator said it was empty but returned an element");
assert_matches!(
src.next(),
None,
"iterator said it was empty but returned an element"
);
return Ok(());
}
};
@@ -894,7 +902,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
let offset_ptr = ptr.offset(Size::from_bytes(idx) * 2, &tcx)?; // `Size` multiplication
allocation.write_scalar(&tcx, offset_ptr, val.into(), Size::from_bytes(2))?;
}
src.next().expect_none("iterator was longer than it said it would be");
assert_matches!(src.next(), None, "iterator was longer than it said it would be");
Ok(())
}

3 changes: 2 additions & 1 deletion compiler/rustc_mir/src/lib.rs
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ Rust MIR: a lowered representation of Rust.
#![feature(nll)]
#![feature(in_band_lifetimes)]
#![feature(array_windows)]
#![feature(assert_matches)]
#![feature(bindings_after_at)]
#![feature(bool_to_option)]
#![feature(box_patterns)]
@@ -18,13 +19,13 @@ Rust MIR: a lowered representation of Rust.
#![feature(exact_size_is_empty)]
#![feature(exhaustive_patterns)]
#![feature(never_type)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
#![feature(trusted_len)]
#![feature(try_blocks)]
#![feature(associated_type_defaults)]
#![feature(stmt_expr_attributes)]
#![feature(trait_alias)]
#![feature(option_expect_none)]
#![feature(option_get_or_insert_default)]
#![feature(or_patterns)]
#![feature(once_cell)]
12 changes: 5 additions & 7 deletions compiler/rustc_mir/src/transform/coverage/debug.rs
Original file line number Diff line number Diff line change
@@ -285,10 +285,8 @@ impl DebugCounters {
),
};
counters
.insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
.expect_none(
"attempt to add the same counter_kind to DebugCounters more than once",
);
.try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
.expect("attempt to add the same counter_kind to DebugCounters more than once");
}
}

@@ -479,9 +477,9 @@ impl GraphvizData {
counter_kind: &CoverageKind,
) {
if let Some(edge_to_counter) = self.some_edge_to_counter.as_mut() {
edge_to_counter.insert((from_bcb, to_bb), counter_kind.clone()).expect_none(
"invalid attempt to insert more than one edge counter for the same edge",
);
edge_to_counter
.try_insert((from_bcb, to_bb), counter_kind.clone())
.expect("invalid attempt to insert more than one edge counter for the same edge");
}
}

2 changes: 1 addition & 1 deletion compiler/rustc_mir/src/transform/deduplicate_blocks.rs
Original file line number Diff line number Diff line change
@@ -86,7 +86,7 @@ fn find_duplicates<'a, 'tcx>(body: &'a Body<'tcx>) -> FxHashMap<BasicBlock, Basi
// The basic block was already in the hashmap, which means we have a duplicate
let value = *occupied.get();
debug!("Inserting {:?} -> {:?}", bb, value);
duplicates.insert(bb, value).expect_none("key was already inserted");
duplicates.try_insert(bb, value).expect("key was already inserted");
}
Entry::Vacant(vacant) => {
vacant.insert(bb);
14 changes: 9 additions & 5 deletions compiler/rustc_span/src/hygiene.rs
Original file line number Diff line number Diff line change
@@ -118,7 +118,8 @@ impl ExpnId {
HygieneData::with(|data| {
let old_expn_data = &mut data.expn_data[self.0 as usize];
assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
expn_data.orig_id.replace(self.as_u32()).expect_none("orig_id should be None");
assert_eq!(expn_data.orig_id, None);
expn_data.orig_id = Some(self.as_u32());
*old_expn_data = Some(expn_data);
});
update_disambiguator(self)
@@ -202,7 +203,8 @@ impl HygieneData {
fn fresh_expn(&mut self, mut expn_data: Option<ExpnData>) -> ExpnId {
let raw_id = self.expn_data.len() as u32;
if let Some(data) = expn_data.as_mut() {
data.orig_id.replace(raw_id).expect_none("orig_id should be None");
assert_eq!(data.orig_id, None);
data.orig_id = Some(raw_id);
}
self.expn_data.push(expn_data);
ExpnId(raw_id)
@@ -1410,9 +1412,11 @@ fn update_disambiguator(expn_id: ExpnId) {
let new_hash: Fingerprint = hasher.finish();

HygieneData::with(|data| {
data.expn_data_disambiguators
.get(&new_hash)
.expect_none("Hash collision after disambiguator update!");
assert_eq!(
data.expn_data_disambiguators.get(&new_hash),
None,
"Hash collision after disambiguator update!",
);
});
};
}
4 changes: 2 additions & 2 deletions compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
@@ -21,7 +21,6 @@
#![feature(negative_impls)]
#![feature(nll)]
#![feature(min_specialization)]
#![feature(option_expect_none)]

#[macro_use]
extern crate rustc_macros;
@@ -1996,7 +1995,8 @@ impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
if cache.len() < new_len {
cache.resize(new_len, None);
}
cache[index].replace(sub_hash).expect_none("Cache slot was filled");
let prev = cache[index].replace(sub_hash);
assert_eq!(prev, None, "Cache slot was filled");
});
sub_hash.hash_stable(ctx, hasher);
}
42 changes: 0 additions & 42 deletions compiler/rustc_span/src/source_map.rs
Original file line number Diff line number Diff line change
@@ -453,41 +453,6 @@ impl SourceMap {
}
}

/// Returns `Some(span)`, a union of the LHS and RHS span. The LHS must precede the RHS. If
/// there are gaps between LHS and RHS, the resulting union will cross these gaps.
/// For this to work,
///
/// * the syntax contexts of both spans much match,
/// * the LHS span needs to end on the same line the RHS span begins,
/// * the LHS span must start at or before the RHS span.
pub fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
// Ensure we're at the same expansion ID.
if sp_lhs.ctxt() != sp_rhs.ctxt() {
return None;
}

let lhs_end = match self.lookup_line(sp_lhs.hi()) {
Ok(x) => x,
Err(_) => return None,
};
let rhs_begin = match self.lookup_line(sp_rhs.lo()) {
Ok(x) => x,
Err(_) => return None,
};

// If we must cross lines to merge, don't merge.
if lhs_end.line != rhs_begin.line {
return None;
}

// Ensure these follow the expected order and that we don't overlap.
if (sp_lhs.lo() <= sp_rhs.lo()) && (sp_lhs.hi() <= sp_rhs.lo()) {
Some(sp_lhs.to(sp_rhs))
} else {
None
}
}

pub fn span_to_string(&self, sp: Span) -> String {
if self.files.borrow().source_files.is_empty() && sp.is_dummy() {
return "no-location".to_string();
@@ -931,13 +896,6 @@ impl SourceMap {
SourceFileAndBytePos { sf, pos: offset }
}

/// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
let idx = self.lookup_source_file_idx(bpos);
let sf = &(*self.files.borrow().source_files)[idx];
sf.bytepos_to_file_charpos(bpos)
}

// Returns the index of the `SourceFile` (in `self.files`) that contains `pos`.
// This index is guaranteed to be valid for the lifetime of this `SourceMap`,
// since `source_files` is a `MonotonicVec`
44 changes: 44 additions & 0 deletions compiler/rustc_span/src/source_map/tests.rs
Original file line number Diff line number Diff line change
@@ -10,6 +10,50 @@ fn init_source_map() -> SourceMap {
sm
}

impl SourceMap {
/// Returns `Some(span)`, a union of the LHS and RHS span. The LHS must precede the RHS. If
/// there are gaps between LHS and RHS, the resulting union will cross these gaps.
/// For this to work,
///
/// * the syntax contexts of both spans much match,
/// * the LHS span needs to end on the same line the RHS span begins,
/// * the LHS span must start at or before the RHS span.
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
// Ensure we're at the same expansion ID.
if sp_lhs.ctxt() != sp_rhs.ctxt() {
return None;
}

let lhs_end = match self.lookup_line(sp_lhs.hi()) {
Ok(x) => x,
Err(_) => return None,
};
let rhs_begin = match self.lookup_line(sp_rhs.lo()) {
Ok(x) => x,
Err(_) => return None,
};

// If we must cross lines to merge, don't merge.
if lhs_end.line != rhs_begin.line {
return None;
}

// Ensure these follow the expected order and that we don't overlap.
if (sp_lhs.lo() <= sp_rhs.lo()) && (sp_lhs.hi() <= sp_rhs.lo()) {
Some(sp_lhs.to(sp_rhs))
} else {
None
}
}

/// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
let idx = self.lookup_source_file_idx(bpos);
let sf = &(*self.files.borrow().source_files)[idx];
sf.bytepos_to_file_charpos(bpos)
}
}

/// Tests `lookup_byte_offset`.
#[test]
fn t3() {
3 changes: 3 additions & 0 deletions library/alloc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -2,6 +2,9 @@
authors = ["The Rust Project Developers"]
name = "alloc"
version = "0.0.0"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
description = "The Rust core allocation and collections library"
autotests = false
autobenches = false
edition = "2018"
56 changes: 56 additions & 0 deletions library/alloc/src/string.rs
Original file line number Diff line number Diff line change
@@ -1202,6 +1202,62 @@ impl String {
ch
}

/// Remove all matches of pattern `pat` in the `String`.
///
/// # Examples
///
/// ```
/// #![feature(string_remove_matches)]
/// let mut s = String::from("Trees are not green, the sky is not blue.");
/// s.remove_matches("not ");
/// assert_eq!("Trees are green, the sky is blue.", s);
/// ```
///
/// Matches will be detected and removed iteratively, so in cases where
/// patterns overlap, only the first pattern will be removed:
///
/// ```
/// #![feature(string_remove_matches)]
/// let mut s = String::from("banana");
/// s.remove_matches("ana");
/// assert_eq!("bna", s);
/// ```
#[unstable(feature = "string_remove_matches", reason = "new API", issue = "72826")]
pub fn remove_matches<'a, P>(&'a mut self, pat: P)
where
P: for<'x> Pattern<'x>,
{
use core::str::pattern::Searcher;

let matches = {
let mut searcher = pat.into_searcher(self);
let mut matches = Vec::new();

while let Some(m) = searcher.next_match() {
matches.push(m);
}

matches
};

let len = self.len();
let mut shrunk_by = 0;

// SAFETY: start and end will be on utf8 byte boundaries per
// the Searcher docs
unsafe {
for (start, end) in matches {
ptr::copy(
self.vec.as_mut_ptr().add(end - shrunk_by),
self.vec.as_mut_ptr().add(start - shrunk_by),
len - end,
);
shrunk_by += end - start;
}
self.vec.set_len(len - shrunk_by);
}
}

/// Retains only the characters specified by the predicate.
///
/// In other words, remove all characters `c` such that `f(c)` returns `false`.
1 change: 1 addition & 0 deletions library/alloc/tests/lib.rs
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
#![feature(slice_partition_dedup)]
#![feature(vec_extend_from_within)]
#![feature(vec_spare_capacity)]
#![feature(string_remove_matches)]

use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
27 changes: 27 additions & 0 deletions library/alloc/tests/string.rs
Original file line number Diff line number Diff line change
@@ -365,6 +365,33 @@ fn remove_bad() {
"ศ".to_string().remove(1);
}

#[test]
fn test_remove_matches() {
let mut s = "abc".to_string();

s.remove_matches('b');
assert_eq!(s, "ac");
s.remove_matches('b');
assert_eq!(s, "ac");

let mut s = "abcb".to_string();

s.remove_matches('b');
assert_eq!(s, "ac");

let mut s = "ศไทย中华Việt Nam; foobarศ".to_string();
s.remove_matches('ศ');
assert_eq!(s, "ไทย中华Việt Nam; foobar");

let mut s = "".to_string();
s.remove_matches("");
assert_eq!(s, "");

let mut s = "aaaaa".to_string();
s.remove_matches('a');
assert_eq!(s, "");
}

#[test]
fn test_retain() {
let mut s = String::from("α_β_γ");
3 changes: 3 additions & 0 deletions library/core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -2,6 +2,9 @@
authors = ["The Rust Project Developers"]
name = "core"
version = "0.0.0"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
description = "The Rust Core Library"
autotests = false
autobenches = false
edition = "2018"
2 changes: 1 addition & 1 deletion library/core/src/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
@@ -1012,7 +1012,7 @@ pub trait Iterator {
///
/// Because the closure passed to `skip_while()` takes a reference, and many
/// iterators iterate over references, this leads to a possibly confusing
/// situation, where the type of the closure is a double reference:
/// situation, where the type of the closure argument is a double reference:
///
/// ```
/// let a = [-1, 0, 1];
3 changes: 3 additions & 0 deletions library/panic_abort/Cargo.toml
Original file line number Diff line number Diff line change
@@ -2,6 +2,9 @@
authors = ["The Rust Project Developers"]
name = "panic_abort"
version = "0.0.0"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
description = "Implementation of Rust panics via process aborts"
edition = "2018"

[lib]
3 changes: 3 additions & 0 deletions library/panic_unwind/Cargo.toml
Original file line number Diff line number Diff line change
@@ -2,6 +2,9 @@
authors = ["The Rust Project Developers"]
name = "panic_unwind"
version = "0.0.0"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
description = "Implementation of Rust panics via stack unwinding"
edition = "2018"

[lib]
2 changes: 1 addition & 1 deletion library/std/Cargo.toml
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] }
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
libc = { version = "0.2.88", default-features = false, features = ['rustc-dep-of-std'] }
libc = { version = "0.2.89", default-features = false, features = ['rustc-dep-of-std'] }
compiler_builtins = { version = "0.1.39" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
9 changes: 7 additions & 2 deletions library/std/src/io/mod.rs
Original file line number Diff line number Diff line change
@@ -514,8 +514,8 @@ pub trait Read {
/// waiting for data, but if an object needs to block for a read and cannot,
/// it will typically signal this via an [`Err`] return value.
///
/// If the return value of this method is [`Ok(n)`], then it must be
/// guaranteed that `0 <= n <= buf.len()`. A nonzero `n` value indicates
/// If the return value of this method is [`Ok(n)`], then implementations must
/// guarantee that `0 <= n <= buf.len()`. A nonzero `n` value indicates
/// that the buffer `buf` has been filled in with `n` bytes of data from this
/// source. If `n` is `0`, then it can indicate one of two scenarios:
///
@@ -529,6 +529,11 @@ pub trait Read {
/// This may happen for example because fewer bytes are actually available right now
/// (e. g. being close to end-of-file) or because read() was interrupted by a signal.
///
/// As this trait is safe to implement, callers cannot rely on `n <= buf.len()` for safety.
/// Extra care needs to be taken when `unsafe` functions are used to access the read bytes.
/// Callers have to ensure that no unchecked out-of-bounds accesses are possible even if
/// `n > buf.len()`.
///
/// No guarantees are provided about the contents of `buf` when this
/// function is called, implementations cannot rely on any property of the
/// contents of `buf` being true. It is recommended that *implementations*
1 change: 1 addition & 0 deletions library/std/src/os/linux/mod.rs
Original file line number Diff line number Diff line change
@@ -3,4 +3,5 @@
#![stable(feature = "raw_ext", since = "1.1.0")]

pub mod fs;
pub mod process;
pub mod raw;
150 changes: 150 additions & 0 deletions library/std/src/os/linux/process.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
//! Linux-specific extensions to primitives in the `std::process` module.
#![unstable(feature = "linux_pidfd", issue = "82971")]

use crate::io::Result;
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::process;
use crate::sys::fd::FileDesc;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};

/// This type represents a file descriptor that refers to a process.
///
/// A `PidFd` can be obtained by setting the corresponding option on [`Command`]
/// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved
/// from the [`Child`] by calling [`pidfd`] or [`take_pidfd`].
///
/// Example:
/// ```no_run
/// #![feature(linux_pidfd)]
/// use std::os::linux::process::{CommandExt, ChildExt};
/// use std::process::Command;
///
/// let mut child = Command::new("echo")
/// .create_pidfd(true)
/// .spawn()
/// .expect("Failed to spawn child");
///
/// let pidfd = child
/// .take_pidfd()
/// .expect("Failed to retrieve pidfd");
///
/// // The file descriptor will be closed when `pidfd` is dropped.
/// ```
/// Refer to the man page of [`pidfd_open(2)`] for further details.
///
/// [`Command`]: process::Command
/// [`create_pidfd`]: CommandExt::create_pidfd
/// [`Child`]: process::Child
/// [`pidfd`]: fn@ChildExt::pidfd
/// [`take_pidfd`]: ChildExt::take_pidfd
/// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
#[derive(Debug)]
pub struct PidFd {
inner: FileDesc,
}

impl AsInner<FileDesc> for PidFd {
fn as_inner(&self) -> &FileDesc {
&self.inner
}
}

impl FromInner<FileDesc> for PidFd {
fn from_inner(inner: FileDesc) -> PidFd {
PidFd { inner }
}
}

impl IntoInner<FileDesc> for PidFd {
fn into_inner(self) -> FileDesc {
self.inner
}
}

impl AsRawFd for PidFd {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().raw()
}
}

impl FromRawFd for PidFd {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self::from_inner(FileDesc::new(fd))
}
}

impl IntoRawFd for PidFd {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_raw()
}
}

mod private_child_ext {
pub trait Sealed {}
impl Sealed for crate::process::Child {}
}

/// Os-specific extensions for [`Child`]
///
/// [`Child`]: process::Child
pub trait ChildExt: private_child_ext::Sealed {
/// Obtains a reference to the [`PidFd`] created for this [`Child`], if available.
///
/// A pidfd will only be available if its creation was requested with
/// [`create_pidfd`] when the corresponding [`Command`] was created.
///
/// Even if requested, a pidfd may not be available due to an older
/// version of Linux being in use, or if some other error occurred.
///
/// [`Command`]: process::Command
/// [`create_pidfd`]: CommandExt::create_pidfd
/// [`Child`]: process::Child
fn pidfd(&self) -> Result<&PidFd>;

/// Takes ownership of the [`PidFd`] created for this [`Child`], if available.
///
/// A pidfd will only be available if its creation was requested with
/// [`create_pidfd`] when the corresponding [`Command`] was created.
///
/// Even if requested, a pidfd may not be available due to an older
/// version of Linux being in use, or if some other error occurred.
///
/// [`Command`]: process::Command
/// [`create_pidfd`]: CommandExt::create_pidfd
/// [`Child`]: process::Child
fn take_pidfd(&mut self) -> Result<PidFd>;
}

mod private_command_ext {
pub trait Sealed {}
impl Sealed for crate::process::Command {}
}

/// Os-specific extensions for [`Command`]
///
/// [`Command`]: process::Command
pub trait CommandExt: private_command_ext::Sealed {
/// Sets whether a [`PidFd`](struct@PidFd) should be created for the [`Child`]
/// spawned by this [`Command`].
/// By default, no pidfd will be created.
///
/// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`].
///
/// A pidfd will only be created if it is possible to do so
/// in a guaranteed race-free manner (e.g. if the `clone3` system call
/// is supported). Otherwise, [`pidfd`] will return an error.
///
/// [`Command`]: process::Command
/// [`Child`]: process::Child
/// [`pidfd`]: fn@ChildExt::pidfd
/// [`take_pidfd`]: ChildExt::take_pidfd
fn create_pidfd(&mut self, val: bool) -> &mut process::Command;
}

impl CommandExt for process::Command {
fn create_pidfd(&mut self, val: bool) -> &mut process::Command {
self.as_inner_mut().create_pidfd(val);
self
}
}
2 changes: 1 addition & 1 deletion library/std/src/process.rs
Original file line number Diff line number Diff line change
@@ -165,7 +165,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
/// [`wait`]: Child::wait
#[stable(feature = "process", since = "1.0.0")]
pub struct Child {
handle: imp::Process,
pub(crate) handle: imp::Process,

/// The handle for writing to the child's standard input (stdin), if it has
/// been captured. To avoid partially moving
1 change: 1 addition & 0 deletions library/std/src/sys/hermit/mod.rs
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@ pub mod mutex;
pub mod net;
pub mod os;
pub mod path;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;
#[path = "../unsupported/process.rs"]
pub mod process;
38 changes: 0 additions & 38 deletions library/std/src/sys/hermit/pipe.rs

This file was deleted.

6 changes: 6 additions & 0 deletions library/std/src/sys/unix/process/process_common.rs
Original file line number Diff line number Diff line change
@@ -79,6 +79,7 @@ pub struct Command {
stdin: Option<Stdio>,
stdout: Option<Stdio>,
stderr: Option<Stdio>,
pub(crate) create_pidfd: bool,
}

// Create a new type for argv, so that we can make it `Send` and `Sync`
@@ -141,6 +142,7 @@ impl Command {
stdin: None,
stdout: None,
stderr: None,
create_pidfd: false,
}
}

@@ -177,6 +179,10 @@ impl Command {
self.groups = Some(Box::from(groups));
}

pub fn create_pidfd(&mut self, val: bool) {
self.create_pidfd = val;
}

pub fn saw_nul(&self) -> bool {
self.saw_nul
}
133 changes: 130 additions & 3 deletions library/std/src/sys/unix/process/process_unix.rs
Original file line number Diff line number Diff line change
@@ -7,6 +7,9 @@ use crate::sys;
use crate::sys::cvt;
use crate::sys::process::process_common::*;

#[cfg(target_os = "linux")]
use crate::os::linux::process::PidFd;

#[cfg(target_os = "vxworks")]
use libc::RTP_ID as pid_t;

@@ -48,7 +51,8 @@ impl Command {
// a lock any more because the parent won't do anything and the child is
// in its own process. Thus the parent drops the lock guard while the child
// forgets it to avoid unlocking it on a new thread, which would be invalid.
let (env_lock, result) = unsafe { (sys::os::env_read_lock(), cvt(libc::fork())?) };
let env_lock = sys::os::env_read_lock();
let (result, pidfd) = unsafe { self.do_fork()? };

let pid = unsafe {
match result {
@@ -81,7 +85,7 @@ impl Command {
}
};

let mut p = Process { pid, status: None };
let mut p = Process::new(pid, pidfd);
drop(output);
let mut bytes = [0; 8];

@@ -114,6 +118,92 @@ impl Command {
}
}

// Attempts to fork the process. If successful, returns Ok((0, -1))
// in the child, and Ok((child_pid, -1)) in the parent.
#[cfg(not(target_os = "linux"))]
unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
cvt(libc::fork()).map(|res| (res, -1))
}

// Attempts to fork the process. If successful, returns Ok((0, -1))
// in the child, and Ok((child_pid, child_pidfd)) in the parent.
#[cfg(target_os = "linux")]
unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
use crate::sync::atomic::{AtomicBool, Ordering};

static HAS_CLONE3: AtomicBool = AtomicBool::new(true);
const CLONE_PIDFD: u64 = 0x00001000;

#[repr(C)]
struct clone_args {
flags: u64,
pidfd: u64,
child_tid: u64,
parent_tid: u64,
exit_signal: u64,
stack: u64,
stack_size: u64,
tls: u64,
set_tid: u64,
set_tid_size: u64,
cgroup: u64,
}

syscall! {
fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long
}

// If we fail to create a pidfd for any reason, this will
// stay as -1, which indicates an error.
let mut pidfd: pid_t = -1;

// Attempt to use the `clone3` syscall, which supports more arguments
// (in particular, the ability to create a pidfd). If this fails,
// we will fall through this block to a call to `fork()`
if HAS_CLONE3.load(Ordering::Relaxed) {
let mut flags = 0;
if self.create_pidfd {
flags |= CLONE_PIDFD;
}

let mut args = clone_args {
flags,
pidfd: &mut pidfd as *mut pid_t as u64,
child_tid: 0,
parent_tid: 0,
exit_signal: libc::SIGCHLD as u64,
stack: 0,
stack_size: 0,
tls: 0,
set_tid: 0,
set_tid_size: 0,
cgroup: 0,
};

let args_ptr = &mut args as *mut clone_args;
let args_size = crate::mem::size_of::<clone_args>();

let res = cvt(clone3(args_ptr, args_size));
match res {
Ok(n) => return Ok((n as pid_t, pidfd)),
Err(e) => match e.raw_os_error() {
// Multiple threads can race to execute this store,
// but that's fine - that just means that multiple threads
// will have tried and failed to execute the same syscall,
// with no other side effects.
Some(libc::ENOSYS) => HAS_CLONE3.store(false, Ordering::Relaxed),
// Fallback to fork if `EPERM` is returned. (e.g. blocked by seccomp)
Some(libc::EPERM) => {}
_ => return Err(e),
},
}
}

// If we get here, the 'clone3' syscall does not exist
// or we do not have permission to call it
cvt(libc::fork()).map(|res| (res, pidfd))
}

pub fn exec(&mut self, default: Stdio) -> io::Error {
let envp = self.capture_env();

@@ -297,6 +387,7 @@ impl Command {
|| (self.env_saw_path() && !self.program_is_path())
|| !self.get_closures().is_empty()
|| self.get_groups().is_some()
|| self.create_pidfd
{
return Ok(None);
}
@@ -341,7 +432,7 @@ impl Command {
None => None,
};

let mut p = Process { pid: 0, status: None };
let mut p = Process::new(0, -1);

struct PosixSpawnFileActions<'a>(&'a mut MaybeUninit<libc::posix_spawn_file_actions_t>);

@@ -430,9 +521,27 @@ impl Command {
pub struct Process {
pid: pid_t,
status: Option<ExitStatus>,
// On Linux, stores the pidfd created for this child.
// This is None if the user did not request pidfd creation,
// or if the pidfd could not be created for some reason
// (e.g. the `clone3` syscall was not available).
#[cfg(target_os = "linux")]
pidfd: Option<PidFd>,
}

impl Process {
#[cfg(target_os = "linux")]
fn new(pid: pid_t, pidfd: pid_t) -> Self {
use crate::sys_common::FromInner;
let pidfd = (pidfd >= 0).then(|| PidFd::from_inner(sys::fd::FileDesc::new(pidfd)));
Process { pid, status: None, pidfd }
}

#[cfg(not(target_os = "linux"))]
fn new(pid: pid_t, _pidfd: pid_t) -> Self {
Process { pid, status: None }
}

pub fn id(&self) -> u32 {
self.pid as u32
}
@@ -546,6 +655,24 @@ impl fmt::Display for ExitStatus {
}
}

#[cfg(target_os = "linux")]
#[unstable(feature = "linux_pidfd", issue = "82971")]
impl crate::os::linux::process::ChildExt for crate::process::Child {
fn pidfd(&self) -> io::Result<&PidFd> {
self.handle
.pidfd
.as_ref()
.ok_or_else(|| Error::new(ErrorKind::Other, "No pidfd was created."))
}

fn take_pidfd(&mut self) -> io::Result<PidFd> {
self.handle
.pidfd
.take()
.ok_or_else(|| Error::new(ErrorKind::Other, "No pidfd was created."))
}
}

#[cfg(test)]
#[path = "process_unix/tests.rs"]
mod tests;
2 changes: 2 additions & 0 deletions library/unwind/Cargo.toml
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@
authors = ["The Rust Project Developers"]
name = "unwind"
version = "0.0.0"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
edition = "2018"
include = [
'/libunwind/*',
2 changes: 1 addition & 1 deletion src/bootstrap/Cargo.toml
Original file line number Diff line number Diff line change
@@ -53,7 +53,7 @@ merge = "0.1.0"

[target.'cfg(windows)'.dependencies.winapi]
version = "0.3"
features = ["fileapi", "ioapiset", "jobapi2", "handleapi", "winioctl"]
features = ["fileapi", "ioapiset", "jobapi2", "handleapi", "winioctl", "psapi", "impl-default"]

[dev-dependencies]
pretty_assertions = "0.6"
84 changes: 75 additions & 9 deletions src/bootstrap/bin/rustc.rs
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@
use std::env;
use std::path::PathBuf;
use std::process::Command;
use std::process::{Child, Command};
use std::str::FromStr;
use std::time::Instant;

@@ -163,9 +163,11 @@ fn main() {
}

let start = Instant::now();
let status = {
let (child, status) = {
let errmsg = format!("\nFailed to run:\n{:?}\n-------------", cmd);
cmd.status().expect(&errmsg)
let mut child = cmd.spawn().expect(&errmsg);
let status = child.wait().expect(&errmsg);
(child, status)
};

if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some()
@@ -176,7 +178,7 @@ fn main() {
// If the user requested resource usage data, then
// include that in addition to the timing output.
let rusage_data =
env::var_os("RUSTC_PRINT_STEP_RUSAGE").and_then(|_| format_rusage_data());
env::var_os("RUSTC_PRINT_STEP_RUSAGE").and_then(|_| format_rusage_data(child));
eprintln!(
"[RUSTC-TIMING] {} test:{} {}.{:03}{}{}",
crate_name,
@@ -213,19 +215,83 @@ fn main() {
}
}

#[cfg(not(unix))]
/// getrusage is not available on non-unix platforms. So for now, we do not
/// bother trying to make a shim for it.
fn format_rusage_data() -> Option<String> {
#[cfg(all(not(unix), not(windows)))]
// In the future we can add this for more platforms
fn format_rusage_data(_child: Child) -> Option<String> {
None
}

#[cfg(windows)]
fn format_rusage_data(child: Child) -> Option<String> {
use std::os::windows::io::AsRawHandle;
use winapi::um::{processthreadsapi, psapi, timezoneapi};
let handle = child.as_raw_handle();
macro_rules! try_bool {
($e:expr) => {
if $e != 1 {
return None;
}
};
}

let mut user_filetime = Default::default();
let mut user_time = Default::default();
let mut kernel_filetime = Default::default();
let mut kernel_time = Default::default();
let mut memory_counters = psapi::PROCESS_MEMORY_COUNTERS::default();

unsafe {
try_bool!(processthreadsapi::GetProcessTimes(
handle,
&mut Default::default(),
&mut Default::default(),
&mut kernel_filetime,
&mut user_filetime,
));
try_bool!(timezoneapi::FileTimeToSystemTime(&user_filetime, &mut user_time));
try_bool!(timezoneapi::FileTimeToSystemTime(&kernel_filetime, &mut kernel_time));

// Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process
// with the given handle and none of that process's children.
try_bool!(psapi::GetProcessMemoryInfo(
handle as _,
&mut memory_counters as *mut _ as _,
std::mem::size_of::<psapi::PROCESS_MEMORY_COUNTERS_EX>() as u32,
));
}

// Guide on interpreting these numbers:
// https://docs.microsoft.com/en-us/windows/win32/psapi/process-memory-usage-information
let peak_working_set = memory_counters.PeakWorkingSetSize / 1024;
let peak_page_file = memory_counters.PeakPagefileUsage / 1024;
let peak_paged_pool = memory_counters.QuotaPeakPagedPoolUsage / 1024;
let peak_nonpaged_pool = memory_counters.QuotaPeakNonPagedPoolUsage / 1024;
Some(format!(
"user: {USER_SEC}.{USER_USEC:03} \
sys: {SYS_SEC}.{SYS_USEC:03} \
peak working set (kb): {PEAK_WORKING_SET} \
peak page file usage (kb): {PEAK_PAGE_FILE} \
peak paged pool usage (kb): {PEAK_PAGED_POOL} \
peak non-paged pool usage (kb): {PEAK_NONPAGED_POOL} \
page faults: {PAGE_FAULTS}",
USER_SEC = user_time.wSecond + (user_time.wMinute * 60),
USER_USEC = user_time.wMilliseconds,
SYS_SEC = kernel_time.wSecond + (kernel_time.wMinute * 60),
SYS_USEC = kernel_time.wMilliseconds,
PEAK_WORKING_SET = peak_working_set,
PEAK_PAGE_FILE = peak_page_file,
PEAK_PAGED_POOL = peak_paged_pool,
PEAK_NONPAGED_POOL = peak_nonpaged_pool,
PAGE_FAULTS = memory_counters.PageFaultCount,
))
}

#[cfg(unix)]
/// Tries to build a string with human readable data for several of the rusage
/// fields. Note that we are focusing mainly on data that we believe to be
/// supplied on Linux (the `rusage` struct has other fields in it but they are
/// currently unsupported by Linux).
fn format_rusage_data() -> Option<String> {
fn format_rusage_data(_child: Child) -> Option<String> {
let rusage: libc::rusage = unsafe {
let mut recv = std::mem::zeroed();
// -1 is RUSAGE_CHILDREN, which means to get the rusage for all children
27 changes: 27 additions & 0 deletions src/test/ui/command/command-create-pidfd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// run-pass
// only-linux - pidfds are a linux-specific concept

#![feature(linux_pidfd)]
use std::os::linux::process::{CommandExt, ChildExt};
use std::process::Command;

fn main() {
// We don't assert the precise value, since the standard library
// might have opened other file descriptors before our code runs.
let _ = Command::new("echo")
.create_pidfd(true)
.spawn()
.unwrap()
.pidfd().expect("failed to obtain pidfd");

let _ = Command::new("echo")
.create_pidfd(false)
.spawn()
.unwrap()
.pidfd().expect_err("pidfd should not have been created when create_pid(false) is set");

let _ = Command::new("echo")
.spawn()
.unwrap()
.pidfd().expect_err("pidfd should not have been created");
}
Original file line number Diff line number Diff line change
@@ -2,6 +2,10 @@
// no-prefer-dynamic

#![crate_type = "proc-macro"]
#![crate_name = "group_compat_hack"]

// This file has an unusual name in order to trigger the back-compat
// code in the compiler

extern crate proc_macro;
use proc_macro::TokenStream;
8 changes: 5 additions & 3 deletions src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// check-pass
// aux-build:group-compat-hack.rs
// aux-build:pin-project-internal-0.4.0.rs
// compile-flags: -Z span-debug

#![no_std] // Don't load unnecessary hygiene information from std
@@ -51,14 +51,16 @@ mod actix_web_test {
include!("actix-web/src/extract.rs");

struct Foo;
tuple_from_req!(Foo);
tuple_from_req!(Foo); //~ WARN using an old version
//~| WARN this was previously
}

mod actix_web_version_test {
include!("actix-web-2.0.0/src/extract.rs");

struct Foo;
tuple_from_req!(Foo);
tuple_from_req!(Foo); //~ WARN using an old version
//~| WARN this was previously
}

mod actori_web_test {
Original file line number Diff line number Diff line change
@@ -31,7 +31,39 @@ LL | impl_macros!(Foo);
= note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

warning: 2 warnings emitted
warning: using an old version of `actix-web`
--> $DIR/actix-web/src/extract.rs:5:34
|
LL | #[my_macro] struct Three($T);
| ^^
|
::: $DIR/group-compat-hack.rs:54:5
|
LL | tuple_from_req!(Foo);
| --------------------- in this macro invocation
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

warning: using an old version of `actix-web`
--> $DIR/actix-web-2.0.0/src/extract.rs:5:34
|
LL | #[my_macro] struct Three($T);
| ^^
|
::: $DIR/group-compat-hack.rs:62:5
|
LL | tuple_from_req!(Foo);
| --------------------- in this macro invocation
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

warning: 4 warnings emitted

Future incompatibility report: Future breakage date: None, diagnostic:
warning: using an old version of `time-macros-impl`
@@ -68,3 +100,37 @@ LL | impl_macros!(Foo);
= note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

Future breakage date: None, diagnostic:
warning: using an old version of `actix-web`
--> $DIR/actix-web/src/extract.rs:5:34
|
LL | #[my_macro] struct Three($T);
| ^^
|
::: $DIR/group-compat-hack.rs:54:5
|
LL | tuple_from_req!(Foo);
| --------------------- in this macro invocation
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

Future breakage date: None, diagnostic:
warning: using an old version of `actix-web`
--> $DIR/actix-web-2.0.0/src/extract.rs:5:34
|
LL | #[my_macro] struct Three($T);
| ^^
|
::: $DIR/group-compat-hack.rs:62:5
|
LL | tuple_from_req!(Foo);
| --------------------- in this macro invocation
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

Original file line number Diff line number Diff line change
@@ -5,6 +5,6 @@ Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/tim
Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:46:13: 46:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }]
Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:39:25: 39:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:39:32: 39:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:47:12: 47:15 (#0) }], span: $DIR/group-compat-hack.rs:39:38: 39:43 (#28) }], span: $DIR/group-compat-hack.rs:39:37: 39:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:39:44: 39:45 (#28) }]
Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:54:21: 54:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }]
Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:61:21: 61:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }]
Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:68:21: 68:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }]
Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:75:21: 75:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }]
Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:62:21: 62:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }]
Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:70:21: 70:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:33: 5:35 (#43) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }]
Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:77:21: 77:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:33: 5:35 (#48) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }]