Skip to content
Closed
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
5faae38
apfloat: improve doc comments
RalfJung Aug 9, 2019
a3639c6
Make all alt builders produce parallel-enabled compilers
Mark-Simulacrum Sep 23, 2019
f290467
syntax: cleanup method parsing.
Centril Sep 29, 2019
378cc98
syntax: `is_named_argument` -> `is_named_param`.
Centril Sep 29, 2019
4fa9c3b
syntax refactor `parse_fn_params`
Centril Sep 29, 2019
40dc9da
syntax refactor `parse_self_param` (1)
Centril Sep 29, 2019
f688f8a
syntax refactor `parse_self_param` (2)
Centril Sep 29, 2019
ac454e9
syntax refactor `parse_self_param` (3)
Centril Sep 30, 2019
4306d00
syntax refactor `parse_self_param` (4)
Centril Sep 30, 2019
0492302
syntax refactor `parse_self_param` (5)
Centril Sep 30, 2019
347deac
syntax: reorder param parsing to make more sense.
Centril Sep 30, 2019
d9d0e5d
syntax: cleanup `parse_fn_decl`.
Centril Sep 30, 2019
5b80ead
syntax: misc cleanup
Centril Sep 30, 2019
66bf323
syntax: cleanup `parse_visibility`.
Centril Sep 30, 2019
573a8d8
syntax: extract `error_on_invalid_abi`.
Centril Sep 30, 2019
258e86a
syntax: fuse more code paths together.
Centril Sep 30, 2019
bea404f
syntax: stylistic cleanup in item parsing.
Centril Sep 30, 2019
151ce96
syntax: reduce repetition in fn parsing.
Centril Sep 30, 2019
b0b073c
Self-Profiling: Refactor SelfProfiler API to be RAII based where poss…
michaelwoerister Sep 27, 2019
d942622
Self-Profiling: Make names of existing events more consistent and use…
michaelwoerister Sep 27, 2019
1a1067d
Make the default parallelism 1
Mark-Simulacrum Sep 30, 2019
c9baaa7
Fixes #64919. Suggest fix based on operator precendence.
sam09 Sep 30, 2019
df298b4
syntax: document some methods.
Centril Oct 1, 2019
30647d1
syntax: put helpers of `parse_self_param` in the method.
Centril Oct 1, 2019
49780d2
syntax: merge things back into `parse_visibility`.
Centril Oct 1, 2019
e046904
syntax: de-closure-ify `check_or_expected`.
Centril Oct 1, 2019
5c5dd80
syntax: reformat passing of `FnHeader` to `parse_item_fn`.
Centril Oct 1, 2019
9e4eb46
Change to use exprPrecedence instead of exprKind.
sam09 Oct 1, 2019
e1d9f82
Update cargo.
michaelwoerister Oct 1, 2019
6c1b447
Remove unneeded `fn main` blocks from docs
tesuji Oct 1, 2019
3173a09
Update `Cargo.lock` for cargo update
alexcrichton Oct 1, 2019
afc2bcc
Rollup merge of #63416 - RalfJung:apfloat, r=eddyb
tmandry Oct 1, 2019
4992a08
Rollup merge of #64722 - Mark-Simulacrum:alt-parallel, r=alexcrichton
tmandry Oct 1, 2019
8f7c4c0
Rollup merge of #64840 - michaelwoerister:self-profiling-raii-refacto…
tmandry Oct 1, 2019
837c8a2
Rollup merge of #64910 - Centril:params-cleanup, r=petrochenkov
tmandry Oct 1, 2019
3ab24e6
Rollup merge of #64912 - lzutao:unneeded-main-doc, r=jonas-schievink
tmandry Oct 1, 2019
d452213
Rollup merge of #64933 - sam09:master, r=estebank
tmandry Oct 1, 2019
243dbc5
Rollup merge of #64952 - michaelwoerister:update-cargo, r=alexcrichton
tmandry Oct 1, 2019
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
15 changes: 7 additions & 8 deletions Cargo.lock
Original file line number Diff line number Diff line change
@@ -265,7 +265,7 @@ dependencies = [

[[package]]
name = "cargo"
version = "0.40.0"
version = "0.41.0"
dependencies = [
"atty",
"bytesize",
@@ -600,7 +600,7 @@ checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"

[[package]]
name = "crates-io"
version = "0.28.0"
version = "0.29.0"
dependencies = [
"curl",
"failure",
@@ -730,25 +730,24 @@ dependencies = [

[[package]]
name = "curl"
version = "0.4.21"
version = "0.4.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a85f2f95f2bd277d316d1aa8a477687ab4a6942258c7db7c89c187534669979c"
checksum = "d08ad3cb89d076a36b0ce5749eec2c9964f70c0c58480ab6b75a91ec4fc206d8"
dependencies = [
"curl-sys",
"kernel32-sys",
"libc",
"openssl-probe",
"openssl-sys",
"schannel",
"socket2",
"winapi 0.2.8",
"winapi 0.3.6",
]

[[package]]
name = "curl-sys"
version = "0.4.18"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d91a0052d5b982887d8e829bee0faffc7218ea3c6ebd3d6c2c8f678a93c9a42"
checksum = "520594da9914c1dc77ce3be450fc1c74fde67c82966d80f8e93c6d460eb0e9ae"
dependencies = [
"cc",
"libc",
3 changes: 3 additions & 0 deletions src/ci/run.sh
Original file line number Diff line number Diff line change
@@ -55,6 +55,9 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then
if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
elif [ "$DEPLOY_ALT" != "" ]; then
if [ "$NO_PARALLEL_COMPILER" = "" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.parallel-compiler"
fi
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-assertions"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.verify-llvm-ir"
fi
54 changes: 21 additions & 33 deletions src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
@@ -29,10 +29,8 @@
//! Nil,
//! }
//!
//! fn main() {
//! let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
//! println!("{:?}", list);
//! }
//! let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
//! println!("{:?}", list);
//! ```
//!
//! This will print `Cons(1, Cons(2, Nil))`.
@@ -375,14 +373,12 @@ impl<T: ?Sized> Box<T> {
/// ```
/// #![feature(box_into_raw_non_null)]
///
/// fn main() {
/// let x = Box::new(5);
/// let ptr = Box::into_raw_non_null(x);
/// let x = Box::new(5);
/// let ptr = Box::into_raw_non_null(x);
///
/// // Clean up the memory by converting the NonNull pointer back
/// // into a Box and letting the Box be dropped.
/// let x = unsafe { Box::from_raw(ptr.as_ptr()) };
/// }
/// // Clean up the memory by converting the NonNull pointer back
/// // into a Box and letting the Box be dropped.
/// let x = unsafe { Box::from_raw(ptr.as_ptr()) };
/// ```
#[unstable(feature = "box_into_raw_non_null", issue = "47336")]
#[inline]
@@ -428,23 +424,19 @@ impl<T: ?Sized> Box<T> {
/// Simple usage:
///
/// ```
/// fn main() {
/// let x = Box::new(41);
/// let static_ref: &'static mut usize = Box::leak(x);
/// *static_ref += 1;
/// assert_eq!(*static_ref, 42);
/// }
/// let x = Box::new(41);
/// let static_ref: &'static mut usize = Box::leak(x);
/// *static_ref += 1;
/// assert_eq!(*static_ref, 42);
/// ```
///
/// Unsized data:
///
/// ```
/// fn main() {
/// let x = vec![1, 2, 3].into_boxed_slice();
/// let static_ref = Box::leak(x);
/// static_ref[0] = 4;
/// assert_eq!(*static_ref, [4, 2, 3]);
/// }
/// let x = vec![1, 2, 3].into_boxed_slice();
/// let static_ref = Box::leak(x);
/// static_ref[0] = 4;
/// assert_eq!(*static_ref, [4, 2, 3]);
/// ```
#[stable(feature = "box_leak", since = "1.26.0")]
#[inline]
@@ -780,11 +772,9 @@ impl Box<dyn Any> {
/// }
/// }
///
/// fn main() {
/// let my_string = "Hello World".to_string();
/// print_if_string(Box::new(my_string));
/// print_if_string(Box::new(0i8));
/// }
/// let my_string = "Hello World".to_string();
/// print_if_string(Box::new(my_string));
/// print_if_string(Box::new(0i8));
/// ```
pub fn downcast<T: Any>(self) -> Result<Box<T>, Box<dyn Any>> {
if self.is::<T>() {
@@ -814,11 +804,9 @@ impl Box<dyn Any + Send> {
/// }
/// }
///
/// fn main() {
/// let my_string = "Hello World".to_string();
/// print_if_string(Box::new(my_string));
/// print_if_string(Box::new(0i8));
/// }
/// let my_string = "Hello World".to_string();
/// print_if_string(Box::new(my_string));
/// print_if_string(Box::new(0i8));
/// ```
pub fn downcast<T: Any>(self) -> Result<Box<T>, Box<dyn Any + Send>> {
<Box<dyn Any>>::downcast(self).map_err(|s| unsafe {
2 changes: 0 additions & 2 deletions src/liballoc/collections/btree/map.rs
Original file line number Diff line number Diff line change
@@ -2226,14 +2226,12 @@ impl<'a, K: Ord, V: Default> Entry<'a, K, V> {
/// # Examples
///
/// ```
/// # fn main() {
/// use std::collections::BTreeMap;
///
/// let mut map: BTreeMap<&str, Option<usize>> = BTreeMap::new();
/// map.entry("poneyland").or_default();
///
/// assert_eq!(map["poneyland"], None);
/// # }
/// ```
pub fn or_default(self) -> &'a mut V {
match self {
8 changes: 3 additions & 5 deletions src/liballoc/rc.rs
Original file line number Diff line number Diff line change
@@ -861,11 +861,9 @@ impl Rc<dyn Any> {
/// }
/// }
///
/// fn main() {
/// let my_string = "Hello World".to_string();
/// print_if_string(Rc::new(my_string));
/// print_if_string(Rc::new(0i8));
/// }
/// let my_string = "Hello World".to_string();
/// print_if_string(Rc::new(my_string));
/// print_if_string(Rc::new(0i8));
/// ```
pub fn downcast<T: Any>(self) -> Result<Rc<T>, Rc<dyn Any>> {
if (*self).is::<T>() {
11 changes: 3 additions & 8 deletions src/liballoc/slice.rs
Original file line number Diff line number Diff line change
@@ -412,20 +412,15 @@ impl<T> [T] {
///
/// ```
/// #![feature(repeat_generic_slice)]
///
/// fn main() {
/// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]);
/// }
/// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]);
/// ```
///
/// A panic upon overflow:
///
/// ```should_panic
/// #![feature(repeat_generic_slice)]
/// fn main() {
/// // this will panic at runtime
/// b"0123456789abcdef".repeat(usize::max_value());
/// }
/// // this will panic at runtime
/// b"0123456789abcdef".repeat(usize::max_value());
/// ```
#[unstable(feature = "repeat_generic_slice",
reason = "it's on str, why not on slice?",
6 changes: 2 additions & 4 deletions src/liballoc/str.rs
Original file line number Diff line number Diff line change
@@ -500,10 +500,8 @@ impl str {
/// A panic upon overflow:
///
/// ```should_panic
/// fn main() {
/// // this will panic at runtime
/// "0123456789abcdef".repeat(usize::max_value());
/// }
/// // this will panic at runtime
/// "0123456789abcdef".repeat(usize::max_value());
/// ```
#[stable(feature = "repeat_str", since = "1.16.0")]
pub fn repeat(&self, n: usize) -> String {
6 changes: 2 additions & 4 deletions src/liballoc/string.rs
Original file line number Diff line number Diff line change
@@ -164,10 +164,8 @@ use crate::vec::Vec;
///
/// fn example_func<A: TraitExample>(example_arg: A) {}
///
/// fn main() {
/// let example_string = String::from("example_string");
/// example_func(&example_string);
/// }
/// let example_string = String::from("example_string");
/// example_func(&example_string);
/// ```
///
/// There are two options that would work instead. The first would be to
8 changes: 3 additions & 5 deletions src/liballoc/sync.rs
Original file line number Diff line number Diff line change
@@ -1244,11 +1244,9 @@ impl Arc<dyn Any + Send + Sync> {
/// }
/// }
///
/// fn main() {
/// let my_string = "Hello World".to_string();
/// print_if_string(Arc::new(my_string));
/// print_if_string(Arc::new(0i8));
/// }
/// let my_string = "Hello World".to_string();
/// print_if_string(Arc::new(my_string));
/// print_if_string(Arc::new(0i8));
/// ```
pub fn downcast<T>(self) -> Result<Arc<T>, Self>
where
44 changes: 20 additions & 24 deletions src/liballoc/vec.rs
Original file line number Diff line number Diff line change
@@ -389,28 +389,26 @@ impl<T> Vec<T> {
/// use std::ptr;
/// use std::mem;
///
/// fn main() {
/// let mut v = vec![1, 2, 3];
///
/// // Pull out the various important pieces of information about `v`
/// let p = v.as_mut_ptr();
/// let len = v.len();
/// let cap = v.capacity();
/// let mut v = vec![1, 2, 3];
///
/// unsafe {
/// // Cast `v` into the void: no destructor run, so we are in
/// // complete control of the allocation to which `p` points.
/// mem::forget(v);
/// // Pull out the various important pieces of information about `v`
/// let p = v.as_mut_ptr();
/// let len = v.len();
/// let cap = v.capacity();
///
/// // Overwrite memory with 4, 5, 6
/// for i in 0..len as isize {
/// ptr::write(p.offset(i), 4 + i);
/// }
/// unsafe {
/// // Cast `v` into the void: no destructor run, so we are in
/// // complete control of the allocation to which `p` points.
/// mem::forget(v);
///
/// // Put everything back together into a Vec
/// let rebuilt = Vec::from_raw_parts(p, len, cap);
/// assert_eq!(rebuilt, [4, 5, 6]);
/// // Overwrite memory with 4, 5, 6
/// for i in 0..len as isize {
/// ptr::write(p.offset(i), 4 + i);
/// }
///
/// // Put everything back together into a Vec
/// let rebuilt = Vec::from_raw_parts(p, len, cap);
/// assert_eq!(rebuilt, [4, 5, 6]);
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1391,12 +1389,10 @@ impl<T> Vec<T> {
/// ```
/// #![feature(vec_leak)]
///
/// fn main() {
/// let x = vec![1, 2, 3];
/// let static_ref: &'static mut [usize] = Vec::leak(x);
/// static_ref[0] += 1;
/// assert_eq!(static_ref, &[2, 2, 3]);
/// }
/// let x = vec![1, 2, 3];
/// let static_ref: &'static mut [usize] = Vec::leak(x);
/// static_ref[0] += 1;
/// assert_eq!(static_ref, &[2, 2, 3]);
/// ```
#[unstable(feature = "vec_leak", issue = "62195")]
#[inline]
90 changes: 34 additions & 56 deletions src/libcore/any.rs
Original file line number Diff line number Diff line change
@@ -87,10 +87,8 @@ pub trait Any: 'static {
/// TypeId::of::<String>() == s.type_id()
/// }
///
/// fn main() {
/// assert_eq!(is_string(&0), false);
/// assert_eq!(is_string(&"cookie monster".to_string()), true);
/// }
/// assert_eq!(is_string(&0), false);
/// assert_eq!(is_string(&"cookie monster".to_string()), true);
/// ```
#[stable(feature = "get_type_id", since = "1.34.0")]
fn type_id(&self) -> TypeId;
@@ -145,10 +143,8 @@ impl dyn Any {
/// }
/// }
///
/// fn main() {
/// is_string(&0);
/// is_string(&"cookie monster".to_string());
/// }
/// is_string(&0);
/// is_string(&"cookie monster".to_string());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@@ -179,10 +175,8 @@ impl dyn Any {
/// }
/// }
///
/// fn main() {
/// print_if_string(&0);
/// print_if_string(&"cookie monster".to_string());
/// }
/// print_if_string(&0);
/// print_if_string(&"cookie monster".to_string());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@@ -210,16 +204,14 @@ impl dyn Any {
/// }
/// }
///
/// fn main() {
/// let mut x = 10u32;
/// let mut s = "starlord".to_string();
/// let mut x = 10u32;
/// let mut s = "starlord".to_string();
///
/// modify_if_u32(&mut x);
/// modify_if_u32(&mut s);
/// modify_if_u32(&mut x);
/// modify_if_u32(&mut s);
///
/// assert_eq!(x, 42);
/// assert_eq!(&s, "starlord");
/// }
/// assert_eq!(x, 42);
/// assert_eq!(&s, "starlord");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@@ -250,10 +242,8 @@ impl dyn Any+Send {
/// }
/// }
///
/// fn main() {
/// is_string(&0);
/// is_string(&"cookie monster".to_string());
/// }
/// is_string(&0);
/// is_string(&"cookie monster".to_string());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@@ -276,10 +266,8 @@ impl dyn Any+Send {
/// }
/// }
///
/// fn main() {
/// print_if_string(&0);
/// print_if_string(&"cookie monster".to_string());
/// }
/// print_if_string(&0);
/// print_if_string(&"cookie monster".to_string());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@@ -300,16 +288,14 @@ impl dyn Any+Send {
/// }
/// }
///
/// fn main() {
/// let mut x = 10u32;
/// let mut s = "starlord".to_string();
/// let mut x = 10u32;
/// let mut s = "starlord".to_string();
///
/// modify_if_u32(&mut x);
/// modify_if_u32(&mut s);
/// modify_if_u32(&mut x);
/// modify_if_u32(&mut s);
///
/// assert_eq!(x, 42);
/// assert_eq!(&s, "starlord");
/// }
/// assert_eq!(x, 42);
/// assert_eq!(&s, "starlord");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@@ -334,10 +320,8 @@ impl dyn Any+Send+Sync {
/// }
/// }
///
/// fn main() {
/// is_string(&0);
/// is_string(&"cookie monster".to_string());
/// }
/// is_string(&0);
/// is_string(&"cookie monster".to_string());
/// ```
#[stable(feature = "any_send_sync_methods", since = "1.28.0")]
#[inline]
@@ -360,10 +344,8 @@ impl dyn Any+Send+Sync {
/// }
/// }
///
/// fn main() {
/// print_if_string(&0);
/// print_if_string(&"cookie monster".to_string());
/// }
/// print_if_string(&0);
/// print_if_string(&"cookie monster".to_string());
/// ```
#[stable(feature = "any_send_sync_methods", since = "1.28.0")]
#[inline]
@@ -384,16 +366,14 @@ impl dyn Any+Send+Sync {
/// }
/// }
///
/// fn main() {
/// let mut x = 10u32;
/// let mut s = "starlord".to_string();
/// let mut x = 10u32;
/// let mut s = "starlord".to_string();
///
/// modify_if_u32(&mut x);
/// modify_if_u32(&mut s);
/// modify_if_u32(&mut x);
/// modify_if_u32(&mut s);
///
/// assert_eq!(x, 42);
/// assert_eq!(&s, "starlord");
/// }
/// assert_eq!(x, 42);
/// assert_eq!(&s, "starlord");
/// ```
#[stable(feature = "any_send_sync_methods", since = "1.28.0")]
#[inline]
@@ -437,10 +417,8 @@ impl TypeId {
/// TypeId::of::<String>() == TypeId::of::<T>()
/// }
///
/// fn main() {
/// assert_eq!(is_string(&0), false);
/// assert_eq!(is_string(&"cookie monster".to_string()), true);
/// }
/// assert_eq!(is_string(&0), false);
/// assert_eq!(is_string(&"cookie monster".to_string()), true);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="const_type_id")]
16 changes: 6 additions & 10 deletions src/libcore/char/convert.rs
Original file line number Diff line number Diff line change
@@ -111,11 +111,9 @@ impl From<char> for u32 {
/// ```
/// use std::mem;
///
/// fn main() {
/// let c = 'c';
/// let u = u32::from(c);
/// assert!(4 == mem::size_of_val(&u))
/// }
/// let c = 'c';
/// let u = u32::from(c);
/// assert!(4 == mem::size_of_val(&u))
/// ```
#[inline]
fn from(c: char) -> Self {
@@ -150,11 +148,9 @@ impl From<u8> for char {
/// ```
/// use std::mem;
///
/// fn main() {
/// let u = 32 as u8;
/// let c = char::from(u);
/// assert!(4 == mem::size_of_val(&c))
/// }
/// let u = 32 as u8;
/// let c = char::from(u);
/// assert!(4 == mem::size_of_val(&c))
/// ```
#[inline]
fn from(i: u8) -> Self {
50 changes: 26 additions & 24 deletions src/libcore/char/decode.rs
Original file line number Diff line number Diff line change
@@ -31,39 +31,41 @@ pub struct DecodeUtf16Error {
/// ```
/// use std::char::decode_utf16;
///
/// fn main() {
/// // 𝄞mus<invalid>ic<invalid>
/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075,
/// 0x0073, 0xDD1E, 0x0069, 0x0063,
/// 0xD834];
/// // 𝄞mus<invalid>ic<invalid>
/// let v = [
/// 0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834,
/// ];
///
/// assert_eq!(decode_utf16(v.iter().cloned())
/// .map(|r| r.map_err(|e| e.unpaired_surrogate()))
/// .collect::<Vec<_>>(),
/// vec![Ok('𝄞'),
/// Ok('m'), Ok('u'), Ok('s'),
/// Err(0xDD1E),
/// Ok('i'), Ok('c'),
/// Err(0xD834)]);
/// }
/// assert_eq!(
/// decode_utf16(v.iter().cloned())
/// .map(|r| r.map_err(|e| e.unpaired_surrogate()))
/// .collect::<Vec<_>>(),
/// vec![
/// Ok('𝄞'),
/// Ok('m'), Ok('u'), Ok('s'),
/// Err(0xDD1E),
/// Ok('i'), Ok('c'),
/// Err(0xD834)
/// ]
/// );
/// ```
///
/// A lossy decoder can be obtained by replacing `Err` results with the replacement character:
///
/// ```
/// use std::char::{decode_utf16, REPLACEMENT_CHARACTER};
///
/// fn main() {
/// // 𝄞mus<invalid>ic<invalid>
/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075,
/// 0x0073, 0xDD1E, 0x0069, 0x0063,
/// 0xD834];
/// // 𝄞mus<invalid>ic<invalid>
/// let v = [
/// 0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834,
/// ];
///
/// assert_eq!(decode_utf16(v.iter().cloned())
/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
/// .collect::<String>(),
/// "𝄞mus�ic�");
/// }
/// assert_eq!(
/// decode_utf16(v.iter().cloned())
/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
/// .collect::<String>(),
/// "𝄞mus�ic�"
/// );
/// ```
#[stable(feature = "decode_utf16", since = "1.9.0")]
#[inline]
10 changes: 4 additions & 6 deletions src/libcore/fmt/mod.rs
Original file line number Diff line number Diff line change
@@ -1532,12 +1532,10 @@ impl<'a> Formatter<'a> {
/// }
/// }
///
/// fn main() {
/// assert_eq!(&format!("{:<}", Foo), "left");
/// assert_eq!(&format!("{:>}", Foo), "right");
/// assert_eq!(&format!("{:^}", Foo), "center");
/// assert_eq!(&format!("{}", Foo), "into the void");
/// }
/// assert_eq!(&format!("{:<}", Foo), "left");
/// assert_eq!(&format!("{:>}", Foo), "right");
/// assert_eq!(&format!("{:^}", Foo), "center");
/// assert_eq!(&format!("{}", Foo), "into the void");
/// ```
#[stable(feature = "fmt_flags_align", since = "1.28.0")]
pub fn align(&self) -> Option<Alignment> {
48 changes: 23 additions & 25 deletions src/libcore/ptr/mod.rs
Original file line number Diff line number Diff line change
@@ -2732,31 +2732,29 @@ impl<T: ?Sized> Eq for *mut T {}
/// impl Trait for Wrapper {}
/// impl Trait for i32 {}
///
/// fn main() {
/// let wrapper = Wrapper { member: 10 };
///
/// // Pointers have equal addresses.
/// assert!(std::ptr::eq(
/// &wrapper as *const Wrapper as *const u8,
/// &wrapper.member as *const i32 as *const u8
/// ));
///
/// // Objects have equal addresses, but `Trait` has different implementations.
/// assert!(!std::ptr::eq(
/// &wrapper as &dyn Trait,
/// &wrapper.member as &dyn Trait,
/// ));
/// assert!(!std::ptr::eq(
/// &wrapper as &dyn Trait as *const dyn Trait,
/// &wrapper.member as &dyn Trait as *const dyn Trait,
/// ));
///
/// // Converting the reference to a `*const u8` compares by address.
/// assert!(std::ptr::eq(
/// &wrapper as &dyn Trait as *const dyn Trait as *const u8,
/// &wrapper.member as &dyn Trait as *const dyn Trait as *const u8,
/// ));
/// }
/// let wrapper = Wrapper { member: 10 };
///
/// // Pointers have equal addresses.
/// assert!(std::ptr::eq(
/// &wrapper as *const Wrapper as *const u8,
/// &wrapper.member as *const i32 as *const u8
/// ));
///
/// // Objects have equal addresses, but `Trait` has different implementations.
/// assert!(!std::ptr::eq(
/// &wrapper as &dyn Trait,
/// &wrapper.member as &dyn Trait,
/// ));
/// assert!(!std::ptr::eq(
/// &wrapper as &dyn Trait as *const dyn Trait,
/// &wrapper.member as &dyn Trait as *const dyn Trait,
/// ));
///
/// // Converting the reference to a `*const u8` compares by address.
/// assert!(std::ptr::eq(
/// &wrapper as &dyn Trait as *const dyn Trait as *const u8,
/// &wrapper.member as &dyn Trait as *const dyn Trait as *const u8,
/// ));
/// ```
#[stable(feature = "ptr_eq", since = "1.17.0")]
#[inline]
19 changes: 16 additions & 3 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
@@ -805,6 +805,7 @@ macro_rules! options {
pub const parse_list: Option<&str> = Some("a space-separated list of strings");
pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
pub const parse_threads: Option<&str> = Some("a number");
pub const parse_uint: Option<&str> = Some("a number");
pub const parse_passes: Option<&str> =
Some("a space-separated list of passes, or `all`");
@@ -948,6 +949,14 @@ macro_rules! options {
}
}

fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
match v.and_then(|s| s.parse().ok()) {
Some(0) => { *slot = ::num_cpus::get(); true },
Some(i) => { *slot = i; true },
None => false
}
}

fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
match v.and_then(|s| s.parse().ok()) {
Some(i) => { *slot = i; true },
@@ -1251,7 +1260,11 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"prints the LLVM optimization passes being run"),
ast_json: bool = (false, parse_bool, [UNTRACKED],
"print the AST as JSON and halt"),
threads: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
// We default to 1 here since we want to behave like
// a sequential compiler for now. This'll likely be adjusted
// in the future. Note that -Zthreads=0 is the way to get
// the num_cpus behavior.
threads: usize = (1, parse_threads, [UNTRACKED],
"use a thread pool with N threads"),
ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
"print the pre-expansion AST as JSON and halt"),
@@ -2146,14 +2159,14 @@ pub fn build_session_options_and_crate_config(
}
}

if debugging_opts.threads == Some(0) {
if debugging_opts.threads == 0 {
early_error(
error_format,
"value for threads must be a positive non-zero integer",
);
}

if debugging_opts.threads.unwrap_or(1) > 1 && debugging_opts.fuel.is_some() {
if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
early_error(
error_format,
"optimization fuel is incompatible with multiple threads",
32 changes: 4 additions & 28 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ use syntax::source_map;
use syntax::parse::{self, ParseSess};
use syntax::symbol::Symbol;
use syntax_pos::{MultiSpan, Span};
use crate::util::profiling::SelfProfiler;
use crate::util::profiling::{SelfProfiler, SelfProfilerRef};

use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple};
use rustc_data_structures::flock;
@@ -129,7 +129,7 @@ pub struct Session {
pub profile_channel: Lock<Option<mpsc::Sender<ProfileQueriesMsg>>>,

/// Used by `-Z self-profile`.
pub self_profiling: Option<Arc<SelfProfiler>>,
pub prof: SelfProfilerRef,

/// Some measurements that are being gathered during compilation.
pub perf_stats: PerfStats,
@@ -835,24 +835,6 @@ impl Session {
}
}

#[inline(never)]
#[cold]
fn profiler_active<F: FnOnce(&SelfProfiler) -> ()>(&self, f: F) {
match &self.self_profiling {
None => bug!("profiler_active() called but there was no profiler active"),
Some(profiler) => {
f(&profiler);
}
}
}

#[inline(always)]
pub fn profiler<F: FnOnce(&SelfProfiler) -> ()>(&self, f: F) {
if unlikely!(self.self_profiling.is_some()) {
self.profiler_active(f)
}
}

pub fn print_perf_stats(&self) {
println!(
"Total time spent computing symbol hashes: {}",
@@ -896,16 +878,10 @@ impl Session {
ret
}

/// Returns the number of query threads that should be used for this
/// compilation
pub fn threads_from_count(query_threads: Option<usize>) -> usize {
query_threads.unwrap_or(::num_cpus::get())
}

/// Returns the number of query threads that should be used for this
/// compilation
pub fn threads(&self) -> usize {
Self::threads_from_count(self.opts.debugging_opts.threads)
self.opts.debugging_opts.threads
}

/// Returns the number of codegen units that should be used for this
@@ -1257,7 +1233,7 @@ fn build_session_(
imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())),
incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
cgu_reuse_tracker,
self_profiling: self_profiler,
prof: SelfProfilerRef::new(self_profiler),
profile_channel: Lock::new(None),
perf_stats: PerfStats {
symbol_hash_time: Lock::new(Duration::from_secs(0)),
4 changes: 4 additions & 0 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@ use crate::ty::CanonicalPolyFnSig;
use crate::util::common::ErrorReported;
use crate::util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap, ItemLocalSet};
use crate::util::nodemap::{FxHashMap, FxHashSet};
use crate::util::profiling::SelfProfilerRef;

use errors::DiagnosticBuilder;
use arena::SyncDroplessArena;
@@ -1030,6 +1031,8 @@ pub struct GlobalCtxt<'tcx> {

pub dep_graph: DepGraph,

pub prof: SelfProfilerRef,

/// Common objects.
pub common: Common<'tcx>,

@@ -1260,6 +1263,7 @@ impl<'tcx> TyCtxt<'tcx> {
arena: WorkerLocal::new(|_| Arena::default()),
interners,
dep_graph,
prof: s.prof.clone(),
common,
types: common_types,
lifetimes: common_lifetimes,
26 changes: 11 additions & 15 deletions src/librustc/ty/query/plumbing.rs
Original file line number Diff line number Diff line change
@@ -112,7 +112,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
let mut lock = cache.get_shard_by_value(key).lock();
if let Some(value) = lock.results.get(key) {
profq_msg!(tcx, ProfileQueriesMsg::CacheHit);
tcx.sess.profiler(|p| p.record_query_hit(Q::NAME));
tcx.prof.query_cache_hit(Q::NAME);
let result = (value.value.clone(), value.index);
#[cfg(debug_assertions)]
{
@@ -128,7 +128,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
// in another thread has completed. Record how long we wait in the
// self-profiler.
#[cfg(parallel_compiler)]
tcx.sess.profiler(|p| p.query_blocked_start(Q::NAME));
tcx.prof.query_blocked_start(Q::NAME);

job.clone()
},
@@ -170,7 +170,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
#[cfg(parallel_compiler)]
{
let result = job.r#await(tcx, span);
tcx.sess.profiler(|p| p.query_blocked_end(Q::NAME));
tcx.prof.query_blocked_end(Q::NAME);

if let Err(cycle) = result {
return TryGetJob::Cycle(Q::handle_cycle_error(tcx, cycle));
@@ -382,8 +382,9 @@ impl<'tcx> TyCtxt<'tcx> {
}

if Q::ANON {

profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
self.sess.profiler(|p| p.start_query(Q::NAME));
let prof_timer = self.prof.query_provider(Q::NAME);

let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
self.start_query(job.job.clone(), diagnostics, |tcx| {
@@ -393,7 +394,7 @@ impl<'tcx> TyCtxt<'tcx> {
})
});

self.sess.profiler(|p| p.end_query(Q::NAME));
drop(prof_timer);
profq_msg!(self, ProfileQueriesMsg::ProviderEnd);

self.dep_graph.read_index(dep_node_index);
@@ -451,9 +452,8 @@ impl<'tcx> TyCtxt<'tcx> {
// First we try to load the result from the on-disk cache.
let result = if Q::cache_on_disk(self, key.clone(), None) &&
self.sess.opts.debugging_opts.incremental_queries {
self.sess.profiler(|p| p.incremental_load_result_start(Q::NAME));
let _prof_timer = self.prof.incr_cache_loading(Q::NAME);
let result = Q::try_load_from_disk(self, prev_dep_node_index);
self.sess.profiler(|p| p.incremental_load_result_end(Q::NAME));

// We always expect to find a cached result for things that
// can be forced from `DepNode`.
@@ -469,21 +469,17 @@ impl<'tcx> TyCtxt<'tcx> {

let result = if let Some(result) = result {
profq_msg!(self, ProfileQueriesMsg::CacheHit);
self.sess.profiler(|p| p.record_query_hit(Q::NAME));

result
} else {
// We could not load a result from the on-disk cache, so
// recompute.

self.sess.profiler(|p| p.start_query(Q::NAME));
let _prof_timer = self.prof.query_provider(Q::NAME);

// The dep-graph for this computation is already in-place.
let result = self.dep_graph.with_ignore(|| {
Q::compute(self, key)
});

self.sess.profiler(|p| p.end_query(Q::NAME));
result
};

@@ -551,7 +547,7 @@ impl<'tcx> TyCtxt<'tcx> {
key, dep_node);

profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
self.sess.profiler(|p| p.start_query(Q::NAME));
let prof_timer = self.prof.query_provider(Q::NAME);

let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
self.start_query(job.job.clone(), diagnostics, |tcx| {
@@ -571,7 +567,7 @@ impl<'tcx> TyCtxt<'tcx> {
})
});

self.sess.profiler(|p| p.end_query(Q::NAME));
drop(prof_timer);
profq_msg!(self, ProfileQueriesMsg::ProviderEnd);

if unlikely!(self.sess.opts.debugging_opts.query_dep_graph) {
@@ -619,7 +615,7 @@ impl<'tcx> TyCtxt<'tcx> {
let _ = self.get_query::<Q>(DUMMY_SP, key);
} else {
profq_msg!(self, ProfileQueriesMsg::CacheHit);
self.sess.profiler(|p| p.record_query_hit(Q::NAME));
self.prof.query_cache_hit(Q::NAME);
}
}

326 changes: 237 additions & 89 deletions src/librustc/util/profiling.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::borrow::Cow;
use std::error::Error;
use std::fs;
use std::mem::{self, Discriminant};
use std::path::Path;
use std::process;
use std::sync::Arc;
use std::thread::ThreadId;
use std::u32;

@@ -62,6 +62,206 @@ fn thread_id_to_u64(tid: ThreadId) -> u64 {
unsafe { mem::transmute::<ThreadId, u64>(tid) }
}


/// A reference to the SelfProfiler. It can be cloned and sent across thread
/// boundaries at will.
#[derive(Clone)]
pub struct SelfProfilerRef {
// This field is `None` if self-profiling is disabled for the current
// compilation session.
profiler: Option<Arc<SelfProfiler>>,

// We store the filter mask directly in the reference because that doesn't
// cost anything and allows for filtering with checking if the profiler is
// actually enabled.
event_filter_mask: EventFilter,
}

impl SelfProfilerRef {

pub fn new(profiler: Option<Arc<SelfProfiler>>) -> SelfProfilerRef {
// If there is no SelfProfiler then the filter mask is set to NONE,
// ensuring that nothing ever tries to actually access it.
let event_filter_mask = profiler
.as_ref()
.map(|p| p.event_filter_mask)
.unwrap_or(EventFilter::NONE);

SelfProfilerRef {
profiler,
event_filter_mask,
}
}

// This shim makes sure that calls only get executed if the filter mask
// lets them pass. It also contains some trickery to make sure that
// code is optimized for non-profiling compilation sessions, i.e. anything
// past the filter check is never inlined so it doesn't clutter the fast
// path.
#[inline(always)]
fn exec<F>(&self, event_filter: EventFilter, f: F) -> TimingGuard<'_>
where F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a>
{
#[inline(never)]
fn cold_call<F>(profiler_ref: &SelfProfilerRef, f: F) -> TimingGuard<'_>
where F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a>
{
let profiler = profiler_ref.profiler.as_ref().unwrap();
f(&**profiler)
}

if unlikely!(self.event_filter_mask.contains(event_filter)) {
cold_call(self, f)
} else {
TimingGuard::none()
}
}

/// Start profiling a generic activity. Profiling continues until the
/// TimingGuard returned from this call is dropped.
#[inline(always)]
pub fn generic_activity(&self, event_id: &str) -> TimingGuard<'_> {
self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| {
let event_id = profiler.profiler.alloc_string(event_id);
TimingGuard::start(
profiler,
profiler.generic_activity_event_kind,
event_id
)
})
}

/// Start profiling a generic activity. Profiling continues until
/// `generic_activity_end` is called. The RAII-based `generic_activity`
/// usually is the better alternative.
#[inline(always)]
pub fn generic_activity_start(&self, event_id: &str) {
self.non_guard_generic_event(
|profiler| profiler.generic_activity_event_kind,
|profiler| profiler.profiler.alloc_string(event_id),
EventFilter::GENERIC_ACTIVITIES,
TimestampKind::Start,
);
}

/// End profiling a generic activity that was started with
/// `generic_activity_start`. The RAII-based `generic_activity` usually is
/// the better alternative.
#[inline(always)]
pub fn generic_activity_end(&self, event_id: &str) {
self.non_guard_generic_event(
|profiler| profiler.generic_activity_event_kind,
|profiler| profiler.profiler.alloc_string(event_id),
EventFilter::GENERIC_ACTIVITIES,
TimestampKind::End,
);
}

/// Start profiling a query provider. Profiling continues until the
/// TimingGuard returned from this call is dropped.
#[inline(always)]
pub fn query_provider(&self, query_name: QueryName) -> TimingGuard<'_> {
self.exec(EventFilter::QUERY_PROVIDERS, |profiler| {
let event_id = SelfProfiler::get_query_name_string_id(query_name);
TimingGuard::start(profiler, profiler.query_event_kind, event_id)
})
}

/// Record a query in-memory cache hit.
#[inline(always)]
pub fn query_cache_hit(&self, query_name: QueryName) {
self.non_guard_query_event(
|profiler| profiler.query_cache_hit_event_kind,
query_name,
EventFilter::QUERY_CACHE_HITS,
TimestampKind::Instant,
);
}

/// Start profiling a query being blocked on a concurrent execution.
/// Profiling continues until `query_blocked_end` is called.
#[inline(always)]
pub fn query_blocked_start(&self, query_name: QueryName) {
self.non_guard_query_event(
|profiler| profiler.query_blocked_event_kind,
query_name,
EventFilter::QUERY_BLOCKED,
TimestampKind::Start,
);
}

/// End profiling a query being blocked on a concurrent execution.
#[inline(always)]
pub fn query_blocked_end(&self, query_name: QueryName) {
self.non_guard_query_event(
|profiler| profiler.query_blocked_event_kind,
query_name,
EventFilter::QUERY_BLOCKED,
TimestampKind::End,
);
}

/// Start profiling how long it takes to load a query result from the
/// incremental compilation on-disk cache. Profiling continues until the
/// TimingGuard returned from this call is dropped.
#[inline(always)]
pub fn incr_cache_loading(&self, query_name: QueryName) -> TimingGuard<'_> {
self.exec(EventFilter::INCR_CACHE_LOADS, |profiler| {
let event_id = SelfProfiler::get_query_name_string_id(query_name);
TimingGuard::start(
profiler,
profiler.incremental_load_result_event_kind,
event_id
)
})
}

#[inline(always)]
fn non_guard_query_event(
&self,
event_kind: fn(&SelfProfiler) -> StringId,
query_name: QueryName,
event_filter: EventFilter,
timestamp_kind: TimestampKind
) {
drop(self.exec(event_filter, |profiler| {
let event_id = SelfProfiler::get_query_name_string_id(query_name);
let thread_id = thread_id_to_u64(std::thread::current().id());

profiler.profiler.record_event(
event_kind(profiler),
event_id,
thread_id,
timestamp_kind,
);

TimingGuard::none()
}));
}

#[inline(always)]
fn non_guard_generic_event<F: FnOnce(&SelfProfiler) -> StringId>(
&self,
event_kind: fn(&SelfProfiler) -> StringId,
event_id: F,
event_filter: EventFilter,
timestamp_kind: TimestampKind
) {
drop(self.exec(event_filter, |profiler| {
let thread_id = thread_id_to_u64(std::thread::current().id());

profiler.profiler.record_event(
event_kind(profiler),
event_id(profiler),
thread_id,
timestamp_kind,
);

TimingGuard::none()
}));
}
}

pub struct SelfProfiler {
profiler: Profiler,
event_filter_mask: EventFilter,
@@ -143,103 +343,51 @@ impl SelfProfiler {
let id = SelfProfiler::get_query_name_string_id(query_name);
self.profiler.alloc_string_with_reserved_id(id, query_name.as_str());
}
}

#[inline]
pub fn start_activity(
&self,
label: impl Into<Cow<'static, str>>,
) {
if self.event_filter_mask.contains(EventFilter::GENERIC_ACTIVITIES) {
self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::Start);
}
}

#[inline]
pub fn end_activity(
&self,
label: impl Into<Cow<'static, str>>,
) {
if self.event_filter_mask.contains(EventFilter::GENERIC_ACTIVITIES) {
self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::End);
}
}

#[inline]
pub fn record_query_hit(&self, query_name: QueryName) {
if self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS) {
self.record_query(query_name, self.query_cache_hit_event_kind, TimestampKind::Instant);
}
}

#[inline]
pub fn start_query(&self, query_name: QueryName) {
if self.event_filter_mask.contains(EventFilter::QUERY_PROVIDERS) {
self.record_query(query_name, self.query_event_kind, TimestampKind::Start);
}
}

#[inline]
pub fn end_query(&self, query_name: QueryName) {
if self.event_filter_mask.contains(EventFilter::QUERY_PROVIDERS) {
self.record_query(query_name, self.query_event_kind, TimestampKind::End);
}
}

#[inline]
pub fn incremental_load_result_start(&self, query_name: QueryName) {
if self.event_filter_mask.contains(EventFilter::INCR_CACHE_LOADS) {
self.record_query(
query_name,
self.incremental_load_result_event_kind,
TimestampKind::Start
);
}
}

#[inline]
pub fn incremental_load_result_end(&self, query_name: QueryName) {
if self.event_filter_mask.contains(EventFilter::INCR_CACHE_LOADS) {
self.record_query(
query_name,
self.incremental_load_result_event_kind,
TimestampKind::End
);
}
}
#[must_use]
pub struct TimingGuard<'a>(Option<TimingGuardInternal<'a>>);

#[inline]
pub fn query_blocked_start(&self, query_name: QueryName) {
if self.event_filter_mask.contains(EventFilter::QUERY_BLOCKED) {
self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::Start);
}
}
struct TimingGuardInternal<'a> {
raw_profiler: &'a Profiler,
event_id: StringId,
event_kind: StringId,
thread_id: u64,
}

impl<'a> TimingGuard<'a> {
#[inline]
pub fn query_blocked_end(&self, query_name: QueryName) {
if self.event_filter_mask.contains(EventFilter::QUERY_BLOCKED) {
self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::End);
}
pub fn start(
profiler: &'a SelfProfiler,
event_kind: StringId,
event_id: StringId,
) -> TimingGuard<'a> {
let thread_id = thread_id_to_u64(std::thread::current().id());
let raw_profiler = &profiler.profiler;
raw_profiler.record_event(event_kind, event_id, thread_id, TimestampKind::Start);

TimingGuard(Some(TimingGuardInternal {
raw_profiler,
event_kind,
event_id,
thread_id,
}))
}

#[inline]
fn record(&self, event_id: &str, event_kind: StringId, timestamp_kind: TimestampKind) {
let thread_id = thread_id_to_u64(std::thread::current().id());

let event_id = self.profiler.alloc_string(event_id);
self.profiler.record_event(event_kind, event_id, thread_id, timestamp_kind);
pub fn none() -> TimingGuard<'a> {
TimingGuard(None)
}
}

impl<'a> Drop for TimingGuardInternal<'a> {
#[inline]
fn record_query(
&self,
query_name: QueryName,
event_kind: StringId,
timestamp_kind: TimestampKind,
) {
let dep_node_name = SelfProfiler::get_query_name_string_id(query_name);

let thread_id = thread_id_to_u64(std::thread::current().id());

self.profiler.record_event(event_kind, dep_node_name, thread_id, timestamp_kind);
fn drop(&mut self) {
self.raw_profiler.record_event(
self.event_kind,
self.event_id,
self.thread_id,
TimestampKind::End
);
}
}
3 changes: 2 additions & 1 deletion src/librustc_apfloat/lib.rs
Original file line number Diff line number Diff line change
@@ -555,12 +555,13 @@ pub trait Float
fn ilogb(self) -> ExpInt;

/// Returns: self * 2<sup>exp</sup> for integral exponents.
/// Equivalent to C standard library function `ldexp`.
fn scalbn_r(self, exp: ExpInt, round: Round) -> Self;
fn scalbn(self, exp: ExpInt) -> Self {
self.scalbn_r(exp, Round::NearestTiesToEven)
}

/// Equivalent of C standard library function.
/// Equivalent to C standard library function with the same name.
///
/// While the C standard says exp is an unspecified value for infinity and nan,
/// this returns INT_MAX for infinities, and INT_MIN for NaNs (see `ilogb`).
105 changes: 62 additions & 43 deletions src/librustc_codegen_llvm/back/lto.rs
Original file line number Diff line number Diff line change
@@ -62,11 +62,13 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
};
let exported_symbols = cgcx.exported_symbols
.as_ref().expect("needs exported symbols for LTO");
let mut symbol_white_list = exported_symbols[&LOCAL_CRATE]
.iter()
.filter_map(symbol_filter)
.collect::<Vec<CString>>();
let _timer = cgcx.profile_activity("generate_symbol_white_list_for_thinlto");
let mut symbol_white_list = {
let _timer = cgcx.prof.generic_activity("LLVM_lto_generate_symbol_white_list");
exported_symbols[&LOCAL_CRATE]
.iter()
.filter_map(symbol_filter)
.collect::<Vec<CString>>()
};
info!("{} symbols to preserve in this crate", symbol_white_list.len());

// If we're performing LTO for the entire crate graph, then for each of our
@@ -95,14 +97,17 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
}

for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
let _timer = cgcx.profile_activity(format!("load: {}", path.display()));
let exported_symbols = cgcx.exported_symbols
.as_ref().expect("needs exported symbols for LTO");
symbol_white_list.extend(
exported_symbols[&cnum]
.iter()
.filter_map(symbol_filter));
{
let _timer = cgcx.prof.generic_activity("LLVM_lto_generate_symbol_white_list");
symbol_white_list.extend(
exported_symbols[&cnum]
.iter()
.filter_map(symbol_filter));
}

let _timer = cgcx.prof.generic_activity("LLVM_lto_load_upstream_bitcode");
let archive = ArchiveRO::open(&path).expect("wanted an rlib");
let bytecodes = archive.iter().filter_map(|child| {
child.ok().and_then(|c| c.name().map(|name| (name, c)))
@@ -189,6 +194,7 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
symbol_white_list: &[*const libc::c_char])
-> Result<LtoModuleCodegen<LlvmCodegenBackend>, FatalError>
{
let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_build_monolithic_module");
info!("going for a fat lto");

// Sort out all our lists of incoming modules into two lists.
@@ -287,6 +293,7 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
// save and persist everything with the original module.
let mut linker = Linker::new(llmod);
for (bc_decoded, name) in serialized_modules {
let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_link_module");
info!("linking {:?}", name);
time_ext(cgcx.time_passes, None, &format!("ll link {:?}", name), || {
let data = bc_decoded.data();
@@ -388,6 +395,7 @@ fn thin_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
symbol_white_list: &[*const libc::c_char])
-> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError>
{
let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis");
unsafe {
info!("going for that thin, thin LTO");

@@ -601,16 +609,6 @@ impl ModuleBuffer {
llvm::LLVMRustModuleBufferCreate(m)
})
}

pub fn parse<'a>(
&self,
name: &str,
cx: &'a llvm::Context,
handler: &Handler,
) -> Result<&'a llvm::Module, FatalError> {
let name = CString::new(name).unwrap();
parse_module(cx, &name, self.data(), handler)
}
}

impl ModuleBufferMethods for ModuleBuffer {
@@ -723,7 +721,7 @@ pub unsafe fn optimize_thin_module(
// Like with "fat" LTO, get some better optimizations if landing pads
// are disabled by removing all landing pads.
if cgcx.no_landing_pads {
let _timer = cgcx.profile_activity("LLVM_remove_landing_pads");
let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_remove_landing_pads");
llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
save_temp_bitcode(&cgcx, &module, "thin-lto-after-nounwind");
}
@@ -736,26 +734,41 @@ pub unsafe fn optimize_thin_module(
//
// You can find some more comments about these functions in the LLVM
// bindings we've got (currently `PassWrapper.cpp`)
if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
{
let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_rename");
if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-rename");
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-rename");
if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))

{
let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_resolve_weak");
if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve");
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve");
if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))

{
let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_internalize");
if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize");
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize");
if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))

{
let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_import");
if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-import");
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-import");

// Ok now this is a bit unfortunate. This is also something you won't
// find upstream in LLVM's ThinLTO passes! This is a hack for now to
@@ -786,18 +799,24 @@ pub unsafe fn optimize_thin_module(
// not too much) but for now at least gets LLVM to emit valid DWARF (or
// so it appears). Hopefully we can remove this once upstream bugs are
// fixed in LLVM.
llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1);
save_temp_bitcode(cgcx, &module, "thin-lto-after-patch");
{
let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_patch_debuginfo");
llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1);
save_temp_bitcode(cgcx, &module, "thin-lto-after-patch");
}

// Alright now that we've done everything related to the ThinLTO
// analysis it's time to run some optimizations! Here we use the same
// `run_pass_manager` as the "fat" LTO above except that we tell it to
// populate a thin-specific pass manager, which presumably LLVM treats a
// little differently.
info!("running thin lto passes over {}", module.name);
let config = cgcx.config(module.kind);
run_pass_manager(cgcx, &module, config, true);
save_temp_bitcode(cgcx, &module, "thin-lto-after-pm");
{
let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_optimize");
info!("running thin lto passes over {}", module.name);
let config = cgcx.config(module.kind);
run_pass_manager(cgcx, &module, config, true);
save_temp_bitcode(cgcx, &module, "thin-lto-after-pm");
}
}
Ok(module)
}
25 changes: 14 additions & 11 deletions src/librustc_codegen_llvm/back/write.rs
Original file line number Diff line number Diff line change
@@ -306,6 +306,8 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
config: &ModuleConfig)
-> Result<(), FatalError>
{
let _timer = cgcx.prof.generic_activity("LLVM_module_optimize");

let llmod = module.module_llvm.llmod();
let llcx = &*module.module_llvm.llcx;
let tm = &*module.module_llvm.tm;
@@ -423,7 +425,7 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,

// Finally, run the actual optimization passes
{
let _timer = cgcx.profile_activity("LLVM_function_passes");
let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_function_passes");
time_ext(config.time_passes,
None,
&format!("llvm function passes [{}]", module_name.unwrap()),
@@ -432,7 +434,7 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
});
}
{
let _timer = cgcx.profile_activity("LLVM_module_passes");
let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_module_passes");
time_ext(config.time_passes,
None,
&format!("llvm module passes [{}]", module_name.unwrap()),
@@ -454,7 +456,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>,
config: &ModuleConfig)
-> Result<CompiledModule, FatalError>
{
let _timer = cgcx.profile_activity("codegen");
let _timer = cgcx.prof.generic_activity("LLVM_module_codegen");
{
let llmod = module.module_llvm.llmod();
let llcx = &*module.module_llvm.llcx;
@@ -505,25 +507,26 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>,


if write_bc || config.emit_bc_compressed || config.embed_bitcode {
let _timer = cgcx.profile_activity("LLVM_make_bitcode");
let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_make_bitcode");
let thin = ThinBuffer::new(llmod);
let data = thin.data();

if write_bc {
let _timer = cgcx.profile_activity("LLVM_emit_bitcode");
let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_bitcode");
if let Err(e) = fs::write(&bc_out, data) {
let msg = format!("failed to write bytecode to {}: {}", bc_out.display(), e);
diag_handler.err(&msg);
}
}

if config.embed_bitcode {
let _timer = cgcx.profile_activity("LLVM_embed_bitcode");
let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_embed_bitcode");
embed_bitcode(cgcx, llcx, llmod, Some(data));
}

if config.emit_bc_compressed {
let _timer = cgcx.profile_activity("LLVM_compress_bitcode");
let _timer =
cgcx.prof.generic_activity("LLVM_module_codegen_emit_compressed_bitcode");
let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION);
let data = bytecode::encode(&module.name, data);
if let Err(e) = fs::write(&dst, data) {
@@ -538,7 +541,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>,
time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()),
|| -> Result<(), FatalError> {
if config.emit_ir {
let _timer = cgcx.profile_activity("LLVM_emit_ir");
let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_ir");
let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name);
let out_c = path_to_c_string(&out);

@@ -585,7 +588,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>,
}

if config.emit_asm || asm_to_obj {
let _timer = cgcx.profile_activity("LLVM_emit_asm");
let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_asm");
let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);

// We can't use the same module for asm and binary output, because that triggers
@@ -603,13 +606,13 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>,
}

if write_obj {
let _timer = cgcx.profile_activity("LLVM_emit_obj");
let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_obj");
with_codegen(tm, llmod, config.no_builtins, |cpm| {
write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
llvm::FileType::ObjectFile)
})?;
} else if asm_to_obj {
let _timer = cgcx.profile_activity("LLVM_asm_to_obj");
let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_asm_to_obj");
let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
run_assembler(cgcx, diag_handler, &assembly, &obj_out);

2 changes: 2 additions & 0 deletions src/librustc_codegen_llvm/base.rs
Original file line number Diff line number Diff line change
@@ -108,6 +108,7 @@ pub fn compile_codegen_unit(
cgu_name: InternedString,
tx_to_llvm_workers: &std::sync::mpsc::Sender<Box<dyn std::any::Any + Send>>,
) {
let prof_timer = tcx.prof.generic_activity("codegen_module");
let start_time = Instant::now();

let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
@@ -119,6 +120,7 @@ pub fn compile_codegen_unit(
dep_graph::hash_result,
);
let time_to_codegen = start_time.elapsed();
drop(prof_timer);

// We assume that the cost to run LLVM on a CGU is proportional to
// the time we needed for codegenning it.
4 changes: 2 additions & 2 deletions src/librustc_codegen_llvm/lib.rs
Original file line number Diff line number Diff line change
@@ -324,8 +324,9 @@ impl CodegenBackend for LlvmCodegenBackend {

// Run the linker on any artifacts that resulted from the LLVM run.
// This should produce either a finished executable or library.
sess.profiler(|p| p.start_activity("link_crate"));
time(sess, "linking", || {
let _prof_timer = sess.prof.generic_activity("link_crate");

use rustc_codegen_ssa::back::link::link_binary;
use crate::back::archive::LlvmArchiveBuilder;

@@ -338,7 +339,6 @@ impl CodegenBackend for LlvmCodegenBackend {
target_cpu,
);
});
sess.profiler(|p| p.end_activity("link_crate"));

// Now that we won't touch anything in the incremental compilation directory
// any more, we can finalize it (which involves renaming it)
78 changes: 11 additions & 67 deletions src/librustc_codegen_ssa/back/write.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ use rustc::util::nodemap::FxHashMap;
use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc::ty::TyCtxt;
use rustc::util::common::{time_depth, set_time_depth, print_time_passes_entry};
use rustc::util::profiling::SelfProfiler;
use rustc::util::profiling::SelfProfilerRef;
use rustc_fs_util::link_or_copy;
use rustc_data_structures::svh::Svh;
use rustc_errors::{Handler, Level, FatalError, DiagnosticId};
@@ -31,7 +31,6 @@ use syntax_pos::symbol::{Symbol, sym};
use jobserver::{Client, Acquired};

use std::any::Any;
use std::borrow::Cow;
use std::fs;
use std::io;
use std::mem;
@@ -196,42 +195,13 @@ impl<B: WriteBackendMethods> Clone for TargetMachineFactory<B> {
}
}

pub struct ProfileGenericActivityTimer {
profiler: Option<Arc<SelfProfiler>>,
label: Cow<'static, str>,
}

impl ProfileGenericActivityTimer {
pub fn start(
profiler: Option<Arc<SelfProfiler>>,
label: Cow<'static, str>,
) -> ProfileGenericActivityTimer {
if let Some(profiler) = &profiler {
profiler.start_activity(label.clone());
}

ProfileGenericActivityTimer {
profiler,
label,
}
}
}

impl Drop for ProfileGenericActivityTimer {
fn drop(&mut self) {
if let Some(profiler) = &self.profiler {
profiler.end_activity(self.label.clone());
}
}
}

/// Additional resources used by optimize_and_codegen (not module specific)
#[derive(Clone)]
pub struct CodegenContext<B: WriteBackendMethods> {
// Resources needed when running LTO
pub backend: B,
pub time_passes: bool,
pub profiler: Option<Arc<SelfProfiler>>,
pub prof: SelfProfilerRef,
pub lto: Lto,
pub no_landing_pads: bool,
pub save_temps: bool,
@@ -283,31 +253,6 @@ impl<B: WriteBackendMethods> CodegenContext<B> {
ModuleKind::Allocator => &self.allocator_module_config,
}
}

#[inline(never)]
#[cold]
fn profiler_active<F: FnOnce(&SelfProfiler) -> ()>(&self, f: F) {
match &self.profiler {
None => bug!("profiler_active() called but there was no profiler active"),
Some(profiler) => {
f(&*profiler);
}
}
}

#[inline(always)]
pub fn profile<F: FnOnce(&SelfProfiler) -> ()>(&self, f: F) {
if unlikely!(self.profiler.is_some()) {
self.profiler_active(f)
}
}

pub fn profile_activity(
&self,
label: impl Into<Cow<'static, str>>,
) -> ProfileGenericActivityTimer {
ProfileGenericActivityTimer::start(self.profiler.clone(), label.into())
}
}

fn generate_lto_work<B: ExtraBackendMethods>(
@@ -316,7 +261,7 @@ fn generate_lto_work<B: ExtraBackendMethods>(
needs_thin_lto: Vec<(String, B::ThinBuffer)>,
import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>
) -> Vec<(WorkItem<B>, u64)> {
cgcx.profile(|p| p.start_activity("codegen_run_lto"));
let _prof_timer = cgcx.prof.generic_activity("codegen_run_lto");

let (lto_modules, copy_jobs) = if !needs_fat_lto.is_empty() {
assert!(needs_thin_lto.is_empty());
@@ -343,8 +288,6 @@ fn generate_lto_work<B: ExtraBackendMethods>(
}), 0)
})).collect();

cgcx.profile(|p| p.end_activity("codegen_run_lto"));

result
}

@@ -380,6 +323,9 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
) -> OngoingCodegen<B> {
let (coordinator_send, coordinator_receive) = channel();
let sess = tcx.sess;

sess.prof.generic_activity_start("codegen_and_optimize_crate");

let crate_name = tcx.crate_name(LOCAL_CRATE);
let crate_hash = tcx.crate_hash(LOCAL_CRATE);
let no_builtins = attr::contains_name(&tcx.hir().krate().attrs, sym::no_builtins);
@@ -1088,7 +1034,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
save_temps: sess.opts.cg.save_temps,
opts: Arc::new(sess.opts.clone()),
time_passes: sess.time_extended(),
profiler: sess.self_profiling.clone(),
prof: sess.prof.clone(),
exported_symbols,
plugin_passes: sess.plugin_llvm_passes.borrow().clone(),
remark: sess.opts.cg.remark.clone(),
@@ -1645,12 +1591,8 @@ fn spawn_work<B: ExtraBackendMethods>(
// as a diagnostic was already sent off to the main thread - just
// surface that there was an error in this worker.
bomb.result = {
let label = work.name();
cgcx.profile(|p| p.start_activity(label.clone()));
let result = execute_work_item(&cgcx, work).ok();
cgcx.profile(|p| p.end_activity(label));

result
let _prof_timer = cgcx.prof.generic_activity(&work.name());
execute_work_item(&cgcx, work).ok()
};
});
}
@@ -1835,6 +1777,8 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
self.backend.print_pass_timings()
}

sess.prof.generic_activity_end("codegen_and_optimize_crate");

(CodegenResults {
crate_name: self.crate_name,
crate_hash: self.crate_hash,
5 changes: 1 addition & 4 deletions src/librustc_codegen_ssa/base.rs
Original file line number Diff line number Diff line change
@@ -559,7 +559,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(

if need_metadata_module {
// Codegen the encoded metadata.
tcx.sess.profiler(|p| p.start_activity("codegen crate metadata"));
let _prof_timer = tcx.prof.generic_activity("codegen_crate_metadata");

let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE,
&["crate"],
@@ -570,7 +570,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
backend.write_compressed_metadata(tcx, &ongoing_codegen.metadata,
&mut metadata_llvm_module);
});
tcx.sess.profiler(|p| p.end_activity("codegen crate metadata"));

let metadata_module = ModuleCodegen {
name: metadata_cgu_name,
@@ -599,11 +598,9 @@ pub fn codegen_crate<B: ExtraBackendMethods>(

match cgu_reuse {
CguReuse::No => {
tcx.sess.profiler(|p| p.start_activity(format!("codegen {}", cgu.name())));
let start_time = Instant::now();
backend.compile_codegen_unit(tcx, *cgu.name(), &ongoing_codegen.coordinator_send);
total_codegen_time += start_time.elapsed();
tcx.sess.profiler(|p| p.end_activity(format!("codegen {}", cgu.name())));
false
}
CguReuse::PreLto => {
1 change: 0 additions & 1 deletion src/librustc_codegen_ssa/lib.rs
Original file line number Diff line number Diff line change
@@ -21,7 +21,6 @@
#[macro_use] extern crate log;
#[macro_use] extern crate rustc;
#[macro_use] extern crate rustc_data_structures;
#[macro_use] extern crate syntax;

use std::path::PathBuf;
6 changes: 6 additions & 0 deletions src/librustc_incremental/persist/save.rs
Original file line number Diff line number Diff line change
@@ -28,6 +28,8 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {

join(move || {
if tcx.sess.opts.debugging_opts.incremental_queries {
let _timer = tcx.prof.generic_activity("incr_comp_persist_result_cache");

time(sess, "persist query result cache", || {
save_in(sess,
query_cache_path,
@@ -36,6 +38,8 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
}
}, || {
time(sess, "persist dep-graph", || {
let _timer = tcx.prof.generic_activity("incr_comp_persist_dep_graph");

save_in(sess,
dep_graph_path,
|e| {
@@ -135,6 +139,7 @@ fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut Encoder) {

// Encode the graph data.
let serialized_graph = time(tcx.sess, "getting serialized graph", || {
let _timer = tcx.prof.generic_activity("incr_comp_serialize_dep_graph");
tcx.dep_graph.serialize()
});

@@ -214,6 +219,7 @@ fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut Encoder) {
}

time(tcx.sess, "encoding serialized graph", || {
let _timer = tcx.prof.generic_activity("incr_comp_encode_serialized_dep_graph");
serialized_graph.encode(encoder).unwrap();
});
}
5 changes: 4 additions & 1 deletion src/librustc_interface/interface.rs
Original file line number Diff line number Diff line change
@@ -147,5 +147,8 @@ where
F: FnOnce() -> R + Send,
R: Send,
{
util::spawn_thread_pool(edition, None, &None, f)
// the 1 here is duplicating code in config.opts.debugging_opts.threads
// which also defaults to 1; it ultimately doesn't matter as the default
// isn't threaded, and just ignores this parameter
util::spawn_thread_pool(edition, 1, &None, f)
}
24 changes: 12 additions & 12 deletions src/librustc_interface/passes.rs
Original file line number Diff line number Diff line change
@@ -59,15 +59,17 @@ use std::rc::Rc;
pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
sess.diagnostic()
.set_continue_after_error(sess.opts.debugging_opts.continue_parse_after_error);
sess.profiler(|p| p.start_activity("parsing"));
let krate = time(sess, "parsing", || match *input {
Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess),
Input::Str {
ref input,
ref name,
} => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess),
let krate = time(sess, "parsing", || {
let _prof_timer = sess.prof.generic_activity("parse_crate");

match *input {
Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess),
Input::Str {
ref input,
ref name,
} => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess),
}
})?;
sess.profiler(|p| p.end_activity("parsing"));

sess.diagnostic().set_continue_after_error(true);

@@ -355,8 +357,8 @@ fn configure_and_expand_inner<'a>(
);

// Expand all macros
sess.profiler(|p| p.start_activity("macro expansion"));
krate = time(sess, "expansion", || {
let _prof_timer = sess.prof.generic_activity("macro_expand_crate");
// Windows dlls do not have rpaths, so they don't know how to find their
// dependencies. It's up to us to tell the system where to find all the
// dependent dlls. Note that this uses cfg!(windows) as opposed to
@@ -430,7 +432,6 @@ fn configure_and_expand_inner<'a>(
}
krate
});
sess.profiler(|p| p.end_activity("macro expansion"));

time(sess, "maybe building test harness", || {
syntax_ext::test_harness::inject(
@@ -1071,11 +1072,10 @@ pub fn start_codegen<'tcx>(
encode_and_write_metadata(tcx, outputs)
});

tcx.sess.profiler(|p| p.start_activity("codegen crate"));
let codegen = time(tcx.sess, "codegen", move || {
let _prof_timer = tcx.prof.generic_activity("codegen_crate");
codegen_backend.codegen_crate(tcx, metadata, need_metadata_module)
});
tcx.sess.profiler(|p| p.end_activity("codegen crate"));

if log_enabled!(::log::Level::Info) {
println!("Post-codegen");
6 changes: 3 additions & 3 deletions src/librustc_interface/util.rs
Original file line number Diff line number Diff line change
@@ -173,7 +173,7 @@ pub fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f:
#[cfg(not(parallel_compiler))]
pub fn spawn_thread_pool<F: FnOnce() -> R + Send, R: Send>(
edition: Edition,
_threads: Option<usize>,
_threads: usize,
stderr: &Option<Arc<Mutex<Vec<u8>>>>,
f: F,
) -> R {
@@ -198,7 +198,7 @@ pub fn spawn_thread_pool<F: FnOnce() -> R + Send, R: Send>(
#[cfg(parallel_compiler)]
pub fn spawn_thread_pool<F: FnOnce() -> R + Send, R: Send>(
edition: Edition,
threads: Option<usize>,
threads: usize,
stderr: &Option<Arc<Mutex<Vec<u8>>>>,
f: F,
) -> R {
@@ -209,7 +209,7 @@ pub fn spawn_thread_pool<F: FnOnce() -> R + Send, R: Send>(
let mut config = ThreadPoolBuilder::new()
.acquire_thread_handler(jobserver::acquire_thread)
.release_thread_handler(jobserver::release_thread)
.num_threads(Session::threads_from_count(threads))
.num_threads(threads)
.deadlock_handler(|| unsafe { ty::query::handle_deadlock() });

if let Some(size) = get_stack_size() {
7 changes: 6 additions & 1 deletion src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
@@ -128,6 +128,7 @@ use syntax::attr;
use syntax::feature_gate::{GateIssue, emit_feature_err};
use syntax::source_map::{DUMMY_SP, original_sp};
use syntax::symbol::{kw, sym};
use syntax::util::parser::ExprPrecedence;

use std::cell::{Cell, RefCell, Ref, RefMut};
use std::collections::hash_map::Entry;
@@ -4345,7 +4346,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let max_len = receiver.rfind(".").unwrap();
format!("{}{}", &receiver[..max_len], method_call)
} else {
format!("{}{}", receiver, method_call)
if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
format!("({}){}", receiver, method_call)
} else {
format!("{}{}", receiver, method_call)
}
};
Some(if is_struct_pat_shorthand_field {
format!("{}: {}", receiver, sugg)
4 changes: 1 addition & 3 deletions src/librustc_typeck/lib.rs
Original file line number Diff line number Diff line change
@@ -295,7 +295,7 @@ pub fn provide(providers: &mut Providers<'_>) {
}

pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
tcx.sess.profiler(|p| p.start_activity("type-check crate"));
let _prof_timer = tcx.prof.generic_activity("type_check_crate");

// this ensures that later parts of type checking can assume that items
// have valid types and not error
@@ -347,8 +347,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
check_unused::check_crate(tcx);
check_for_entry_fn(tcx);

tcx.sess.profiler(|p| p.end_activity("type-check crate"));

if tcx.sess.err_count() == 0 {
Ok(())
} else {
11 changes: 3 additions & 8 deletions src/libstd/collections/hash/map.rs
Original file line number Diff line number Diff line change
@@ -192,14 +192,9 @@ use crate::sys;
/// ```
/// use std::collections::HashMap;
///
/// fn main() {
/// let timber_resources: HashMap<&str, i32> =
/// [("Norway", 100),
/// ("Denmark", 50),
/// ("Iceland", 10)]
/// .iter().cloned().collect();
/// // use the values stored in map
/// }
/// let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)]
/// .iter().cloned().collect();
/// // use the values stored in map
/// ```
#[derive(Clone)]
8 changes: 3 additions & 5 deletions src/libstd/collections/hash/set.rs
Original file line number Diff line number Diff line change
@@ -93,11 +93,9 @@ use super::map::{self, HashMap, Keys, RandomState};
/// ```
/// use std::collections::HashSet;
///
/// fn main() {
/// let viking_names: HashSet<&'static str> =
/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect();
/// // use the values stored in the set
/// }
/// let viking_names: HashSet<&'static str> =
/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect();
/// // use the values stored in the set
/// ```
///
/// [`Cell`]: ../../std/cell/struct.Cell.html
17 changes: 6 additions & 11 deletions src/libstd/net/addr.rs
Original file line number Diff line number Diff line change
@@ -217,11 +217,9 @@ impl SocketAddr {
/// ```
/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
///
/// fn main() {
/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
/// assert_eq!(socket.is_ipv4(), true);
/// assert_eq!(socket.is_ipv6(), false);
/// }
/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
/// assert_eq!(socket.is_ipv4(), true);
/// assert_eq!(socket.is_ipv6(), false);
/// ```
#[stable(feature = "sockaddr_checker", since = "1.16.0")]
pub fn is_ipv4(&self) -> bool {
@@ -244,12 +242,9 @@ impl SocketAddr {
/// ```
/// use std::net::{IpAddr, Ipv6Addr, SocketAddr};
///
/// fn main() {
/// let socket = SocketAddr::new(
/// IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080);
/// assert_eq!(socket.is_ipv4(), false);
/// assert_eq!(socket.is_ipv6(), true);
/// }
/// let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080);
/// assert_eq!(socket.is_ipv4(), false);
/// assert_eq!(socket.is_ipv6(), true);
/// ```
#[stable(feature = "sockaddr_checker", since = "1.16.0")]
pub fn is_ipv6(&self) -> bool {
237 changes: 102 additions & 135 deletions src/libstd/net/ip.rs

Large diffs are not rendered by default.

12 changes: 5 additions & 7 deletions src/libstd/primitive_docs.rs
Original file line number Diff line number Diff line change
@@ -426,14 +426,12 @@ mod prim_unit { }
///
/// use std::mem;
///
/// fn main() {
/// unsafe {
/// let my_num: *mut i32 = libc::malloc(mem::size_of::<i32>()) as *mut i32;
/// if my_num.is_null() {
/// panic!("failed to allocate memory");
/// }
/// libc::free(my_num as *mut libc::c_void);
/// unsafe {
/// let my_num: *mut i32 = libc::malloc(mem::size_of::<i32>()) as *mut i32;
/// if my_num.is_null() {
/// panic!("failed to allocate memory");
/// }
/// libc::free(my_num as *mut libc::c_void);
/// }
/// ```
///
2 changes: 1 addition & 1 deletion src/libsyntax/parse/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -1180,7 +1180,7 @@ impl<'a> Parser<'a> {
}
}

crate fn expected_semi_or_open_brace(&mut self) -> PResult<'a, ast::TraitItem> {
crate fn expected_semi_or_open_brace<T>(&mut self) -> PResult<'a, T> {
let token_str = self.this_token_descr();
let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str));
err.span_label(self.token.span, "expected `;` or `{`");
655 changes: 330 additions & 325 deletions src/libsyntax/parse/parser.rs

Large diffs are not rendered by default.

393 changes: 162 additions & 231 deletions src/libsyntax/parse/parser/item.rs

Large diffs are not rendered by default.

8 changes: 2 additions & 6 deletions src/libsyntax/parse/parser/ty.rs
Original file line number Diff line number Diff line change
@@ -231,19 +231,15 @@ impl<'a> Parser<'a> {
}

fn parse_ptr(&mut self) -> PResult<'a, MutTy> {
let mutbl = if self.eat_keyword(kw::Mut) {
Mutability::Mutable
} else if self.eat_keyword(kw::Const) {
Mutability::Immutable
} else {
let mutbl = self.parse_const_or_mut().unwrap_or_else(|| {
let span = self.prev_span;
let msg = "expected mut or const in raw pointer type";
self.struct_span_err(span, msg)
.span_label(span, msg)
.help("use `*mut T` or `*const T` as appropriate")
.emit();
Mutability::Immutable
};
});
let t = self.parse_ty_no_plus()?;
Ok(MutTy { ty: t, mutbl })
}
12 changes: 6 additions & 6 deletions src/test/ui/async-await/edition-deny-async-fns-2015.stderr
Original file line number Diff line number Diff line change
@@ -10,18 +10,18 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
LL | fn baz() { async fn foo() {} }
| ^^^^^

error[E0670]: `async fn` is not permitted in the 2015 edition
--> $DIR/edition-deny-async-fns-2015.rs:8:5
|
LL | async fn bar() {}
| ^^^^^

error[E0670]: `async fn` is not permitted in the 2015 edition
--> $DIR/edition-deny-async-fns-2015.rs:7:1
|
LL | async fn async_baz() {
| ^^^^^

error[E0670]: `async fn` is not permitted in the 2015 edition
--> $DIR/edition-deny-async-fns-2015.rs:8:5
|
LL | async fn bar() {}
| ^^^^^

error[E0670]: `async fn` is not permitted in the 2015 edition
--> $DIR/edition-deny-async-fns-2015.rs:14:5
|
2 changes: 1 addition & 1 deletion src/test/ui/conversion-methods.stderr
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@ LL | let _prove_piercing_earnest: Vec<usize> = &[1, 2, 3];
| ^^^^^^^^^^
| |
| expected struct `std::vec::Vec`, found reference
| help: try using a conversion method: `&[1, 2, 3].to_vec()`
| help: try using a conversion method: `(&[1, 2, 3]).to_vec()`
|
= note: expected type `std::vec::Vec<usize>`
found type `&[{integer}; 3]`
2 changes: 1 addition & 1 deletion src/test/ui/infinite/infinite-autoderef.stderr
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ LL | x = box x;
| ^^^^^
| |
| cyclic type of infinite size
| help: try using a conversion method: `box x.to_string()`
| help: try using a conversion method: `(box x).to_string()`

error[E0055]: reached the recursion limit while auto-dereferencing `Foo`
--> $DIR/infinite-autoderef.rs:25:5
9 changes: 9 additions & 0 deletions src/test/ui/mismatched_types/abridged.rs
Original file line number Diff line number Diff line change
@@ -50,4 +50,13 @@ fn e() -> X<X<String, String>, String> {
x //~ ERROR mismatched types
}

fn f() -> String {
1+2 //~ ERROR mismatched types
}


fn g() -> String {
-2 //~ ERROR mismatched types
}

fn main() {}
30 changes: 29 additions & 1 deletion src/test/ui/mismatched_types/abridged.stderr
Original file line number Diff line number Diff line change
@@ -66,6 +66,34 @@ LL | x
= note: expected type `X<X<_, std::string::String>, _>`
found type `X<X<_, {integer}>, _>`

error: aborting due to 6 previous errors
error[E0308]: mismatched types
--> $DIR/abridged.rs:54:5
|
LL | fn f() -> String {
| ------ expected `std::string::String` because of return type
LL | 1+2
| ^^^
| |
| expected struct `std::string::String`, found integer
| help: try using a conversion method: `(1+2).to_string()`
|
= note: expected type `std::string::String`
found type `{integer}`

error[E0308]: mismatched types
--> $DIR/abridged.rs:59:5
|
LL | fn g() -> String {
| ------ expected `std::string::String` because of return type
LL | -2
| ^^
| |
| expected struct `std::string::String`, found integer
| help: try using a conversion method: `(-2).to_string()`
|
= note: expected type `std::string::String`
found type `{integer}`

error: aborting due to 8 previous errors

For more information about this error, try `rustc --explain E0308`.
2 changes: 1 addition & 1 deletion src/test/ui/occurs-check-2.stderr
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ LL | f = box g;
| ^^^^^
| |
| cyclic type of infinite size
| help: try using a conversion method: `box g.to_string()`
| help: try using a conversion method: `(box g).to_string()`

error: aborting due to previous error

2 changes: 1 addition & 1 deletion src/test/ui/occurs-check.stderr
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ LL | f = box f;
| ^^^^^
| |
| cyclic type of infinite size
| help: try using a conversion method: `box f.to_string()`
| help: try using a conversion method: `(box f).to_string()`

error: aborting due to previous error

2 changes: 1 addition & 1 deletion src/test/ui/span/coerce-suggestions.stderr
Original file line number Diff line number Diff line change
@@ -44,7 +44,7 @@ LL | f = box f;
| ^^^^^
| |
| cyclic type of infinite size
| help: try using a conversion method: `box f.to_string()`
| help: try using a conversion method: `(box f).to_string()`

error[E0308]: mismatched types
--> $DIR/coerce-suggestions.rs:21:9
2 changes: 1 addition & 1 deletion src/tools/cargo
Submodule cargo updated 84 files
+92 −3 CHANGELOG.md
+4 −4 Cargo.toml
+2 −4 crates/cargo-test-support/src/lib.rs
+1 −1 crates/crates-io/Cargo.toml
+11 −2 src/bin/cargo/commands/bench.rs
+7 −1 src/bin/cargo/commands/build.rs
+2 −2 src/bin/cargo/commands/check.rs
+3 −1 src/bin/cargo/commands/clean.rs
+3 −1 src/bin/cargo/commands/clippy.rs
+3 −1 src/bin/cargo/commands/doc.rs
+2 −2 src/bin/cargo/commands/fix.rs
+10 −3 src/bin/cargo/commands/install.rs
+7 −1 src/bin/cargo/commands/run.rs
+7 −2 src/bin/cargo/commands/rustc.rs
+2 −0 src/bin/cargo/commands/rustdoc.rs
+13 −1 src/bin/cargo/commands/test.rs
+43 −38 src/cargo/core/compiler/build_config.rs
+63 −67 src/cargo/core/compiler/build_context/mod.rs
+18 −46 src/cargo/core/compiler/build_context/target_info.rs
+2 −2 src/cargo/core/compiler/build_plan.rs
+15 −8 src/cargo/core/compiler/compilation.rs
+128 −0 src/cargo/core/compiler/compile_kind.rs
+21 −51 src/cargo/core/compiler/context/compilation_files.rs
+23 −31 src/cargo/core/compiler/context/mod.rs
+12 −19 src/cargo/core/compiler/custom_build.rs
+2 −2 src/cargo/core/compiler/fingerprint.rs
+6 −5 src/cargo/core/compiler/job_queue.rs
+16 −22 src/cargo/core/compiler/layout.rs
+12 −43 src/cargo/core/compiler/mod.rs
+5 −10 src/cargo/core/compiler/standard_lib.rs
+2 −11 src/cargo/core/compiler/timings.rs
+3 −3 src/cargo/core/compiler/unit.rs
+10 −12 src/cargo/core/compiler/unit_dependencies.rs
+5 −0 src/cargo/core/features.rs
+20 −1 src/cargo/core/interning.rs
+365 −67 src/cargo/core/profiles.rs
+18 −13 src/cargo/core/resolver/context.rs
+1 −1 src/cargo/core/resolver/errors.rs
+24 −13 src/cargo/ops/cargo_clean.rs
+16 −19 src/cargo/ops/cargo_compile.rs
+10 −19 src/cargo/ops/cargo_doc.rs
+37 −35 src/cargo/ops/cargo_fetch.rs
+7 −9 src/cargo/ops/cargo_install.rs
+10 −1 src/cargo/ops/cargo_package.rs
+11 −19 src/cargo/ops/common_for_install_and_uninstall.rs
+37 −3 src/cargo/ops/registry.rs
+2 −2 src/cargo/sources/registry/mod.rs
+59 −4 src/cargo/util/command_prelude.rs
+26 −0 src/cargo/util/config.rs
+2 −2 src/cargo/util/dependency_queue.rs
+7 −0 src/cargo/util/network.rs
+1 −2 src/cargo/util/progress.rs
+3 −2 src/cargo/util/rustc.rs
+136 −34 src/cargo/util/toml/mod.rs
+7 −0 src/doc/src/reference/config.md
+60 −1 src/doc/src/reference/unstable.md
+9 −2 tests/testsuite/bad_config.rs
+23 −23 tests/testsuite/bench.rs
+0 −12 tests/testsuite/build.rs
+6 −6 tests/testsuite/build_script.rs
+106 −30 tests/testsuite/config.rs
+5 −5 tests/testsuite/cross_compile.rs
+1 −7 tests/testsuite/fix.rs
+25 −26 tests/testsuite/freshness.rs
+1 −1 tests/testsuite/git.rs
+1 −0 tests/testsuite/main.rs
+5 −1 tests/testsuite/member_errors.rs
+0 −20 tests/testsuite/message_format.rs
+1 −1 tests/testsuite/new.rs
+57 −0 tests/testsuite/patch.rs
+2 −2 tests/testsuite/path.rs
+1 −6 tests/testsuite/profile_config.rs
+477 −0 tests/testsuite/profile_custom.rs
+0 −36 tests/testsuite/profile_overrides.rs
+128 −104 tests/testsuite/profile_targets.rs
+1 −1 tests/testsuite/profiles.rs
+55 −0 tests/testsuite/publish_lockfile.rs
+22 −22 tests/testsuite/required_features.rs
+4 −4 tests/testsuite/rustflags.rs
+5 −1 tests/testsuite/search.rs
+2 −2 tests/testsuite/standard_lib.rs
+47 −47 tests/testsuite/test.rs
+1 −6 tests/testsuite/timings.rs
+2 −2 tests/testsuite/tool_paths.rs