Auto merge of #50611 - alexcrichton:rollup, r=alexcrichton

Rollup of 18 pull requests

Successful merges:

 - #49423 (Extend tests for RFC1598 (GAT))
 - #50010 (Give SliceIndex impls a test suite of girth befitting the implementation (and fix a UTF8 boundary check))
 - #50447 (Fix update-references for tests within subdirectories.)
 - #50514 (Pull in a wasm fix from LLVM upstream)
 - #50524 (Make DepGraph::previous_work_products immutable)
 - #50532 (Don't use Lock for heavily accessed CrateMetadata::cnum_map.)
 - #50538 ( Make CrateNum allocation more thread-safe. )
 - #50564 (Inline `Span` methods.)
 - #50565 (Use SmallVec for DepNodeIndex within dep_graph.)
 - #50569 (Allow for specifying a linker plugin for cross-language LTO)
 - #50572 (Clarify in the docs that `mul_add` is not always faster.)
 - #50574 (add fn `into_inner(self) -> (Idx, Idx)` to RangeInclusive (#49022))
 - #50575 (std: Avoid `ptr::copy` if unnecessary in `vec::Drain`)
 - #50588 (Move "See also" disambiguation links for primitive types to top)
 - #50590 (Fix tuple struct field spans)
 - #50591 (Restore RawVec::reserve* documentation)
 - #50598 (Remove unnecessary mutable borrow and resizing in DepGraph::serialize)
 - #50606 (Retry when downloading the Docker cache.)

Failed merges:

 - #50161 (added missing implementation hint)
 - #50558 (Remove all reference to DepGraph::work_products)
This commit is contained in:
bors 2018-05-10 23:33:13 +00:00
commit a006328126
52 changed files with 1394 additions and 496 deletions

View File

@ -36,8 +36,10 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
s3url="s3://$SCCACHE_BUCKET/docker/$cksum"
url="https://s3-us-west-1.amazonaws.com/$SCCACHE_BUCKET/docker/$cksum"
echo "Attempting to download $s3url"
rm -f /tmp/rustci_docker_cache
set +e
loaded_images=$(curl $url | docker load | sed 's/.* sha/sha/')
retry curl -f -L -C - -o /tmp/rustci_docker_cache "$url"
loaded_images=$(docker load -i /tmp/rustci_docker_cache | sed 's/.* sha/sha/')
set -e
echo "Downloaded containers:\n$loaded_images"
fi

View File

@ -21,11 +21,12 @@ function retry {
while true; do
"$@" && break || {
if [[ $n -lt $max ]]; then
sleep $n # don't retry immediately
((n++))
echo "Command failed. Attempt $n/$max:"
else
echo "The command has failed after $n attempts."
exit 1
return 1
fi
}
done

View File

@ -385,26 +385,7 @@ impl<T, A: Alloc> RawVec<T, A> {
}
}
/// Ensures that the buffer contains at least enough space to hold
/// `used_cap + needed_extra_cap` elements. If it doesn't already,
/// will reallocate the minimum possible amount of memory necessary.
/// Generally this will be exactly the amount of memory necessary,
/// but in principle the allocator is free to give back more than
/// we asked for.
///
/// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate
/// the requested space. This is not really unsafe, but the unsafe
/// code *you* write that relies on the behavior of this function may break.
///
/// # Panics
///
/// * Panics if the requested capacity exceeds `usize::MAX` bytes.
/// * Panics on 32-bit platforms if the requested capacity exceeds
/// `isize::MAX` bytes.
///
/// # Aborts
///
/// Aborts on OOM
/// The same as `reserve_exact`, but returns on errors instead of panicking or aborting.
pub fn try_reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize)
-> Result<(), CollectionAllocErr> {
@ -441,6 +422,26 @@ impl<T, A: Alloc> RawVec<T, A> {
}
}
/// Ensures that the buffer contains at least enough space to hold
/// `used_cap + needed_extra_cap` elements. If it doesn't already,
/// will reallocate the minimum possible amount of memory necessary.
/// Generally this will be exactly the amount of memory necessary,
/// but in principle the allocator is free to give back more than
/// we asked for.
///
/// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate
/// the requested space. This is not really unsafe, but the unsafe
/// code *you* write that relies on the behavior of this function may break.
///
/// # Panics
///
/// * Panics if the requested capacity exceeds `usize::MAX` bytes.
/// * Panics on 32-bit platforms if the requested capacity exceeds
/// `isize::MAX` bytes.
///
/// # Aborts
///
/// Aborts on OOM
pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) {
match self.try_reserve_exact(used_cap, needed_extra_cap) {
Err(CapacityOverflow) => capacity_overflow(),
@ -463,6 +464,42 @@ impl<T, A: Alloc> RawVec<T, A> {
Ok(cmp::max(double_cap, required_cap))
}
/// The same as `reserve`, but returns on errors instead of panicking or aborting.
pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize)
-> Result<(), CollectionAllocErr> {
unsafe {
// NOTE: we don't early branch on ZSTs here because we want this
// to actually catch "asking for more than usize::MAX" in that case.
// If we make it past the first branch then we are guaranteed to
// panic.
// Don't actually need any more capacity.
// Wrapping in case they give a bad `used_cap`
if self.cap().wrapping_sub(used_cap) >= needed_extra_cap {
return Ok(());
}
let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?;
let new_layout = Layout::array::<T>(new_cap).map_err(|_| CapacityOverflow)?;
// FIXME: may crash and burn on over-reserve
alloc_guard(new_layout.size())?;
let res = match self.current_layout() {
Some(layout) => {
debug_assert!(new_layout.align() == layout.align());
self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size())
}
None => self.a.alloc(new_layout),
};
self.ptr = res?.cast().into();
self.cap = new_cap;
Ok(())
}
}
/// Ensures that the buffer contains at least enough space to hold
/// `used_cap + needed_extra_cap` elements. If it doesn't already have
/// enough capacity, will reallocate enough space plus comfortable slack
@ -515,42 +552,6 @@ impl<T, A: Alloc> RawVec<T, A> {
/// # vector.push_all(&[1, 3, 5, 7, 9]);
/// # }
/// ```
pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize)
-> Result<(), CollectionAllocErr> {
unsafe {
// NOTE: we don't early branch on ZSTs here because we want this
// to actually catch "asking for more than usize::MAX" in that case.
// If we make it past the first branch then we are guaranteed to
// panic.
// Don't actually need any more capacity.
// Wrapping in case they give a bad `used_cap`
if self.cap().wrapping_sub(used_cap) >= needed_extra_cap {
return Ok(());
}
let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?;
let new_layout = Layout::array::<T>(new_cap).map_err(|_| CapacityOverflow)?;
// FIXME: may crash and burn on over-reserve
alloc_guard(new_layout.size())?;
let res = match self.current_layout() {
Some(layout) => {
debug_assert!(new_layout.align() == layout.align());
self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size())
}
None => self.a.alloc(new_layout),
};
self.ptr = res?.cast().into();
self.cap = new_cap;
Ok(())
}
}
/// The same as try_reserve, but errors are lowered to a call to oom().
pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) {
match self.try_reserve(used_cap, needed_extra_cap) {
Err(CapacityOverflow) => capacity_overflow(),

View File

@ -10,6 +10,8 @@
//! A dynamically-sized view into a contiguous sequence, `[T]`.
//!
//! *[See also the slice primitive type](../../std/primitive.slice.html).*
//!
//! Slices are a view into a block of memory represented as a pointer and a
//! length.
//!
@ -78,8 +80,6 @@
//! * Further methods that return iterators are [`.split`], [`.splitn`],
//! [`.chunks`], [`.windows`] and more.
//!
//! *[See also the slice primitive type](../../std/primitive.slice.html).*
//!
//! [`Clone`]: ../../std/clone/trait.Clone.html
//! [`Eq`]: ../../std/cmp/trait.Eq.html
//! [`Ord`]: ../../std/cmp/trait.Ord.html

View File

@ -10,6 +10,8 @@
//! Unicode string slices.
//!
//! *[See also the `str` primitive type](../../std/primitive.str.html).*
//!
//! The `&str` type is one of the two main string types, the other being `String`.
//! Unlike its `String` counterpart, its contents are borrowed.
//!
@ -29,8 +31,6 @@
//! ```
//! let hello_world: &'static str = "Hello, world!";
//! ```
//!
//! *[See also the `str` primitive type](../../std/primitive.str.html).*
#![stable(feature = "rust1", since = "1.0.0")]

View File

@ -291,113 +291,379 @@ fn test_replace_pattern() {
assert_eq!(data.replace(|c| c == 'γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ");
}
#[test]
fn test_slice() {
assert_eq!("ab", &"abc"[0..2]);
assert_eq!("bc", &"abc"[1..3]);
assert_eq!("", &"abc"[1..1]);
assert_eq!("\u{65e5}", &"\u{65e5}\u{672c}"[0..3]);
// The current implementation of SliceIndex fails to handle methods
// orthogonally from range types; therefore, it is worth testing
// all of the indexing operations on each input.
mod slice_index {
// Test a slicing operation **that should succeed,**
// testing it on all of the indexing methods.
//
// This is not suitable for testing failure on invalid inputs.
macro_rules! assert_range_eq {
($s:expr, $range:expr, $expected:expr)
=> {
let mut s: String = $s.to_owned();
let mut expected: String = $expected.to_owned();
{
let s: &str = &s;
let expected: &str = &expected;
let data = "ประเทศไทย中华";
assert_eq!("", &data[0..3]);
assert_eq!("", &data[3..6]);
assert_eq!("", &data[3..3]);
assert_eq!("", &data[30..33]);
assert_eq!(&s[$range], expected, "(in assertion for: index)");
assert_eq!(s.get($range), Some(expected), "(in assertion for: get)");
unsafe {
assert_eq!(
s.get_unchecked($range), expected,
"(in assertion for: get_unchecked)",
);
}
}
{
let s: &mut str = &mut s;
let expected: &mut str = &mut expected;
fn a_million_letter_x() -> String {
let mut i = 0;
let mut rs = String::new();
while i < 100000 {
rs.push_str("华华华华华华华华华华");
i += 1;
assert_eq!(
&mut s[$range], expected,
"(in assertion for: index_mut)",
);
assert_eq!(
s.get_mut($range), Some(&mut expected[..]),
"(in assertion for: get_mut)",
);
unsafe {
assert_eq!(
s.get_unchecked_mut($range), expected,
"(in assertion for: get_unchecked_mut)",
);
}
}
}
rs
}
fn half_a_million_letter_x() -> String {
let mut i = 0;
let mut rs = String::new();
while i < 100000 {
rs.push_str("华华华华华");
i += 1;
// Make sure the macro can actually detect bugs,
// because if it can't, then what are we even doing here?
//
// (Be aware this only demonstrates the ability to detect bugs
// in the FIRST method that panics, as the macro is not designed
// to be used in `should_panic`)
#[test]
#[should_panic(expected = "out of bounds")]
fn assert_range_eq_can_fail_by_panic() {
assert_range_eq!("abc", 0..5, "abc");
}
// (Be aware this only demonstrates the ability to detect bugs
// in the FIRST method it calls, as the macro is not designed
// to be used in `should_panic`)
#[test]
#[should_panic(expected = "==")]
fn assert_range_eq_can_fail_by_inequality() {
assert_range_eq!("abc", 0..2, "abc");
}
// Generates test cases for bad index operations.
//
// This generates `should_panic` test cases for Index/IndexMut
// and `None` test cases for get/get_mut.
macro_rules! panic_cases {
($(
in mod $case_name:ident {
data: $data:expr;
// optional:
//
// a similar input for which DATA[input] succeeds, and the corresponding
// output str. This helps validate "critical points" where an input range
// straddles the boundary between valid and invalid.
// (such as the input `len..len`, which is just barely valid)
$(
good: data[$good:expr] == $output:expr;
)*
bad: data[$bad:expr];
message: $expect_msg:expr; // must be a literal
}
)*) => {$(
mod $case_name {
#[test]
fn pass() {
let mut v: String = $data.into();
$( assert_range_eq!(v, $good, $output); )*
{
let v: &str = &v;
assert_eq!(v.get($bad), None, "(in None assertion for get)");
}
{
let v: &mut str = &mut v;
assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)");
}
}
#[test]
#[should_panic(expected = $expect_msg)]
fn index_fail() {
let v: String = $data.into();
let v: &str = &v;
let _v = &v[$bad];
}
#[test]
#[should_panic(expected = $expect_msg)]
fn index_mut_fail() {
let mut v: String = $data.into();
let v: &mut str = &mut v;
let _v = &mut v[$bad];
}
}
)*};
}
#[test]
fn simple_ascii() {
assert_range_eq!("abc", .., "abc");
assert_range_eq!("abc", 0..2, "ab");
assert_range_eq!("abc", 0..=1, "ab");
assert_range_eq!("abc", ..2, "ab");
assert_range_eq!("abc", ..=1, "ab");
assert_range_eq!("abc", 1..3, "bc");
assert_range_eq!("abc", 1..=2, "bc");
assert_range_eq!("abc", 1..1, "");
assert_range_eq!("abc", 1..=0, "");
}
#[test]
fn simple_unicode() {
// 日本
assert_range_eq!("\u{65e5}\u{672c}", .., "\u{65e5}\u{672c}");
assert_range_eq!("\u{65e5}\u{672c}", 0..3, "\u{65e5}");
assert_range_eq!("\u{65e5}\u{672c}", 0..=2, "\u{65e5}");
assert_range_eq!("\u{65e5}\u{672c}", ..3, "\u{65e5}");
assert_range_eq!("\u{65e5}\u{672c}", ..=2, "\u{65e5}");
assert_range_eq!("\u{65e5}\u{672c}", 3..6, "\u{672c}");
assert_range_eq!("\u{65e5}\u{672c}", 3..=5, "\u{672c}");
assert_range_eq!("\u{65e5}\u{672c}", 3.., "\u{672c}");
let data = "ประเทศไทย中华";
assert_range_eq!(data, 0..3, "");
assert_range_eq!(data, 3..6, "");
assert_range_eq!(data, 3..3, "");
assert_range_eq!(data, 30..33, "");
/*0: 中
3:
6: V
7: i
8:
11: t
12:
13: N
14: a
15: m */
let ss = "中华Việt Nam";
assert_range_eq!(ss, 3..6, "");
assert_range_eq!(ss, 6..16, "Việt Nam");
assert_range_eq!(ss, 6..=15, "Việt Nam");
assert_range_eq!(ss, 6.., "Việt Nam");
assert_range_eq!(ss, 0..3, "");
assert_range_eq!(ss, 3..7, "华V");
assert_range_eq!(ss, 3..=6, "华V");
assert_range_eq!(ss, 3..3, "");
assert_range_eq!(ss, 3..=2, "");
}
#[test]
#[cfg(not(target_arch = "asmjs"))] // hits an OOM
fn simple_big() {
fn a_million_letter_x() -> String {
let mut i = 0;
let mut rs = String::new();
while i < 100000 {
rs.push_str("华华华华华华华华华华");
i += 1;
}
rs
}
rs
fn half_a_million_letter_x() -> String {
let mut i = 0;
let mut rs = String::new();
while i < 100000 {
rs.push_str("华华华华华");
i += 1;
}
rs
}
let letters = a_million_letter_x();
assert_range_eq!(letters, 0..3 * 500000, half_a_million_letter_x());
}
let letters = a_million_letter_x();
assert_eq!(half_a_million_letter_x(), &letters[0..3 * 500000]);
}
#[test]
fn test_slice_2() {
let ss = "中华Việt Nam";
assert_eq!("", &ss[3..6]);
assert_eq!("Việt Nam", &ss[6..16]);
assert_eq!("ab", &"abc"[0..2]);
assert_eq!("bc", &"abc"[1..3]);
assert_eq!("", &"abc"[1..1]);
assert_eq!("", &ss[0..3]);
assert_eq!("华V", &ss[3..7]);
assert_eq!("", &ss[3..3]);
/*0: 中
3:
6: V
7: i
8:
11: t
12:
13: N
14: a
15: m */
}
#[test]
#[should_panic]
fn test_slice_fail() {
&"中华Việt Nam"[0..2];
}
#[test]
#[should_panic]
fn test_str_slice_rangetoinclusive_max_panics() {
&"hello"[..=usize::max_value()];
}
#[test]
#[should_panic]
fn test_str_slice_rangeinclusive_max_panics() {
&"hello"[1..=usize::max_value()];
}
#[test]
#[should_panic]
fn test_str_slicemut_rangetoinclusive_max_panics() {
let mut s = "hello".to_owned();
let s: &mut str = &mut s;
&mut s[..=usize::max_value()];
}
#[test]
#[should_panic]
fn test_str_slicemut_rangeinclusive_max_panics() {
let mut s = "hello".to_owned();
let s: &mut str = &mut s;
&mut s[1..=usize::max_value()];
}
#[test]
fn test_str_get_maxinclusive() {
let mut s = "hello".to_owned();
{
let s: &str = &s;
assert_eq!(s.get(..=usize::max_value()), None);
assert_eq!(s.get(1..=usize::max_value()), None);
#[test]
#[should_panic]
fn test_slice_fail() {
&"中华Việt Nam"[0..2];
}
{
let s: &mut str = &mut s;
assert_eq!(s.get(..=usize::max_value()), None);
assert_eq!(s.get(1..=usize::max_value()), None);
panic_cases! {
in mod rangefrom_len {
data: "abcdef";
good: data[6..] == "";
bad: data[7..];
message: "out of bounds";
}
in mod rangeto_len {
data: "abcdef";
good: data[..6] == "abcdef";
bad: data[..7];
message: "out of bounds";
}
in mod rangetoinclusive_len {
data: "abcdef";
good: data[..=5] == "abcdef";
bad: data[..=6];
message: "out of bounds";
}
in mod range_len_len {
data: "abcdef";
good: data[6..6] == "";
bad: data[7..7];
message: "out of bounds";
}
in mod rangeinclusive_len_len {
data: "abcdef";
good: data[6..=5] == "";
bad: data[7..=6];
message: "out of bounds";
}
}
panic_cases! {
in mod range_neg_width {
data: "abcdef";
good: data[4..4] == "";
bad: data[4..3];
message: "begin <= end (4 <= 3)";
}
in mod rangeinclusive_neg_width {
data: "abcdef";
good: data[4..=3] == "";
bad: data[4..=2];
message: "begin <= end (4 <= 3)";
}
}
mod overflow {
panic_cases! {
in mod rangeinclusive {
data: "hello";
// note: using 0 specifically ensures that the result of overflowing is 0..0,
// so that `get` doesn't simply return None for the wrong reason.
bad: data[0..=usize::max_value()];
message: "maximum usize";
}
in mod rangetoinclusive {
data: "hello";
bad: data[..=usize::max_value()];
message: "maximum usize";
}
}
}
mod boundary {
const DATA: &'static str = "abcαβγ";
const BAD_START: usize = 4;
const GOOD_START: usize = 3;
const BAD_END: usize = 6;
const GOOD_END: usize = 7;
const BAD_END_INCL: usize = BAD_END - 1;
const GOOD_END_INCL: usize = GOOD_END - 1;
// it is especially important to test all of the different range types here
// because some of the logic may be duplicated as part of micro-optimizations
// to dodge unicode boundary checks on half-ranges.
panic_cases! {
in mod range_1 {
data: super::DATA;
bad: data[super::BAD_START..super::GOOD_END];
message:
"byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
}
in mod range_2 {
data: super::DATA;
bad: data[super::GOOD_START..super::BAD_END];
message:
"byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
}
in mod rangefrom {
data: super::DATA;
bad: data[super::BAD_START..];
message:
"byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
}
in mod rangeto {
data: super::DATA;
bad: data[..super::BAD_END];
message:
"byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
}
in mod rangeinclusive_1 {
data: super::DATA;
bad: data[super::BAD_START..=super::GOOD_END_INCL];
message:
"byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
}
in mod rangeinclusive_2 {
data: super::DATA;
bad: data[super::GOOD_START..=super::BAD_END_INCL];
message:
"byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
}
in mod rangetoinclusive {
data: super::DATA;
bad: data[..=super::BAD_END_INCL];
message:
"byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
}
}
}
const LOREM_PARAGRAPH: &'static str = "\
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem \
sit amet dolor ultricies condimentum. Praesent iaculis purus elit, ac malesuada \
quam malesuada in. Duis sed orci eros. Suspendisse sit amet magna mollis, mollis \
nunc luctus, imperdiet mi. Integer fringilla non sem ut lacinia. Fusce varius \
tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec tempus vel, \
gravida nec quam.";
// check the panic includes the prefix of the sliced string
#[test]
#[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")]
fn test_slice_fail_truncated_1() {
&LOREM_PARAGRAPH[..1024];
}
// check the truncation in the panic message
#[test]
#[should_panic(expected="luctus, im`[...]")]
fn test_slice_fail_truncated_2() {
&LOREM_PARAGRAPH[..1024];
}
}
@ -446,50 +712,6 @@ fn test_is_char_boundary() {
}
}
}
const LOREM_PARAGRAPH: &'static str = "\
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \
ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \
eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \
sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \
tempus vel, gravida nec quam.";
// check the panic includes the prefix of the sliced string
#[test]
#[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")]
fn test_slice_fail_truncated_1() {
&LOREM_PARAGRAPH[..1024];
}
// check the truncation in the panic message
#[test]
#[should_panic(expected="luctus, im`[...]")]
fn test_slice_fail_truncated_2() {
&LOREM_PARAGRAPH[..1024];
}
#[test]
#[should_panic(expected="byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of")]
fn test_slice_fail_boundary_1() {
&"abcαβγ"[4..];
}
#[test]
#[should_panic(expected="byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of")]
fn test_slice_fail_boundary_2() {
&"abcαβγ"[2..6];
}
#[test]
fn test_slice_from() {
assert_eq!(&"abcd"[0..], "abcd");
assert_eq!(&"abcd"[2..], "cd");
assert_eq!(&"abcd"[4..], "");
}
#[test]
fn test_slice_to() {
assert_eq!(&"abcd"[..0], "");
assert_eq!(&"abcd"[..2], "ab");
assert_eq!(&"abcd"[..4], "abcd");
}
#[test]
fn test_trim_left_matches() {

View File

@ -2533,9 +2533,11 @@ impl<'a, T> Drop for Drain<'a, T> {
// memmove back untouched tail, update to new length
let start = source_vec.len();
let tail = self.tail_start;
let src = source_vec.as_ptr().offset(tail as isize);
let dst = source_vec.as_mut_ptr().offset(start as isize);
ptr::copy(src, dst, self.tail_len);
if tail != start {
let src = source_vec.as_ptr().offset(tail as isize);
let dst = source_vec.as_mut_ptr().offset(start as isize);
ptr::copy(src, dst, self.tail_len);
}
source_vec.set_len(start + self.tail_len);
}
}

View File

@ -11,9 +11,9 @@
//! This module provides constants which are specific to the implementation
//! of the `f32` floating point data type.
//!
//! Mathematically significant numbers are provided in the `consts` sub-module.
//!
//! *[See also the `f32` primitive type](../../std/primitive.f32.html).*
//!
//! Mathematically significant numbers are provided in the `consts` sub-module.
#![stable(feature = "rust1", since = "1.0.0")]

View File

@ -11,9 +11,9 @@
//! This module provides constants which are specific to the implementation
//! of the `f64` floating point data type.
//!
//! Mathematically significant numbers are provided in the `consts` sub-module.
//!
//! *[See also the `f64` primitive type](../../std/primitive.f64.html).*
//!
//! Mathematically significant numbers are provided in the `consts` sub-module.
#![stable(feature = "rust1", since = "1.0.0")]

View File

@ -411,6 +411,21 @@ impl<Idx> RangeInclusive<Idx> {
pub fn end(&self) -> &Idx {
&self.end
}
/// Destructures the RangeInclusive into (lower bound, upper (inclusive) bound).
///
/// # Examples
///
/// ```
/// #![feature(inclusive_range_methods)]
///
/// assert_eq!((3..=5).into_inner(), (3, 5));
/// ```
#[unstable(feature = "inclusive_range_methods", issue = "49022")]
#[inline]
pub fn into_inner(self) -> (Idx, Idx) {
(self.start, self.end)
}
}
#[stable(feature = "inclusive_range", since = "1.26.0")]

View File

@ -2262,6 +2262,12 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! {
panic!("slice index starts at {} but ends at {}", index, end);
}
#[inline(never)]
#[cold]
fn slice_index_overflow_fail() -> ! {
panic!("attempted to index slice up to maximum usize");
}
/// A helper trait used for indexing operations.
#[unstable(feature = "slice_get_slice", issue = "35729")]
#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"]
@ -2538,15 +2544,13 @@ impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
#[inline]
fn index(self, slice: &[T]) -> &[T] {
assert!(self.end != usize::max_value(),
"attempted to index slice up to maximum usize");
if self.end == usize::max_value() { slice_index_overflow_fail(); }
(self.start..self.end + 1).index(slice)
}
#[inline]
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
assert!(self.end != usize::max_value(),
"attempted to index slice up to maximum usize");
if self.end == usize::max_value() { slice_index_overflow_fail(); }
(self.start..self.end + 1).index_mut(slice)
}
}

View File

@ -1849,6 +1849,12 @@ mod traits {
}
}
#[inline(never)]
#[cold]
fn str_index_overflow_fail() -> ! {
panic!("attempted to index str up to maximum usize");
}
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
impl SliceIndex<str> for ops::RangeFull {
type Output = str;
@ -2029,19 +2035,13 @@ mod traits {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
if let Some(end) = self.end.checked_add(1) {
(self.start..end).get(slice)
} else {
None
}
if self.end == usize::max_value() { None }
else { (self.start..self.end+1).get(slice) }
}
#[inline]
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
if let Some(end) = self.end.checked_add(1) {
(self.start..end).get_mut(slice)
} else {
None
}
if self.end == usize::max_value() { None }
else { (self.start..self.end+1).get_mut(slice) }
}
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
@ -2053,14 +2053,12 @@ mod traits {
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
assert!(self.end != usize::max_value(),
"attempted to index str up to maximum usize");
if self.end == usize::max_value() { str_index_overflow_fail(); }
(self.start..self.end+1).index(slice)
}
#[inline]
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
assert!(self.end != usize::max_value(),
"attempted to index str up to maximum usize");
if self.end == usize::max_value() { str_index_overflow_fail(); }
(self.start..self.end+1).index_mut(slice)
}
}
@ -2072,40 +2070,30 @@ mod traits {
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) {
Some(unsafe { self.get_unchecked(slice) })
} else {
None
}
if self.end == usize::max_value() { None }
else { (..self.end+1).get(slice) }
}
#[inline]
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) {
Some(unsafe { self.get_unchecked_mut(slice) })
} else {
None
}
if self.end == usize::max_value() { None }
else { (..self.end+1).get_mut(slice) }
}
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
let ptr = slice.as_ptr();
super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end + 1))
(..self.end+1).get_unchecked(slice)
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
let ptr = slice.as_ptr();
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1))
(..self.end+1).get_unchecked_mut(slice)
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
assert!(self.end != usize::max_value(),
"attempted to index str up to maximum usize");
if self.end == usize::max_value() { str_index_overflow_fail(); }
(..self.end+1).index(slice)
}
#[inline]
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
assert!(self.end != usize::max_value(),
"attempted to index str up to maximum usize");
if self.end == usize::max_value() { str_index_overflow_fail(); }
(..self.end+1).index_mut(slice)
}
}

View File

@ -376,48 +376,224 @@ fn test_windows_zip() {
assert_eq!(res, [14, 18, 22, 26]);
}
#[test]
fn get_range() {
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
assert_eq!(v.get(..), Some(&[0, 1, 2, 3, 4, 5][..]));
assert_eq!(v.get(..2), Some(&[0, 1][..]));
assert_eq!(v.get(2..), Some(&[2, 3, 4, 5][..]));
assert_eq!(v.get(1..4), Some(&[1, 2, 3][..]));
assert_eq!(v.get(7..), None);
assert_eq!(v.get(7..10), None);
}
// The current implementation of SliceIndex fails to handle methods
// orthogonally from range types; therefore, it is worth testing
// all of the indexing operations on each input.
mod slice_index {
// This checks all six indexing methods, given an input range that
// should succeed. (it is NOT suitable for testing invalid inputs)
macro_rules! assert_range_eq {
($arr:expr, $range:expr, $expected:expr)
=> {
let mut arr = $arr;
let mut expected = $expected;
{
let s: &[_] = &arr;
let expected: &[_] = &expected;
#[test]
fn get_mut_range() {
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
assert_eq!(v.get_mut(..), Some(&mut [0, 1, 2, 3, 4, 5][..]));
assert_eq!(v.get_mut(..2), Some(&mut [0, 1][..]));
assert_eq!(v.get_mut(2..), Some(&mut [2, 3, 4, 5][..]));
assert_eq!(v.get_mut(1..4), Some(&mut [1, 2, 3][..]));
assert_eq!(v.get_mut(7..), None);
assert_eq!(v.get_mut(7..10), None);
}
assert_eq!(&s[$range], expected, "(in assertion for: index)");
assert_eq!(s.get($range), Some(expected), "(in assertion for: get)");
unsafe {
assert_eq!(
s.get_unchecked($range), expected,
"(in assertion for: get_unchecked)",
);
}
}
{
let s: &mut [_] = &mut arr;
let expected: &mut [_] = &mut expected;
#[test]
fn get_unchecked_range() {
unsafe {
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
assert_eq!(v.get_unchecked(..), &[0, 1, 2, 3, 4, 5][..]);
assert_eq!(v.get_unchecked(..2), &[0, 1][..]);
assert_eq!(v.get_unchecked(2..), &[2, 3, 4, 5][..]);
assert_eq!(v.get_unchecked(1..4), &[1, 2, 3][..]);
assert_eq!(
&mut s[$range], expected,
"(in assertion for: index_mut)",
);
assert_eq!(
s.get_mut($range), Some(&mut expected[..]),
"(in assertion for: get_mut)",
);
unsafe {
assert_eq!(
s.get_unchecked_mut($range), expected,
"(in assertion for: get_unchecked_mut)",
);
}
}
}
}
}
#[test]
fn get_unchecked_mut_range() {
unsafe {
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
assert_eq!(v.get_unchecked_mut(..), &mut [0, 1, 2, 3, 4, 5][..]);
assert_eq!(v.get_unchecked_mut(..2), &mut [0, 1][..]);
assert_eq!(v.get_unchecked_mut(2..), &mut[2, 3, 4, 5][..]);
assert_eq!(v.get_unchecked_mut(1..4), &mut [1, 2, 3][..]);
// Make sure the macro can actually detect bugs,
// because if it can't, then what are we even doing here?
//
// (Be aware this only demonstrates the ability to detect bugs
// in the FIRST method that panics, as the macro is not designed
// to be used in `should_panic`)
#[test]
#[should_panic(expected = "out of range")]
fn assert_range_eq_can_fail_by_panic() {
assert_range_eq!([0, 1, 2], 0..5, [0, 1, 2]);
}
// (Be aware this only demonstrates the ability to detect bugs
// in the FIRST method it calls, as the macro is not designed
// to be used in `should_panic`)
#[test]
#[should_panic(expected = "==")]
fn assert_range_eq_can_fail_by_inequality() {
assert_range_eq!([0, 1, 2], 0..2, [0, 1, 2]);
}
// Test cases for bad index operations.
//
// This generates `should_panic` test cases for Index/IndexMut
// and `None` test cases for get/get_mut.
macro_rules! panic_cases {
($(
// each test case needs a unique name to namespace the tests
in mod $case_name:ident {
data: $data:expr;
// optional:
//
// one or more similar inputs for which data[input] succeeds,
// and the corresponding output as an array. This helps validate
// "critical points" where an input range straddles the boundary
// between valid and invalid.
// (such as the input `len..len`, which is just barely valid)
$(
good: data[$good:expr] == $output:expr;
)*
bad: data[$bad:expr];
message: $expect_msg:expr;
}
)*) => {$(
mod $case_name {
#[test]
fn pass() {
let mut v = $data;
$( assert_range_eq!($data, $good, $output); )*
{
let v: &[_] = &v;
assert_eq!(v.get($bad), None, "(in None assertion for get)");
}
{
let v: &mut [_] = &mut v;
assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)");
}
}
#[test]
#[should_panic(expected = $expect_msg)]
fn index_fail() {
let v = $data;
let v: &[_] = &v;
let _v = &v[$bad];
}
#[test]
#[should_panic(expected = $expect_msg)]
fn index_mut_fail() {
let mut v = $data;
let v: &mut [_] = &mut v;
let _v = &mut v[$bad];
}
}
)*};
}
#[test]
fn simple() {
let v = [0, 1, 2, 3, 4, 5];
assert_range_eq!(v, .., [0, 1, 2, 3, 4, 5]);
assert_range_eq!(v, ..2, [0, 1]);
assert_range_eq!(v, ..=1, [0, 1]);
assert_range_eq!(v, 2.., [2, 3, 4, 5]);
assert_range_eq!(v, 1..4, [1, 2, 3]);
assert_range_eq!(v, 1..=3, [1, 2, 3]);
}
panic_cases! {
in mod rangefrom_len {
data: [0, 1, 2, 3, 4, 5];
good: data[6..] == [];
bad: data[7..];
message: "but ends at"; // perhaps not ideal
}
in mod rangeto_len {
data: [0, 1, 2, 3, 4, 5];
good: data[..6] == [0, 1, 2, 3, 4, 5];
bad: data[..7];
message: "out of range";
}
in mod rangetoinclusive_len {
data: [0, 1, 2, 3, 4, 5];
good: data[..=5] == [0, 1, 2, 3, 4, 5];
bad: data[..=6];
message: "out of range";
}
in mod range_len_len {
data: [0, 1, 2, 3, 4, 5];
good: data[6..6] == [];
bad: data[7..7];
message: "out of range";
}
in mod rangeinclusive_len_len {
data: [0, 1, 2, 3, 4, 5];
good: data[6..=5] == [];
bad: data[7..=6];
message: "out of range";
}
}
panic_cases! {
in mod range_neg_width {
data: [0, 1, 2, 3, 4, 5];
good: data[4..4] == [];
bad: data[4..3];
message: "but ends at";
}
in mod rangeinclusive_neg_width {
data: [0, 1, 2, 3, 4, 5];
good: data[4..=3] == [];
bad: data[4..=2];
message: "but ends at";
}
}
panic_cases! {
in mod rangeinclusive_overflow {
data: [0, 1];
// note: using 0 specifically ensures that the result of overflowing is 0..0,
// so that `get` doesn't simply return None for the wrong reason.
bad: data[0 ..= ::std::usize::MAX];
message: "maximum usize";
}
in mod rangetoinclusive_overflow {
data: [0, 1];
bad: data[..= ::std::usize::MAX];
message: "maximum usize";
}
} // panic_cases!
}
#[test]

View File

@ -8,4 +8,4 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// All `str` tests live in collectionstests::str
// All `str` tests live in liballoc/tests

View File

@ -12,6 +12,7 @@ use errors::DiagnosticBuilder;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::small_vec::SmallVec;
use rustc_data_structures::sync::{Lrc, RwLock, ReadGuard, Lock};
use std::env;
use std::hash::Hash;
@ -77,7 +78,7 @@ struct DepGraphData {
/// things available to us. If we find that they are not dirty, we
/// load the path to the file storing those work-products here into
/// this map. We can later look for and extract that data.
previous_work_products: RwLock<FxHashMap<WorkProductId, WorkProduct>>,
previous_work_products: FxHashMap<WorkProductId, WorkProduct>,
/// Work-products that we generate in this run.
work_products: RwLock<FxHashMap<WorkProductId, WorkProduct>>,
@ -90,7 +91,8 @@ struct DepGraphData {
impl DepGraph {
pub fn new(prev_graph: PreviousDepGraph) -> DepGraph {
pub fn new(prev_graph: PreviousDepGraph,
prev_work_products: FxHashMap<WorkProductId, WorkProduct>) -> DepGraph {
// Pre-allocate the fingerprints array. We over-allocate a little so
// that we hopefully don't have to re-allocate during this compilation
// session.
@ -100,7 +102,7 @@ impl DepGraph {
(prev_graph_node_count * 115) / 100);
DepGraph {
data: Some(Lrc::new(DepGraphData {
previous_work_products: RwLock::new(FxHashMap()),
previous_work_products: prev_work_products,
work_products: RwLock::new(FxHashMap()),
dep_node_debug: Lock::new(FxHashMap()),
current: Lock::new(CurrentDepGraph::new()),
@ -131,7 +133,7 @@ impl DepGraph {
let mut edges = Vec::new();
for (index, edge_targets) in current_dep_graph.edges.iter_enumerated() {
let from = current_dep_graph.nodes[index];
for &edge_target in edge_targets {
for &edge_target in edge_targets.iter() {
let to = current_dep_graph.nodes[edge_target];
edges.push((from, to));
}
@ -209,7 +211,7 @@ impl DepGraph {
self.with_task_impl(key, cx, arg, false, task,
|key| OpenTask::Regular(Lock::new(RegularOpenTask {
node: key,
reads: Vec::new(),
reads: SmallVec::new(),
read_set: FxHashSet(),
})),
|data, key, task| data.borrow_mut().complete_task(key, task))
@ -230,7 +232,7 @@ impl DepGraph {
self.with_task_impl(key, cx, input, true, identity_fn,
|_| OpenTask::Ignore,
|data, key, _| data.borrow_mut().alloc_node(key, Vec::new()))
|data, key, _| data.borrow_mut().alloc_node(key, SmallVec::new()))
}
fn with_task_impl<'gcx, C, A, R>(
@ -353,7 +355,7 @@ impl DepGraph {
if let Some(ref data) = self.data {
let (result, open_task) = ty::tls::with_context(|icx| {
let task = OpenTask::Anon(Lock::new(AnonOpenTask {
reads: Vec::new(),
reads: SmallVec::new(),
read_set: FxHashSet(),
}));
@ -460,19 +462,6 @@ impl DepGraph {
self.data.as_ref().unwrap().previous.node_to_index(dep_node)
}
/// Indicates that a previous work product exists for `v`. This is
/// invoked during initial start-up based on what nodes are clean
/// (and what files exist in the incr. directory).
pub fn insert_previous_work_product(&self, v: &WorkProductId, data: WorkProduct) {
debug!("insert_previous_work_product({:?}, {:?})", v, data);
self.data
.as_ref()
.unwrap()
.previous_work_products
.borrow_mut()
.insert(v.clone(), data);
}
/// Indicates that we created the given work-product in this run
/// for `v`. This record will be preserved and loaded in the next
/// run.
@ -492,7 +481,7 @@ impl DepGraph {
self.data
.as_ref()
.and_then(|data| {
data.previous_work_products.borrow().get(v).cloned()
data.previous_work_products.get(v).cloned()
})
}
@ -504,8 +493,8 @@ impl DepGraph {
/// Access the map of work-products created during the cached run. Only
/// used during saving of the dep-graph.
pub fn previous_work_products(&self) -> ReadGuard<FxHashMap<WorkProductId, WorkProduct>> {
self.data.as_ref().unwrap().previous_work_products.borrow()
pub fn previous_work_products(&self) -> &FxHashMap<WorkProductId, WorkProduct> {
&self.data.as_ref().unwrap().previous_work_products
}
#[inline(always)]
@ -534,15 +523,9 @@ impl DepGraph {
}
pub fn serialize(&self) -> SerializedDepGraph {
let mut fingerprints = self.fingerprints.borrow_mut();
let current_dep_graph = self.data.as_ref().unwrap().current.borrow();
// Make sure we don't run out of bounds below.
if current_dep_graph.nodes.len() > fingerprints.len() {
fingerprints.resize(current_dep_graph.nodes.len(), Fingerprint::ZERO);
}
let fingerprints = fingerprints.clone().convert_index_type();
let fingerprints = self.fingerprints.borrow().clone().convert_index_type();
let nodes = current_dep_graph.nodes.clone().convert_index_type();
let total_edge_count: usize = current_dep_graph.edges.iter()
@ -626,7 +609,7 @@ impl DepGraph {
debug_assert!(data.colors.borrow().get(prev_dep_node_index).is_none());
let mut current_deps = Vec::new();
let mut current_deps = SmallVec::new();
for &dep_dep_node_index in prev_deps {
let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index);
@ -923,7 +906,7 @@ pub enum WorkProductFileKind {
pub(super) struct CurrentDepGraph {
nodes: IndexVec<DepNodeIndex, DepNode>,
edges: IndexVec<DepNodeIndex, Vec<DepNodeIndex>>,
edges: IndexVec<DepNodeIndex, SmallVec<[DepNodeIndex; 8]>>,
node_to_node_index: FxHashMap<DepNode, DepNodeIndex>,
forbidden_edge: Option<EdgeFilter>,
@ -1061,7 +1044,7 @@ impl CurrentDepGraph {
} = task {
debug_assert_eq!(node, key);
let krate_idx = self.node_to_node_index[&DepNode::new_no_params(DepKind::Krate)];
self.alloc_node(node, vec![krate_idx])
self.alloc_node(node, SmallVec::one(krate_idx))
} else {
bug!("complete_eval_always_task() - Expected eval always task to be popped");
}
@ -1107,7 +1090,7 @@ impl CurrentDepGraph {
fn alloc_node(&mut self,
dep_node: DepNode,
edges: Vec<DepNodeIndex>)
edges: SmallVec<[DepNodeIndex; 8]>)
-> DepNodeIndex {
debug_assert_eq!(self.edges.len(), self.nodes.len());
debug_assert_eq!(self.node_to_node_index.len(), self.nodes.len());
@ -1122,12 +1105,12 @@ impl CurrentDepGraph {
pub struct RegularOpenTask {
node: DepNode,
reads: Vec<DepNodeIndex>,
reads: SmallVec<[DepNodeIndex; 8]>,
read_set: FxHashSet<DepNodeIndex>,
}
pub struct AnonOpenTask {
reads: Vec<DepNodeIndex>,
reads: SmallVec<[DepNodeIndex; 8]>,
read_set: FxHashSet<DepNodeIndex>,
}

View File

@ -95,6 +95,23 @@ pub enum Lto {
Fat,
}
#[derive(Clone, PartialEq, Hash)]
pub enum CrossLangLto {
LinkerPlugin(PathBuf),
NoLink,
Disabled
}
impl CrossLangLto {
pub fn embed_bitcode(&self) -> bool {
match *self {
CrossLangLto::LinkerPlugin(_) |
CrossLangLto::NoLink => true,
CrossLangLto::Disabled => false,
}
}
}
#[derive(Clone, Copy, PartialEq, Hash)]
pub enum DebugInfoLevel {
NoDebugInfo,
@ -412,6 +429,7 @@ top_level_options!(
// Remap source path prefixes in all output (messages, object files, debug, etc)
remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
edition: Edition [TRACKED],
}
);
@ -777,11 +795,15 @@ macro_rules! options {
Some("`string` or `string=string`");
pub const parse_lto: Option<&'static str> =
Some("one of `thin`, `fat`, or omitted");
pub const parse_cross_lang_lto: Option<&'static str> =
Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `no-link`, \
or the path to the linker plugin");
}
#[allow(dead_code)]
mod $mod_set {
use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto};
use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto,
CrossLangLto};
use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
use std::path::PathBuf;
@ -986,6 +1008,26 @@ macro_rules! options {
true
}
fn parse_cross_lang_lto(slot: &mut CrossLangLto, v: Option<&str>) -> bool {
if v.is_some() {
let mut bool_arg = None;
if parse_opt_bool(&mut bool_arg, v) {
*slot = if bool_arg.unwrap() {
CrossLangLto::NoLink
} else {
CrossLangLto::Disabled
};
return true
}
}
*slot = match v {
None |
Some("no-link") => CrossLangLto::NoLink,
Some(path) => CrossLangLto::LinkerPlugin(PathBuf::from(path)),
};
true
}
}
) }
@ -1295,7 +1337,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"make the current crate share its generic instantiations"),
chalk: bool = (false, parse_bool, [TRACKED],
"enable the experimental Chalk-based trait solving engine"),
cross_lang_lto: bool = (false, parse_bool, [TRACKED],
cross_lang_lto: CrossLangLto = (CrossLangLto::Disabled, parse_cross_lang_lto, [TRACKED],
"generate build artifacts that are compatible with linker-based LTO."),
}
@ -2327,7 +2369,7 @@ mod dep_tracking {
use std::path::PathBuf;
use std::collections::hash_map::DefaultHasher;
use super::{CrateType, DebugInfoLevel, ErrorOutputType, Lto, OptLevel, OutputTypes,
Passes, Sanitizer};
Passes, Sanitizer, CrossLangLto};
use syntax::feature_gate::UnstableFeatures;
use rustc_target::spec::{PanicStrategy, RelroLevel, TargetTriple};
use syntax::edition::Edition;
@ -2391,6 +2433,7 @@ mod dep_tracking {
impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
impl_dep_tracking_hash_via_hash!(TargetTriple);
impl_dep_tracking_hash_via_hash!(Edition);
impl_dep_tracking_hash_via_hash!(CrossLangLto);
impl_dep_tracking_hash_for_sortable_vec_of!(String);
impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
@ -2455,7 +2498,7 @@ mod tests {
use lint;
use middle::cstore;
use session::config::{build_configuration, build_session_options_and_crate_config};
use session::config::Lto;
use session::config::{Lto, CrossLangLto};
use session::build_session;
use std::collections::{BTreeMap, BTreeSet};
use std::iter::FromIterator;
@ -3111,6 +3154,10 @@ mod tests {
opts = reference.clone();
opts.debugging_opts.relro_level = Some(RelroLevel::Full);
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
opts = reference.clone();
opts.debugging_opts.cross_lang_lto = CrossLangLto::NoLink;
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
}
#[test]

View File

@ -657,6 +657,13 @@ impl Session {
}
}
pub fn target_cpu(&self) -> &str {
match self.opts.cg.target_cpu {
Some(ref s) => &**s,
None => &*self.target.target.options.cpu
}
}
pub fn must_not_eliminate_frame_pointers(&self) -> bool {
if let Some(x) = self.opts.cg.force_frame_pointers {
x

View File

@ -980,15 +980,16 @@ where
let dep_graph = match future_dep_graph {
None => DepGraph::new_disabled(),
Some(future) => {
let prev_graph = time(sess, "blocked while dep-graph loading finishes", || {
future
.open()
.unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
message: format!("could not decode incremental cache: {:?}", e),
})
.open(sess)
});
DepGraph::new(prev_graph)
let (prev_graph, prev_work_products) =
time(sess, "blocked while dep-graph loading finishes", || {
future
.open()
.unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
message: format!("could not decode incremental cache: {:?}", e),
})
.open(sess)
});
DepGraph::new(prev_graph, prev_work_products)
}
};
let hir_forest = time(sess, "lowering ast -> hir", || {

View File

@ -10,7 +10,8 @@
//! Code to save/load the dep-graph from files.
use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph};
use rustc_data_structures::fx::FxHashMap;
use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc::ty::maps::OnDiskCache;
@ -32,65 +33,22 @@ pub fn dep_graph_tcx_init<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
tcx.allocate_metadata_dep_nodes();
tcx.precompute_in_scope_traits_hashes();
if tcx.sess.incr_comp_session_dir_opt().is_none() {
// If we are only building with -Zquery-dep-graph but without an actual
// incr. comp. session directory, we exit here. Otherwise we'd fail
// when trying to load work products.
return
}
let work_products_path = work_products_path(tcx.sess);
let load_result = load_data(tcx.sess.opts.debugging_opts.incremental_info, &work_products_path);
if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
// Decode the list of work_products
let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos);
let work_products: Vec<SerializedWorkProduct> =
RustcDecodable::decode(&mut work_product_decoder).unwrap_or_else(|e| {
let msg = format!("Error decoding `work-products` from incremental \
compilation session directory: {}", e);
tcx.sess.fatal(&msg[..])
});
for swp in work_products {
let mut all_files_exist = true;
for &(_, ref file_name) in swp.work_product.saved_files.iter() {
let path = in_incr_comp_dir_sess(tcx.sess, file_name);
if !path.exists() {
all_files_exist = false;
if tcx.sess.opts.debugging_opts.incremental_info {
eprintln!("incremental: could not find file for work \
product: {}", path.display());
}
}
}
if all_files_exist {
debug!("reconcile_work_products: all files for {:?} exist", swp);
tcx.dep_graph.insert_previous_work_product(&swp.id, swp.work_product);
} else {
debug!("reconcile_work_products: some file for {:?} does not exist", swp);
delete_dirty_work_product(tcx, swp);
}
}
}
}
type WorkProductMap = FxHashMap<WorkProductId, WorkProduct>;
pub enum LoadResult<T> {
Ok { data: T },
DataOutOfDate,
Error { message: String },
}
impl LoadResult<PreviousDepGraph> {
pub fn open(self, sess: &Session) -> PreviousDepGraph {
impl LoadResult<(PreviousDepGraph, WorkProductMap)> {
pub fn open(self, sess: &Session) -> (PreviousDepGraph, WorkProductMap) {
match self {
LoadResult::Error { message } => {
sess.warn(&message);
PreviousDepGraph::new(SerializedDepGraph::new())
(PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
},
LoadResult::DataOutOfDate => {
if let Err(err) = delete_all_session_dir_contents(sess) {
@ -98,7 +56,7 @@ impl LoadResult<PreviousDepGraph> {
incremental compilation session directory contents `{}`: {}.",
dep_graph_path(sess).display(), err));
}
PreviousDepGraph::new(SerializedDepGraph::new())
(PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
}
LoadResult::Ok { data } => data
}
@ -125,10 +83,10 @@ fn load_data(report_incremental_info: bool, path: &Path) -> LoadResult<(Vec<u8>,
}
}
fn delete_dirty_work_product(tcx: TyCtxt,
fn delete_dirty_work_product(sess: &Session,
swp: SerializedWorkProduct) {
debug!("delete_dirty_work_product({:?})", swp);
work_product::delete_workproduct_files(tcx.sess, &swp.work_product);
work_product::delete_workproduct_files(sess, &swp.work_product);
}
/// Either a result that has already be computed or a
@ -149,7 +107,7 @@ impl<T> MaybeAsync<T> {
/// Launch a thread and load the dependency graph in the background.
pub fn load_dep_graph(sess: &Session) ->
MaybeAsync<LoadResult<PreviousDepGraph>>
MaybeAsync<LoadResult<(PreviousDepGraph, WorkProductMap)>>
{
// Since `sess` isn't `Sync`, we perform all accesses to `sess`
// before we fire the background thread.
@ -159,7 +117,7 @@ pub fn load_dep_graph(sess: &Session) ->
if sess.opts.incremental.is_none() {
// No incremental compilation.
return MaybeAsync::Sync(LoadResult::Ok {
data: PreviousDepGraph::new(SerializedDepGraph::new())
data: (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
});
}
@ -169,6 +127,50 @@ pub fn load_dep_graph(sess: &Session) ->
let report_incremental_info = sess.opts.debugging_opts.incremental_info;
let expected_hash = sess.opts.dep_tracking_hash();
let mut prev_work_products = FxHashMap();
// If we are only building with -Zquery-dep-graph but without an actual
// incr. comp. session directory, we skip this. Otherwise we'd fail
// when trying to load work products.
if sess.incr_comp_session_dir_opt().is_some() {
let work_products_path = work_products_path(sess);
let load_result = load_data(report_incremental_info, &work_products_path);
if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
// Decode the list of work_products
let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos);
let work_products: Vec<SerializedWorkProduct> =
RustcDecodable::decode(&mut work_product_decoder).unwrap_or_else(|e| {
let msg = format!("Error decoding `work-products` from incremental \
compilation session directory: {}", e);
sess.fatal(&msg[..])
});
for swp in work_products {
let mut all_files_exist = true;
for &(_, ref file_name) in swp.work_product.saved_files.iter() {
let path = in_incr_comp_dir_sess(sess, file_name);
if !path.exists() {
all_files_exist = false;
if sess.opts.debugging_opts.incremental_info {
eprintln!("incremental: could not find file for work \
product: {}", path.display());
}
}
}
if all_files_exist {
debug!("reconcile_work_products: all files for {:?} exist", swp);
prev_work_products.insert(swp.id, swp.work_product);
} else {
debug!("reconcile_work_products: some file for {:?} does not exist", swp);
delete_dirty_work_product(sess, swp);
}
}
}
}
MaybeAsync::Async(std::thread::spawn(move || {
time_ext(time_passes, None, "background load prev dep-graph", move || {
match load_data(report_incremental_info, &path) {
@ -195,7 +197,7 @@ pub fn load_dep_graph(sess: &Session) ->
let dep_graph = SerializedDepGraph::decode(&mut decoder)
.expect("Error reading cached dep-graph");
LoadResult::Ok { data: PreviousDepGraph::new(dep_graph) }
LoadResult::Ok { data: (PreviousDepGraph::new(dep_graph), prev_work_products) }
}
}
})

View File

@ -51,7 +51,6 @@ pub struct Library {
pub struct CrateLoader<'a> {
pub sess: &'a Session,
cstore: &'a CStore,
next_crate_num: CrateNum,
local_crate_name: Symbol,
}
@ -102,7 +101,6 @@ impl<'a> CrateLoader<'a> {
CrateLoader {
sess,
cstore,
next_crate_num: cstore.next_crate_num(),
local_crate_name: Symbol::intern(local_crate_name),
}
}
@ -198,8 +196,7 @@ impl<'a> CrateLoader<'a> {
self.verify_no_symbol_conflicts(span, &crate_root);
// Claim this crate number and cache it
let cnum = self.next_crate_num;
self.next_crate_num = CrateNum::from_u32(cnum.as_u32() + 1);
let cnum = self.cstore.alloc_new_crate_num();
// Stash paths for top-most crate locally if necessary.
let crate_paths = if root.is_none() {
@ -219,6 +216,8 @@ impl<'a> CrateLoader<'a> {
let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
let dependencies: Vec<CrateNum> = cnum_map.iter().cloned().collect();
let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
crate_root.def_path_table.decode((&metadata, self.sess))
});
@ -239,8 +238,9 @@ impl<'a> CrateLoader<'a> {
}),
root: crate_root,
blob: metadata,
cnum_map: Lock::new(cnum_map),
cnum_map,
cnum,
dependencies: Lock::new(dependencies),
codemap_import_info: RwLock::new(vec![]),
attribute_cache: Lock::new([Vec::new(), Vec::new()]),
dep_kind: Lock::new(dep_kind),
@ -392,7 +392,7 @@ impl<'a> CrateLoader<'a> {
// Propagate the extern crate info to dependencies.
extern_crate.direct = false;
for &dep_cnum in cmeta.cnum_map.borrow().iter() {
for &dep_cnum in cmeta.dependencies.borrow().iter() {
self.update_extern_crate(dep_cnum, extern_crate, visited);
}
}
@ -1040,7 +1040,7 @@ impl<'a> CrateLoader<'a> {
}
info!("injecting a dep from {} to {}", cnum, krate);
data.cnum_map.borrow_mut().push(krate);
data.dependencies.borrow_mut().push(krate);
});
}
}

View File

@ -64,8 +64,9 @@ pub struct CrateMetadata {
pub extern_crate: Lock<Option<ExternCrate>>,
pub blob: MetadataBlob,
pub cnum_map: Lock<CrateNumMap>,
pub cnum_map: CrateNumMap,
pub cnum: CrateNum,
pub dependencies: Lock<Vec<CrateNum>>,
pub codemap_import_info: RwLock<Vec<ImportedFileMap>>,
pub attribute_cache: Lock<[Vec<Option<Lrc<[ast::Attribute]>>>; 2]>,
@ -96,32 +97,34 @@ pub struct CStore {
impl CStore {
pub fn new(metadata_loader: Box<MetadataLoader + Sync>) -> CStore {
CStore {
metas: RwLock::new(IndexVec::new()),
// We add an empty entry for LOCAL_CRATE (which maps to zero) in
// order to make array indices in `metas` match with the
// corresponding `CrateNum`. This first entry will always remain
// `None`.
metas: RwLock::new(IndexVec::from_elem_n(None, 1)),
extern_mod_crate_map: Lock::new(FxHashMap()),
metadata_loader,
}
}
/// You cannot use this function to allocate a CrateNum in a thread-safe manner.
/// It is currently only used in CrateLoader which is single-threaded code.
pub fn next_crate_num(&self) -> CrateNum {
CrateNum::new(self.metas.borrow().len() + 1)
pub(super) fn alloc_new_crate_num(&self) -> CrateNum {
let mut metas = self.metas.borrow_mut();
let cnum = CrateNum::new(metas.len());
metas.push(None);
cnum
}
pub fn get_crate_data(&self, cnum: CrateNum) -> Lrc<CrateMetadata> {
pub(super) fn get_crate_data(&self, cnum: CrateNum) -> Lrc<CrateMetadata> {
self.metas.borrow()[cnum].clone().unwrap()
}
pub fn set_crate_data(&self, cnum: CrateNum, data: Lrc<CrateMetadata>) {
use rustc_data_structures::indexed_vec::Idx;
let mut met = self.metas.borrow_mut();
while met.len() <= cnum.index() {
met.push(None);
}
met[cnum] = Some(data);
pub(super) fn set_crate_data(&self, cnum: CrateNum, data: Lrc<CrateMetadata>) {
let mut metas = self.metas.borrow_mut();
assert!(metas[cnum].is_none(), "Overwriting crate metadata entry");
metas[cnum] = Some(data);
}
pub fn iter_crate_data<I>(&self, mut i: I)
pub(super) fn iter_crate_data<I>(&self, mut i: I)
where I: FnMut(CrateNum, &Lrc<CrateMetadata>)
{
for (k, v) in self.metas.borrow().iter_enumerated() {
@ -131,20 +134,22 @@ impl CStore {
}
}
pub fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec<CrateNum> {
pub(super) fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec<CrateNum> {
let mut ordering = Vec::new();
self.push_dependencies_in_postorder(&mut ordering, krate);
ordering.reverse();
ordering
}
pub fn push_dependencies_in_postorder(&self, ordering: &mut Vec<CrateNum>, krate: CrateNum) {
pub(super) fn push_dependencies_in_postorder(&self,
ordering: &mut Vec<CrateNum>,
krate: CrateNum) {
if ordering.contains(&krate) {
return;
}
let data = self.get_crate_data(krate);
for &dep in data.cnum_map.borrow().iter() {
for &dep in data.dependencies.borrow().iter() {
if dep != krate {
self.push_dependencies_in_postorder(ordering, dep);
}
@ -153,7 +158,7 @@ impl CStore {
ordering.push(krate);
}
pub fn do_postorder_cnums_untracked(&self) -> Vec<CrateNum> {
pub(super) fn do_postorder_cnums_untracked(&self) -> Vec<CrateNum> {
let mut ordering = Vec::new();
for (num, v) in self.metas.borrow().iter_enumerated() {
if let &Some(_) = v {
@ -163,11 +168,11 @@ impl CStore {
return ordering
}
pub fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) {
pub(super) fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) {
self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
}
pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
pub(super) fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
}
}

View File

@ -246,7 +246,7 @@ impl<'a, 'tcx: 'a> TyDecoder<'a, 'tcx> for DecodeContext<'a, 'tcx> {
if cnum == LOCAL_CRATE {
self.cdata().cnum
} else {
self.cdata().cnum_map.borrow()[cnum]
self.cdata().cnum_map[cnum]
}
}
}
@ -932,7 +932,7 @@ impl<'a, 'tcx> CrateMetadata {
// Translate a DefId from the current compilation environment to a DefId
// for an external crate.
fn reverse_translate_def_id(&self, did: DefId) -> Option<DefId> {
for (local, &global) in self.cnum_map.borrow().iter_enumerated() {
for (local, &global) in self.cnum_map.iter_enumerated() {
if global == did.krate {
return Some(DefId {
krate: local,
@ -1007,7 +1007,7 @@ impl<'a, 'tcx> CrateMetadata {
.enumerate()
.flat_map(|(i, link)| {
let cnum = CrateNum::new(i + 1);
link.map(|link| (self.cnum_map.borrow()[cnum], link))
link.map(|link| (self.cnum_map[cnum], link))
})
.collect()
}

View File

@ -970,6 +970,9 @@ fn link_args(cmd: &mut Linker,
out_filename: &Path,
trans: &CrateTranslation) {
// Linker plugins should be specified early in the list of arguments
cmd.cross_lang_lto();
// The default library location, we need this to find the runtime.
// The location of crates will be determined as needed.
let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();

View File

@ -21,7 +21,8 @@ use back::symbol_export;
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
use rustc::middle::dependency_format::Linkage;
use rustc::session::Session;
use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel};
use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel,
CrossLangLto};
use rustc::ty::TyCtxt;
use rustc_target::spec::{LinkerFlavor, LldFlavor};
use serialize::{json, Encoder};
@ -127,6 +128,7 @@ pub trait Linker {
fn subsystem(&mut self, subsystem: &str);
fn group_start(&mut self);
fn group_end(&mut self);
fn cross_lang_lto(&mut self);
// Should have been finalize(self), but we don't support self-by-value on trait objects (yet?).
fn finalize(&mut self) -> Command;
}
@ -434,6 +436,42 @@ impl<'a> Linker for GccLinker<'a> {
self.linker_arg("--end-group");
}
}
fn cross_lang_lto(&mut self) {
match self.sess.opts.debugging_opts.cross_lang_lto {
CrossLangLto::Disabled |
CrossLangLto::NoLink => {
// Nothing to do
}
CrossLangLto::LinkerPlugin(ref path) => {
self.linker_arg(&format!("-plugin={}", path.display()));
let opt_level = match self.sess.opts.optimize {
config::OptLevel::No => "O0",
config::OptLevel::Less => "O1",
config::OptLevel::Default => "O2",
config::OptLevel::Aggressive => "O3",
config::OptLevel::Size => "Os",
config::OptLevel::SizeMin => "Oz",
};
self.linker_arg(&format!("-plugin-opt={}", opt_level));
self.linker_arg(&format!("-plugin-opt=mcpu={}", self.sess.target_cpu()));
match self.sess.opts.cg.lto {
config::Lto::Thin |
config::Lto::ThinLocal => {
self.linker_arg(&format!("-plugin-opt=thin"));
}
config::Lto::Fat |
config::Lto::Yes |
config::Lto::No => {
// default to regular LTO
}
}
}
}
}
}
pub struct MsvcLinker<'a> {
@ -666,6 +704,10 @@ impl<'a> Linker for MsvcLinker<'a> {
// MSVC doesn't need group indicators
fn group_start(&mut self) {}
fn group_end(&mut self) {}
fn cross_lang_lto(&mut self) {
// Do nothing
}
}
pub struct EmLinker<'a> {
@ -832,6 +874,10 @@ impl<'a> Linker for EmLinker<'a> {
// Appears not necessary on Emscripten
fn group_start(&mut self) {}
fn group_end(&mut self) {}
fn cross_lang_lto(&mut self) {
// Do nothing
}
}
fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec<String> {
@ -984,4 +1030,8 @@ impl Linker for WasmLd {
// Not needed for now with LLD
fn group_start(&mut self) {}
fn group_end(&mut self) {}
fn cross_lang_lto(&mut self) {
// Do nothing for now
}
}

View File

@ -174,10 +174,7 @@ pub fn target_machine_factory(sess: &Session, find_features: bool)
let triple = &sess.target.target.llvm_target;
let triple = CString::new(triple.as_bytes()).unwrap();
let cpu = match sess.opts.cg.target_cpu {
Some(ref s) => &**s,
None => &*sess.target.target.options.cpu
};
let cpu = sess.target_cpu();
let cpu = CString::new(cpu.as_bytes()).unwrap();
let features = attributes::llvm_target_features(sess)
.collect::<Vec<_>>()
@ -294,7 +291,7 @@ impl ModuleConfig {
self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode;
let embed_bitcode = sess.target.target.options.embed_bitcode ||
sess.opts.debugging_opts.embed_bitcode ||
sess.opts.debugging_opts.cross_lang_lto;
sess.opts.debugging_opts.cross_lang_lto.embed_bitcode();
if embed_bitcode {
match sess.opts.optimize {
config::OptLevel::No |
@ -1358,7 +1355,8 @@ fn execute_work_item(cgcx: &CodegenContext,
// Don't run LTO passes when cross-lang LTO is enabled. The linker
// will do that for us in this case.
let needs_lto = needs_lto && !cgcx.opts.debugging_opts.cross_lang_lto;
let needs_lto = needs_lto &&
!cgcx.opts.debugging_opts.cross_lang_lto.embed_bitcode();
if needs_lto {
Ok(WorkItemResult::NeedsLTO(mtrans))

View File

@ -11,9 +11,9 @@
//! This module provides constants which are specific to the implementation
//! of the `f32` floating point data type.
//!
//! Mathematically significant numbers are provided in the `consts` sub-module.
//!
//! *[See also the `f32` primitive type](../../std/primitive.f32.html).*
//!
//! Mathematically significant numbers are provided in the `consts` sub-module.
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
@ -195,8 +195,10 @@ impl f32 {
}
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding
/// error. This produces a more accurate result with better performance than
/// a separate multiplication operation followed by an add.
/// error, yielding a more accurate result than an unfused multiply-add.
///
/// Using `mul_add` can be more performant than an unfused multiply-add if
/// the target architecture has a dedicated `fma` CPU instruction.
///
/// ```
/// use std::f32;

View File

@ -11,9 +11,9 @@
//! This module provides constants which are specific to the implementation
//! of the `f64` floating point data type.
//!
//! Mathematically significant numbers are provided in the `consts` sub-module.
//!
//! *[See also the `f64` primitive type](../../std/primitive.f64.html).*
//!
//! Mathematically significant numbers are provided in the `consts` sub-module.
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
@ -173,8 +173,10 @@ impl f64 {
}
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding
/// error. This produces a more accurate result with better performance than
/// a separate multiplication operation followed by an add.
/// error, yielding a more accurate result than an unfused multiply-add.
///
/// Using `mul_add` can be more performant than an unfused multiply-add if
/// the target architecture has a dedicated `fma` CPU instruction.
///
/// ```
/// let m = 10.0_f64;

View File

@ -370,6 +370,8 @@ mod prim_unit { }
//
/// Raw, unsafe pointers, `*const T`, and `*mut T`.
///
/// *[See also the `std::ptr` module](ptr/index.html).*
///
/// Working with raw pointers in Rust is uncommon,
/// typically limited to a few patterns.
///
@ -444,8 +446,6 @@ mod prim_unit { }
/// but C APIs hand out a lot of pointers generally, so are a common source
/// of raw pointers in Rust.
///
/// *[See also the `std::ptr` module](ptr/index.html).*
///
/// [`null`]: ../std/ptr/fn.null.html
/// [`null_mut`]: ../std/ptr/fn.null_mut.html
/// [`is_null`]: ../std/primitive.pointer.html#method.is_null
@ -563,6 +563,8 @@ mod prim_array { }
//
/// A dynamically-sized view into a contiguous sequence, `[T]`.
///
/// *[See also the `std::slice` module](slice/index.html).*
///
/// Slices are a view into a block of memory represented as a pointer and a
/// length.
///
@ -585,8 +587,6 @@ mod prim_array { }
/// assert_eq!(x, &[1, 7, 3]);
/// ```
///
/// *[See also the `std::slice` module](slice/index.html).*
///
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_slice { }
@ -594,15 +594,13 @@ mod prim_slice { }
//
/// String slices.
///
/// *[See also the `std::str` module](str/index.html).*
///
/// The `str` type, also called a 'string slice', is the most primitive string
/// type. It is usually seen in its borrowed form, `&str`. It is also the type
/// of string literals, `&'static str`.
///
/// Strings slices are always valid UTF-8.
///
/// This documentation describes a number of methods and trait implementations
/// on the `str` type. For technical reasons, there is additional, separate
/// documentation in the [`std::str`](str/index.html) module as well.
/// String slices are always valid UTF-8.
///
/// # Examples
///
@ -862,11 +860,11 @@ mod prim_u128 { }
//
/// The pointer-sized signed integer type.
///
/// *[See also the `std::isize` module](isize/index.html).*
///
/// The size of this primitive is how many bytes it takes to reference any
/// location in memory. For example, on a 32 bit target, this is 4 bytes
/// and on a 64 bit target, this is 8 bytes.
///
/// *[See also the `std::isize` module](isize/index.html).*
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_isize { }
@ -874,11 +872,11 @@ mod prim_isize { }
//
/// The pointer-sized unsigned integer type.
///
/// *[See also the `std::usize` module](usize/index.html).*
///
/// The size of this primitive is how many bytes it takes to reference any
/// location in memory. For example, on a 32 bit target, this is 4 bytes
/// and on a 64 bit target, this is 8 bytes.
///
/// *[See also the `std::usize` module](usize/index.html).*
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_usize { }

View File

@ -5741,7 +5741,7 @@ impl<'a> Parser<'a> {
let vis = p.parse_visibility(true)?;
let ty = p.parse_ty()?;
Ok(StructField {
span: lo.to(p.span),
span: lo.to(ty.span),
vis,
ident: None,
id: ast::DUMMY_NODE_ID,

View File

@ -31,11 +31,13 @@ pub struct Span(u32);
impl Copy for Span {}
impl Clone for Span {
#[inline]
fn clone(&self) -> Span {
*self
}
}
impl PartialEq for Span {
#[inline]
fn eq(&self, other: &Span) -> bool {
let a = self.0;
let b = other.0;
@ -44,6 +46,7 @@ impl PartialEq for Span {
}
impl Eq for Span {}
impl Hash for Span {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
let a = self.0;
a.hash(state)

@ -1 +1 @@
Subproject commit b6c1a03fb498f6c03d1cbfd4404223a046f8c3b2
Subproject commit fd7dd99edf371ac502ae4e70288c027f6692ace0

View File

@ -18,9 +18,9 @@ endif
OBJDUMP=llvm-objdump
SECTION_HEADERS=$(OBJDUMP) -section-headers
BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1
BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1
BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1 --emit=obj
BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1 --emit=obj
all: staticlib staticlib-fat-lto staticlib-thin-lto rlib exe cdylib rdylib

View File

@ -5,7 +5,7 @@ LL | enum Bar {
| ^^^^^^^^ recursive type has infinite size
...
LL | BarSome(Bar)
| ---- recursive without indirection
| --- recursive without indirection
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable

View File

@ -4,7 +4,7 @@ error[E0072]: recursive type `Expr` has infinite size
LL | enum Expr { //~ ERROR E0072
| ^^^^^^^^^ recursive type has infinite size
LL | Plus(Expr, Expr),
| ----- ----- recursive without indirection
| ---- ---- recursive without indirection
| |
| recursive without indirection
|

View File

@ -20,14 +20,14 @@ enum Foo<'a, T> {
// Type U needs to outlive lifetime 'b
struct Bar<'b, U> {
field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
}
// Type K needs to outlive lifetime 'c.
enum Ying<'c, K> {
One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
One(&'c Yang<K>) //~ ERROR the parameter type `K` may not live long enough [E0309]
}
struct Yang<V> {

View File

@ -3,13 +3,13 @@ error[E0309]: the parameter type `U` may not live long enough
|
LL | struct Bar<'b, U> {
| - help: consider adding an explicit lifetime bound `U: 'b`...
LL | field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
LL | field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^
|
note: ...so that the reference type `&'b U` does not outlive the data it points at
--> $DIR/enum.rs:23:5
|
LL | field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
LL | field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^
error[E0309]: the parameter type `K` may not live long enough
@ -17,14 +17,14 @@ error[E0309]: the parameter type `K` may not live long enough
|
LL | enum Ying<'c, K> {
| - help: consider adding an explicit lifetime bound `K: 'c`...
LL | One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
| ^^^^^^^^^^^^
LL | One(&'c Yang<K>) //~ ERROR the parameter type `K` may not live long enough [E0309]
| ^^^^^^^^^^^
|
note: ...so that the reference type `&'c Yang<K>` does not outlive the data it points at
--> $DIR/enum.rs:30:9
|
LL | One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
| ^^^^^^^^^^^^
LL | One(&'c Yang<K>) //~ ERROR the parameter type `K` may not live long enough [E0309]
| ^^^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -0,0 +1,97 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(generic_associated_types)]
#![feature(associated_type_defaults)]
//FIXME(#44265): "lifetime parameters are not allowed on this type" errors will be addressed in a
//follow-up PR
// A Collection trait and collection families. Based on
// http://smallcultfollowing.com/babysteps/blog/2016/11/03/
// associated-type-constructors-part-2-family-traits/
trait Collection<T> {
type Iter<'iter>: Iterator<Item=&'iter T>;
type Family: CollectionFamily;
// Test associated type defaults with parameters
type Sibling<U>: Collection<U> =
<<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
//~^ ERROR type parameters are not allowed on this type [E0109]
fn empty() -> Self;
fn add(&mut self, value: T);
fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>;
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
}
trait CollectionFamily {
type Member<T>: Collection<T, Family = Self>;
}
struct VecFamily;
impl CollectionFamily for VecFamily {
type Member<T> = Vec<T>;
}
impl<T> Collection<T> for Vec<T> {
type Iter<'iter> = std::slice::Iter<'iter, T>;
type Family = VecFamily;
fn empty() -> Self {
Vec::new()
}
fn add(&mut self, value: T) {
self.push(value)
}
fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> {
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
self.iter()
}
}
fn floatify<C>(ints: &C) -> <<C as Collection<i32>>::Family as CollectionFamily>::Member<f32>
//~^ ERROR type parameters are not allowed on this type [E0109]
where
C: Collection<i32>,
{
let mut res = C::Family::Member::<f32>::empty();
for &v in ints.iterate() {
res.add(v as f32);
}
res
}
fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
//~^ ERROR type parameters are not allowed on this type [E0109]
where
C: Collection<i32>,
{
let mut res = C::Family::Member::<f32>::empty();
for &v in ints.iterate() {
res.add(v as f32);
}
res
}
fn use_floatify() {
let a = vec![1i32, 2, 3];
let b = floatify(a);
println!("{}", b.iterate().next());
let c = floatify_sibling(a);
println!("{}", c.iterate().next());
}
fn main() {}

View File

@ -0,0 +1,34 @@
error[E0109]: type parameters are not allowed on this type
--> $DIR/collections.rs:65:90
|
LL | fn floatify<C>(ints: &C) -> <<C as Collection<i32>>::Family as CollectionFamily>::Member<f32>
| ^^^ type parameter not allowed
error[E0109]: type parameters are not allowed on this type
--> $DIR/collections.rs:77:69
|
LL | fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
| ^^^ type parameter not allowed
error[E0109]: type parameters are not allowed on this type
--> $DIR/collections.rs:26:71
|
LL | <<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
| ^ type parameter not allowed
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/collections.rs:33:50
|
LL | fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>;
| ^^^^^ lifetime parameter not allowed on this type
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/collections.rs:59:50
|
LL | fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> {
| ^^^^^ lifetime parameter not allowed on this type
error: aborting due to 5 previous errors
Some errors occurred: E0109, E0110.
For more information about an error, try `rustc --explain E0109`.

View File

@ -10,6 +10,8 @@
#![feature(generic_associated_types)]
use std::ops::Deref;
//FIXME(#44265): "lifetime parameters are not allowed on this type" errors will be addressed in a
//follow-up PR
@ -18,11 +20,18 @@ trait Foo {
}
trait Baz {
type Quux<'a>;
type Quux<'a>: Foo;
// This weird type tests that we can use universal function call syntax to access the Item on
type Baa<'a>: Deref<Target = <Self::Quux<'a> as Foo>::Bar<'a, 'static>>;
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
//~| ERROR lifetime parameters are not allowed on this type [E0110]
}
impl<T> Baz for T where T: Foo {
type Quux<'a> = <T as Foo>::Bar<'a, 'static>;
type Quux<'a> = T;
type Baa<'a> = &'a <T as Foo>::Bar<'a, 'static>;
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
}

View File

@ -1,9 +1,21 @@
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/construct_with_other_type.rs:25:37
--> $DIR/construct_with_other_type.rs:26:46
|
LL | type Quux<'a> = <T as Foo>::Bar<'a, 'static>;
| ^^ lifetime parameter not allowed on this type
LL | type Baa<'a>: Deref<Target = <Self::Quux<'a> as Foo>::Bar<'a, 'static>>;
| ^^ lifetime parameter not allowed on this type
error: aborting due to previous error
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/construct_with_other_type.rs:26:63
|
LL | type Baa<'a>: Deref<Target = <Self::Quux<'a> as Foo>::Bar<'a, 'static>>;
| ^^ lifetime parameter not allowed on this type
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/construct_with_other_type.rs:34:40
|
LL | type Baa<'a> = &'a <T as Foo>::Bar<'a, 'static>;
| ^^ lifetime parameter not allowed on this type
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0110`.

View File

@ -20,13 +20,40 @@ trait Iterable {
type Iter<'a>: Iterator<Item = Self::Item<'a>>;
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
// This weird type tests that we can use universal function call syntax to access the Item on
// Self::Iter which we have declared to be an Iterator
type Iter2<'a>: Deref<Target = <Self::Iter<'a> as Iterator>::Item>;
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
fn iter<'a>(&'a self) -> Self::Iter<'a>;
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
}
// Impl for struct type
impl<T> Iterable for Vec<T> {
type Item<'a> = &'a T;
type Iter<'a> = std::slice::Iter<'a, T>;
fn iter<'a>(&'a self) -> Self::Iter<'a> {
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
self.iter()
}
}
// Impl for a primitive type
impl<T> Iterable for [T] {
type Item<'a> = &'a T;
type Iter<'a> = std::slice::Iter<'a, T>;
fn iter<'a>(&'a self) -> Self::Iter<'a> {
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
self.iter()
}
}
fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> {
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
it.iter()
}
fn get_first<'a, I: Iterable>(it: &'a I) -> Option<I::Item<'a>> {
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
it.iter().next()
}
fn main() {}

View File

@ -5,17 +5,35 @@ LL | type Iter<'a>: Iterator<Item = Self::Item<'a>>;
| ^^ lifetime parameter not allowed on this type
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/iterable.rs:25:48
--> $DIR/iterable.rs:49:53
|
LL | type Iter2<'a>: Deref<Target = <Self::Iter<'a> as Iterator>::Item>;
| ^^ lifetime parameter not allowed on this type
LL | fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> {
| ^^ lifetime parameter not allowed on this type
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/iterable.rs:28:41
--> $DIR/iterable.rs:54:60
|
LL | fn get_first<'a, I: Iterable>(it: &'a I) -> Option<I::Item<'a>> {
| ^^ lifetime parameter not allowed on this type
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/iterable.rs:23:41
|
LL | fn iter<'a>(&'a self) -> Self::Iter<'a>;
| ^^ lifetime parameter not allowed on this type
error: aborting due to 3 previous errors
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/iterable.rs:32:41
|
LL | fn iter<'a>(&'a self) -> Self::Iter<'a> {
| ^^ lifetime parameter not allowed on this type
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/iterable.rs:43:41
|
LL | fn iter<'a>(&'a self) -> Self::Iter<'a> {
| ^^ lifetime parameter not allowed on this type
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0110`.

View File

@ -0,0 +1,56 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(generic_associated_types)]
#![feature(associated_type_defaults)]
//FIXME(#44265): "lifetime parameters are not allowed on this type" errors will be addressed in a
//follow-up PR
//FIXME(#44265): Update expected errors once E110 is resolved, now does not get past `trait Foo`
trait Foo {
type A<'a>;
type B<'a, 'b>;
type C;
type D<T>;
type E<'a, T>;
// Test parameters in default values
type FOk<T> = Self::E<'static, T>;
//~^ ERROR type parameters are not allowed on this type [E0109]
//~| ERROR lifetime parameters are not allowed on this type [E0110]
type FErr1 = Self::E<'static, 'static>; // Error
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
type FErr2<T> = Self::E<'static, T, u32>; // Error
//~^ ERROR type parameters are not allowed on this type [E0109]
//~| ERROR lifetime parameters are not allowed on this type [E0110]
}
struct Fooy;
impl Foo for Fooy {
type A = u32; // Error: parameter expected
type B<'a, T> = Vec<T>; // Error: lifetime param expected
type C<'a> = u32; // Error: no param expected
type D<'a> = u32; // Error: type param expected
type E<T, U> = u32; // Error: lifetime expected as the first param
}
struct Fooer;
impl Foo for Fooer {
type A<T> = u32; // Error: lifetime parameter expected
type B<'a> = u32; // Error: another lifetime param expected
type C<T> = T; // Error: no param expected
type D<'b, T> = u32; // Error: unexpected lifetime param
type E<'a, 'b> = u32; // Error: type expected as the second param
}
fn main() {}

View File

@ -0,0 +1,34 @@
error[E0109]: type parameters are not allowed on this type
--> $DIR/parameter_number_and_kind.rs:26:36
|
LL | type FOk<T> = Self::E<'static, T>;
| ^ type parameter not allowed
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/parameter_number_and_kind.rs:26:27
|
LL | type FOk<T> = Self::E<'static, T>;
| ^^^^^^^ lifetime parameter not allowed on this type
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/parameter_number_and_kind.rs:29:26
|
LL | type FErr1 = Self::E<'static, 'static>; // Error
| ^^^^^^^ lifetime parameter not allowed on this type
error[E0109]: type parameters are not allowed on this type
--> $DIR/parameter_number_and_kind.rs:31:38
|
LL | type FErr2<T> = Self::E<'static, T, u32>; // Error
| ^ type parameter not allowed
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/parameter_number_and_kind.rs:31:29
|
LL | type FErr2<T> = Self::E<'static, T, u32>; // Error
| ^^^^^^^ lifetime parameter not allowed on this type
error: aborting due to 5 previous errors
Some errors occurred: E0109, E0110.
For more information about an error, try `rustc --explain E0109`.

View File

@ -0,0 +1,42 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(generic_associated_types)]
//FIXME(#44265): The lifetime shadowing and type parameter shadowing
// should cause an error. Now it compiles (errorneously) and this will be addressed
// by a future PR. Then remove the following:
// compile-pass
trait Shadow<'a> {
type Bar<'a>; // Error: shadowed lifetime
}
trait NoShadow<'a> {
type Bar<'b>; // OK
}
impl<'a> NoShadow<'a> for &'a u32 {
type Bar<'a> = i32; // Error: shadowed lifetime
}
trait ShadowT<T> {
type Bar<T>; // Error: shadowed type parameter
}
trait NoShadowT<T> {
type Bar<U>; // OK
}
impl<T> NoShadowT<T> for Option<T> {
type Bar<T> = i32; // Error: shadowed type parameter
}
fn main() {}

View File

@ -35,4 +35,48 @@ struct Foo<T: StreamingIterator> {
fn foo<T>(iter: T) where T: StreamingIterator, for<'a> T::Item<'a>: Display { /* ... */ }
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
// Full example of enumerate iterator
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
struct StreamEnumerate<I> {
iter: I,
count: usize,
}
impl<I: StreamingIterator> StreamingIterator for StreamEnumerate<I> {
type Item<'a> = (usize, I::Item<'a>);
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
fn next<'a>(&'a self) -> Option<Self::Item<'a>> {
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
match self.iter.next() {
None => None,
Some(val) => {
let r = Some((self.count, val));
self.count += 1;
r
}
}
}
}
impl<I> StreamEnumerate<I> {
pub fn new(iter: I) -> Self {
StreamEnumerate {
count: 0,
iter: iter,
}
}
}
fn test_stream_enumerate() {
let v = vec!["a", "b", "c"];
let se = StreamEnumerate::new(v.iter());
let a: &str = se.next().unwrap().1;
for (i, s) in se {
println!("{} {}", i, s);
}
println!("{}", a);
}
fn main() {}

View File

@ -16,6 +16,18 @@ error[E0110]: lifetime parameters are not allowed on this type
LL | fn next<'a>(&'a self) -> Option<Self::Item<'a>>;
| ^^ lifetime parameter not allowed on this type
error: aborting due to 3 previous errors
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/streaming_iterator.rs:47:37
|
LL | type Item<'a> = (usize, I::Item<'a>);
| ^^ lifetime parameter not allowed on this type
error[E0110]: lifetime parameters are not allowed on this type
--> $DIR/streaming_iterator.rs:49:48
|
LL | fn next<'a>(&'a self) -> Option<Self::Item<'a>> {
| ^^ lifetime parameter not allowed on this type
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0110`.

View File

@ -32,7 +32,7 @@ LL | #[derive(Copy)] //~ ERROR may not be implemented for this type
| ^^^^
LL | enum EFoo2<'a> {
LL | Bar(&'a mut bool),
| ------------- this field does not implement `Copy`
| ------------ this field does not implement `Copy`
error: aborting due to 4 previous errors

View File

@ -22,7 +22,7 @@ error[E0277]: the trait bound `T: std::marker::Sized` is not satisfied
--> $DIR/union-sized-field.rs:23:11
|
LL | Value(T), //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied
| ^^ `T` does not have a constant size known at compile-time
| ^ `T` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `T`
= help: consider adding a `where T: std::marker::Sized` bound

View File

@ -2,7 +2,7 @@ error[E0277]: the trait bound `W: std::marker::Sized` is not satisfied
--> $DIR/unsized-enum2.rs:33:8
|
LL | VA(W), //~ ERROR `W: std::marker::Sized` is not satisfied
| ^^ `W` does not have a constant size known at compile-time
| ^ `W` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `W`
= help: consider adding a `where W: std::marker::Sized` bound
@ -22,7 +22,7 @@ error[E0277]: the trait bound `Y: std::marker::Sized` is not satisfied
--> $DIR/unsized-enum2.rs:35:15
|
LL | VC(isize, Y), //~ ERROR `Y: std::marker::Sized` is not satisfied
| ^^ `Y` does not have a constant size known at compile-time
| ^ `Y` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `Y`
= help: consider adding a `where Y: std::marker::Sized` bound
@ -42,7 +42,7 @@ error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied
--> $DIR/unsized-enum2.rs:39:8
|
LL | VE([u8]), //~ ERROR `[u8]: std::marker::Sized` is not satisfied
| ^^^^^ `[u8]` does not have a constant size known at compile-time
| ^^^^ `[u8]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
= note: no field of an enum variant may have a dynamically sized type
@ -60,7 +60,7 @@ error[E0277]: the trait bound `[f32]: std::marker::Sized` is not satisfied
--> $DIR/unsized-enum2.rs:41:15
|
LL | VG(isize, [f32]), //~ ERROR `[f32]: std::marker::Sized` is not satisfied
| ^^^^^^ `[f32]` does not have a constant size known at compile-time
| ^^^^^ `[f32]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[f32]`
= note: no field of an enum variant may have a dynamically sized type
@ -78,7 +78,7 @@ error[E0277]: the trait bound `Foo + 'static: std::marker::Sized` is not satisfi
--> $DIR/unsized-enum2.rs:51:8
|
LL | VM(Foo), //~ ERROR `Foo + 'static: std::marker::Sized` is not satisfied
| ^^^^ `Foo + 'static` does not have a constant size known at compile-time
| ^^^ `Foo + 'static` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `Foo + 'static`
= note: no field of an enum variant may have a dynamically sized type
@ -96,7 +96,7 @@ error[E0277]: the trait bound `FooBar + 'static: std::marker::Sized` is not sati
--> $DIR/unsized-enum2.rs:53:15
|
LL | VO(isize, FooBar), //~ ERROR `FooBar + 'static: std::marker::Sized` is not satisfied
| ^^^^^^^ `FooBar + 'static` does not have a constant size known at compile-time
| ^^^^^^ `FooBar + 'static` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `FooBar + 'static`
= note: no field of an enum variant may have a dynamically sized type
@ -114,7 +114,7 @@ error[E0277]: the trait bound `[i8]: std::marker::Sized` is not satisfied
--> $DIR/unsized-enum2.rs:57:8
|
LL | VQ(<&'static [i8] as Deref>::Target), //~ ERROR `[i8]: std::marker::Sized` is not satisfied
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[i8]` does not have a constant size known at compile-time
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[i8]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[i8]`
= note: no field of an enum variant may have a dynamically sized type
@ -132,7 +132,7 @@ error[E0277]: the trait bound `[f64]: std::marker::Sized` is not satisfied
--> $DIR/unsized-enum2.rs:60:15
|
LL | VS(isize, <&'static [f64] as Deref>::Target),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[f64]` does not have a constant size known at compile-time
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[f64]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[f64]`
= note: no field of an enum variant may have a dynamically sized type
@ -150,7 +150,7 @@ error[E0277]: the trait bound `PathHelper1 + 'static: std::marker::Sized` is not
--> $DIR/unsized-enum2.rs:45:8
|
LL | VI(Path1), //~ ERROR `PathHelper1 + 'static: std::marker::Sized` is not satisfied
| ^^^^^^ `PathHelper1 + 'static` does not have a constant size known at compile-time
| ^^^^^ `PathHelper1 + 'static` does not have a constant size known at compile-time
|
= help: within `Path1`, the trait `std::marker::Sized` is not implemented for `PathHelper1 + 'static`
= note: required because it appears within the type `Path1`
@ -170,7 +170,7 @@ error[E0277]: the trait bound `PathHelper3 + 'static: std::marker::Sized` is not
--> $DIR/unsized-enum2.rs:47:15
|
LL | VK(isize, Path3), //~ ERROR `PathHelper3 + 'static: std::marker::Sized` is not satisfied
| ^^^^^^ `PathHelper3 + 'static` does not have a constant size known at compile-time
| ^^^^^ `PathHelper3 + 'static` does not have a constant size known at compile-time
|
= help: within `Path3`, the trait `std::marker::Sized` is not implemented for `PathHelper3 + 'static`
= note: required because it appears within the type `Path3`

View File

@ -26,6 +26,7 @@ if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then
echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs"
fi
MYDIR=$(dirname $0)
BUILD_DIR="$1"
shift
@ -33,13 +34,13 @@ shift
shopt -s nullglob
while [[ "$1" != "" ]]; do
MYDIR=$(dirname $1)
for EXT in "stderr" "stdout" "fixed"; do
for OUT_NAME in $BUILD_DIR/${1%.rs}.*$EXT; do
OUT_DIR=`dirname "$1"`
OUT_BASE=`basename "$OUT_NAME"`
if ! (diff $OUT_NAME $MYDIR/$OUT_BASE >& /dev/null); then
echo updating $MYDIR/$OUT_BASE
cp $OUT_NAME $MYDIR
if ! (diff $OUT_NAME $MYDIR/$OUT_DIR/$OUT_BASE >& /dev/null); then
echo updating $MYDIR/$OUT_DIR/$OUT_BASE
cp $OUT_NAME $MYDIR/$OUT_DIR
fi
done
done