1
Fork 0

Auto merge of #28897 - steveklabnik:rollup, r=steveklabnik

- Successful merges: #28836, #28856, #28874, #28876, #28878, #28880, #28882, #28885, #28889, #28896
- Failed merges:
This commit is contained in:
bors 2015-10-08 12:15:47 +00:00
commit b75fe81055
16 changed files with 178 additions and 84 deletions

View file

@ -85,3 +85,20 @@ Use inner doc comments _only_ to document crates and file-level modules:
//! //!
//! The core library is a something something... //! The core library is a something something...
``` ```
### Explain context.
Rust doesn't have special constructors, only functions that return new
instances. These aren't visible in the automatically generated documentation
for a type, so you should specifically link to them:
``` rust
/// An iterator that yields `None` forever after the underlying iterator
/// yields `None` once.
///
/// These can be created through
/// [`iter.fuse()`](trait.Iterator.html#method.fuse).
pub struct Fuse<I> {
// ...
}
```

View file

@ -26,7 +26,7 @@ shells out to the system linker (`gcc` on most systems, `link.exe` on MSVC),
so it makes sense to provide extra command line so it makes sense to provide extra command line
arguments, but this will not always be the case. In the future `rustc` may use arguments, but this will not always be the case. In the future `rustc` may use
LLVM directly to link native libraries, in which case `link_args` will have no LLVM directly to link native libraries, in which case `link_args` will have no
meaning. You can achieve the same effect as the `link-args` attribute with the meaning. You can achieve the same effect as the `link_args` attribute with the
`-C link-args` argument to `rustc`. `-C link-args` argument to `rustc`.
It is highly recommended to *not* use this attribute, and rather use the more It is highly recommended to *not* use this attribute, and rather use the more
@ -71,7 +71,7 @@ Dynamic linking on Linux can be undesirable if you wish to use new library
features on old systems or target systems which do not have the required features on old systems or target systems which do not have the required
dependencies for your program to run. dependencies for your program to run.
Static linking is supported via an alternative `libc`, `musl`. You can compile Static linking is supported via an alternative `libc`, [`musl`](http://www.musl-libc.org). You can compile
your own version of Rust with `musl` enabled and install it into a custom your own version of Rust with `musl` enabled and install it into a custom
directory with the instructions below: directory with the instructions below:

View file

@ -1,9 +1,10 @@
% Closures % Closures
Rust not only has named functions, but anonymous functions as well. Anonymous Sometimes it is useful to wrap up a function and _free variables_ for better
functions that have an associated environment are called closures, because they clarity and reuse. The free variables that can be used come from the
close over an environment. Rust has a really great implementation of them, as enclosing scope and are closed over when used in the function. From this, we
well see. get the name closures and Rust provides a really great implementation of
them, as well see.
# Syntax # Syntax
@ -34,7 +35,7 @@ assert_eq!(4, plus_two(2));
``` ```
Youll notice a few things about closures that are a bit different from regular Youll notice a few things about closures that are a bit different from regular
functions defined with `fn`. The first is that we did not need to named functions defined with `fn`. The first is that we did not need to
annotate the types of arguments the closure takes or the values it returns. We annotate the types of arguments the closure takes or the values it returns. We
can: can:
@ -44,14 +45,15 @@ let plus_one = |x: i32| -> i32 { x + 1 };
assert_eq!(2, plus_one(1)); assert_eq!(2, plus_one(1));
``` ```
But we dont have to. Why is this? Basically, it was chosen for ergonomic reasons. But we dont have to. Why is this? Basically, it was chosen for ergonomic
While specifying the full type for named functions is helpful with things like reasons. While specifying the full type for named functions is helpful with
documentation and type inference, the types of closures are rarely documented things like documentation and type inference, the full type signatures of
since theyre anonymous, and they dont cause the kinds of error-at-a-distance closures are rarely documented since theyre anonymous, and they dont cause
problems that inferring named function types can. the kinds of error-at-a-distance problems that inferring named function types
can.
The second is that the syntax is similar, but a bit different. Ive added spaces The second is that the syntax is similar, but a bit different. Ive added
here for easier comparison: spaces here for easier comparison:
```rust ```rust
fn plus_one_v1 (x: i32) -> i32 { x + 1 } fn plus_one_v1 (x: i32) -> i32 { x + 1 }
@ -63,8 +65,8 @@ Small differences, but theyre similar.
# Closures and their environment # Closures and their environment
Closures are called such because they close over their environment. It The environment for a closure can include bindings from its enclosing scope in
looks like this: addition to parameters and local bindings. It looks like this:
```rust ```rust
let num = 5; let num = 5;
@ -197,9 +199,10 @@ frame. Without `move`, a closure may be tied to the stack frame that created
it, while a `move` closure is self-contained. This means that you cannot it, while a `move` closure is self-contained. This means that you cannot
generally return a non-`move` closure from a function, for example. generally return a non-`move` closure from a function, for example.
But before we talk about taking and returning closures, we should talk some more But before we talk about taking and returning closures, we should talk some
about the way that closures are implemented. As a systems language, Rust gives more about the way that closures are implemented. As a systems language, Rust
you tons of control over what your code does, and closures are no different. gives you tons of control over what your code does, and closures are no
different.
# Closure implementation # Closure implementation
@ -288,9 +291,9 @@ isnt interesting. The next part is:
# some_closure(1) } # some_closure(1) }
``` ```
Because `Fn` is a trait, we can bound our generic with it. In this case, our closure Because `Fn` is a trait, we can bound our generic with it. In this case, our
takes a `i32` as an argument and returns an `i32`, and so the generic bound we use closure takes a `i32` as an argument and returns an `i32`, and so the generic
is `Fn(i32) -> i32`. bound we use is `Fn(i32) -> i32`.
Theres one other key point here: because were bounding a generic with a Theres one other key point here: because were bounding a generic with a
trait, this will get monomorphized, and therefore, well be doing static trait, this will get monomorphized, and therefore, well be doing static
@ -452,7 +455,7 @@ autogenerated name.
The error also points out that the return type is expected to be a reference, The error also points out that the return type is expected to be a reference,
but what we are trying to return is not. Further, we cannot directly assign a but what we are trying to return is not. Further, we cannot directly assign a
`'static` lifetime to an object. So we'll take a different approach and return `'static` lifetime to an object. So we'll take a different approach and return
a "trait object" by `Box`ing up the `Fn`. This _almost_ works: a trait object by `Box`ing up the `Fn`. This _almost_ works:
```rust,ignore ```rust,ignore
fn factory() -> Box<Fn(i32) -> i32> { fn factory() -> Box<Fn(i32) -> i32> {

View file

@ -563,8 +563,8 @@ What's going on here?
First, both `extern crate` and `use` allow renaming the thing that is being First, both `extern crate` and `use` allow renaming the thing that is being
imported. So the crate is still called "phrases", but here we will refer imported. So the crate is still called "phrases", but here we will refer
to it as "sayings". Similarly, the first `use` statement pulls in the to it as "sayings". Similarly, the first `use` statement pulls in the
`japanese::farewells` module from the crate, but makes it available as `japanese::greetings` module from the crate, but makes it available as
`jp_farewells` as opposed to simply `farewells`. This can help to avoid `ja_greetings` as opposed to simply `greetings`. This can help to avoid
ambiguity when importing similarly-named items from different places. ambiguity when importing similarly-named items from different places.
The second `use` statement uses a star glob to bring in _all_ symbols from the The second `use` statement uses a star glob to bring in _all_ symbols from the

View file

@ -42,12 +42,12 @@ loop is just a handy way to write this `loop`/`match`/`break` construct.
`for` loops aren't the only thing that uses iterators, however. Writing your `for` loops aren't the only thing that uses iterators, however. Writing your
own iterator involves implementing the `Iterator` trait. While doing that is own iterator involves implementing the `Iterator` trait. While doing that is
outside of the scope of this guide, Rust provides a number of useful iterators outside of the scope of this guide, Rust provides a number of useful iterators
to accomplish various tasks. Before we talk about those, we should talk about a to accomplish various tasks. But first, a few notes about limitations of ranges.
Rust anti-pattern. And that's using ranges like this.
Yes, we just talked about how ranges are cool. But ranges are also very Ranges are very primitive, and we often can use better alternatives. Consider
primitive. For example, if you needed to iterate over the contents of a vector, following Rust anti-pattern: using ranges to emulate a C-style `for` loop. Lets
you may be tempted to write this: suppose you needed to iterate over the contents of a vector. You may be tempted
to write this:
```rust ```rust
let nums = vec![1, 2, 3]; let nums = vec![1, 2, 3];
@ -281,8 +281,8 @@ If you are trying to execute a closure on an iterator for its side effects,
just use `for` instead. just use `for` instead.
There are tons of interesting iterator adapters. `take(n)` will return an There are tons of interesting iterator adapters. `take(n)` will return an
iterator over the next `n` elements of the original iterator. Let's try it out with our infinite iterator over the next `n` elements of the original iterator. Let's try it out
iterator from before: with an infinite iterator:
```rust ```rust
for i in (1..).take(5) { for i in (1..).take(5) {

View file

@ -43,11 +43,11 @@ With that in mind, lets learn about lifetimes.
Lending out a reference to a resource that someone else owns can be Lending out a reference to a resource that someone else owns can be
complicated. For example, imagine this set of operations: complicated. For example, imagine this set of operations:
- I acquire a handle to some kind of resource. 1. I acquire a handle to some kind of resource.
- I lend you a reference to the resource. 2. I lend you a reference to the resource.
- I decide Im done with the resource, and deallocate it, while you still have 3. I decide Im done with the resource, and deallocate it, while you still have
your reference. your reference.
- You decide to use the resource. 4. You decide to use the resource.
Uh oh! Your reference is pointing to an invalid resource. This is called a Uh oh! Your reference is pointing to an invalid resource. This is called a
dangling pointer or use after free, when the resource is memory. dangling pointer or use after free, when the resource is memory.

View file

@ -299,7 +299,7 @@ match x {
``` ```
This prints `no`, because the `if` applies to the whole of `4 | 5`, and not to This prints `no`, because the `if` applies to the whole of `4 | 5`, and not to
just the `5`, In other words, the the precedence of `if` behaves like this: just the `5`. In other words, the precedence of `if` behaves like this:
```text ```text
(4 | 5) if y => ... (4 | 5) if y => ...

View file

@ -61,7 +61,8 @@ pub struct DebugStruct<'a, 'b: 'a> {
has_fields: bool, has_fields: bool,
} }
pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>,
name: &str)
-> DebugStruct<'a, 'b> { -> DebugStruct<'a, 'b> {
let result = fmt.write_str(name); let result = fmt.write_str(name);
DebugStruct { DebugStruct {
@ -84,7 +85,8 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
if self.is_pretty() { if self.is_pretty() {
let mut writer = PadAdapter::new(self.fmt); let mut writer = PadAdapter::new(self.fmt);
fmt::write(&mut writer, format_args!("{}\n{}: {:#?}", prefix, name, value)) fmt::write(&mut writer,
format_args!("{}\n{}: {:#?}", prefix, name, value))
} else { } else {
write!(self.fmt, "{} {}: {:?}", prefix, name, value) write!(self.fmt, "{} {}: {:?}", prefix, name, value)
} }
@ -195,10 +197,18 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
self.result = self.result.and_then(|_| { self.result = self.result.and_then(|_| {
if self.is_pretty() { if self.is_pretty() {
let mut writer = PadAdapter::new(self.fmt); let mut writer = PadAdapter::new(self.fmt);
let prefix = if self.has_fields { "," } else { "" }; let prefix = if self.has_fields {
","
} else {
""
};
fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry)) fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry))
} else { } else {
let prefix = if self.has_fields { ", " } else { "" }; let prefix = if self.has_fields {
", "
} else {
""
};
write!(self.fmt, "{}{:?}", prefix, entry) write!(self.fmt, "{}{:?}", prefix, entry)
} }
}); });
@ -207,7 +217,11 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
} }
pub fn finish(&mut self) { pub fn finish(&mut self) {
let prefix = if self.is_pretty() && self.has_fields { "\n" } else { "" }; let prefix = if self.is_pretty() && self.has_fields {
"\n"
} else {
""
};
self.result = self.result.and_then(|_| self.fmt.write_str(prefix)); self.result = self.result.and_then(|_| self.fmt.write_str(prefix));
} }
@ -232,7 +246,7 @@ pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b
fmt: fmt, fmt: fmt,
result: result, result: result,
has_fields: false, has_fields: false,
} },
} }
} }
@ -247,7 +261,9 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> {
/// Adds the contents of an iterator of entries to the set output. /// Adds the contents of an iterator of entries to the set output.
#[stable(feature = "debug_builders", since = "1.2.0")] #[stable(feature = "debug_builders", since = "1.2.0")]
pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugSet<'a, 'b> pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugSet<'a, 'b>
where D: fmt::Debug, I: IntoIterator<Item=D> { where D: fmt::Debug,
I: IntoIterator<Item = D>
{
for entry in entries { for entry in entries {
self.entry(&entry); self.entry(&entry);
} }
@ -278,7 +294,7 @@ pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a,
fmt: fmt, fmt: fmt,
result: result, result: result,
has_fields: false, has_fields: false,
} },
} }
} }
@ -293,7 +309,9 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> {
/// Adds the contents of an iterator of entries to the list output. /// Adds the contents of an iterator of entries to the list output.
#[stable(feature = "debug_builders", since = "1.2.0")] #[stable(feature = "debug_builders", since = "1.2.0")]
pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugList<'a, 'b> pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugList<'a, 'b>
where D: fmt::Debug, I: IntoIterator<Item=D> { where D: fmt::Debug,
I: IntoIterator<Item = D>
{
for entry in entries { for entry in entries {
self.entry(&entry); self.entry(&entry);
} }
@ -335,10 +353,19 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
self.result = self.result.and_then(|_| { self.result = self.result.and_then(|_| {
if self.is_pretty() { if self.is_pretty() {
let mut writer = PadAdapter::new(self.fmt); let mut writer = PadAdapter::new(self.fmt);
let prefix = if self.has_fields { "," } else { "" }; let prefix = if self.has_fields {
fmt::write(&mut writer, format_args!("{}\n{:#?}: {:#?}", prefix, key, value)) ","
} else {
""
};
fmt::write(&mut writer,
format_args!("{}\n{:#?}: {:#?}", prefix, key, value))
} else { } else {
let prefix = if self.has_fields { ", " } else { "" }; let prefix = if self.has_fields {
", "
} else {
""
};
write!(self.fmt, "{}{:?}: {:?}", prefix, key, value) write!(self.fmt, "{}{:?}: {:?}", prefix, key, value)
} }
}); });
@ -350,7 +377,10 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
/// Adds the contents of an iterator of entries to the map output. /// Adds the contents of an iterator of entries to the map output.
#[stable(feature = "debug_builders", since = "1.2.0")] #[stable(feature = "debug_builders", since = "1.2.0")]
pub fn entries<K, V, I>(&mut self, entries: I) -> &mut DebugMap<'a, 'b> pub fn entries<K, V, I>(&mut self, entries: I) -> &mut DebugMap<'a, 'b>
where K: fmt::Debug, V: fmt::Debug, I: IntoIterator<Item=(K, V)> { where K: fmt::Debug,
V: fmt::Debug,
I: IntoIterator<Item = (K, V)>
{
for (k, v) in entries { for (k, v) in entries {
self.entry(&k, &v); self.entry(&k, &v);
} }
@ -360,7 +390,11 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
/// Finishes output and returns any error encountered. /// Finishes output and returns any error encountered.
#[stable(feature = "debug_builders", since = "1.2.0")] #[stable(feature = "debug_builders", since = "1.2.0")]
pub fn finish(&mut self) -> fmt::Result { pub fn finish(&mut self) -> fmt::Result {
let prefix = if self.is_pretty() && self.has_fields { "\n" } else { "" }; let prefix = if self.is_pretty() && self.has_fields {
"\n"
} else {
""
};
self.result.and_then(|_| write!(self.fmt, "{}}}", prefix)) self.result.and_then(|_| write!(self.fmt, "{}}}", prefix))
} }

View file

@ -48,7 +48,9 @@ trait GenericRadix {
fn base(&self) -> u8; fn base(&self) -> u8;
/// A radix-specific prefix string. /// A radix-specific prefix string.
fn prefix(&self) -> &'static str { "" } fn prefix(&self) -> &'static str {
""
}
/// Converts an integer to corresponding radix digit. /// Converts an integer to corresponding radix digit.
fn digit(&self, x: u8) -> u8; fn digit(&self, x: u8) -> u8;
@ -70,7 +72,10 @@ trait GenericRadix {
x = x / base; // Deaccumulate the number. x = x / base; // Deaccumulate the number.
*byte = self.digit(n.to_u8()); // Store the digit in the buffer. *byte = self.digit(n.to_u8()); // Store the digit in the buffer.
curr -= 1; curr -= 1;
if x == zero { break }; // No more digits left to accumulate. if x == zero {
// No more digits left to accumulate.
break
};
} }
} else { } else {
// Do the same as above, but accounting for two's complement. // Do the same as above, but accounting for two's complement.
@ -79,7 +84,10 @@ trait GenericRadix {
x = x / base; // Deaccumulate the number. x = x / base; // Deaccumulate the number.
*byte = self.digit(n.to_u8()); // Store the digit in the buffer. *byte = self.digit(n.to_u8()); // Store the digit in the buffer.
curr -= 1; curr -= 1;
if x == zero { break }; // No more digits left to accumulate. if x == zero {
// No more digits left to accumulate.
break
};
} }
} }
let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) }; let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) };
@ -141,13 +149,17 @@ pub struct Radix {
impl Radix { impl Radix {
fn new(base: u8) -> Radix { fn new(base: u8) -> Radix {
assert!(2 <= base && base <= 36, "the base must be in the range of 2..36: {}", base); assert!(2 <= base && base <= 36,
"the base must be in the range of 2..36: {}",
base);
Radix { base: base } Radix { base: base }
} }
} }
impl GenericRadix for Radix { impl GenericRadix for Radix {
fn base(&self) -> u8 { self.base } fn base(&self) -> u8 {
self.base
}
fn digit(&self, x: u8) -> u8 { fn digit(&self, x: u8) -> u8 {
match x { match x {
x @ 0 ... 9 => b'0' + x, x @ 0 ... 9 => b'0' + x,

View file

@ -53,5 +53,5 @@ pub enum Count {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum Position { pub enum Position {
Next, Next,
At(usize) At(usize),
} }

View file

@ -100,7 +100,9 @@ pub trait Hash {
/// Feeds a slice of this type into the state provided. /// Feeds a slice of this type into the state provided.
#[stable(feature = "hash_slice", since = "1.3.0")] #[stable(feature = "hash_slice", since = "1.3.0")]
fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) where Self: Sized { fn hash_slice<H: Hasher>(data: &[Self], state: &mut H)
where Self: Sized
{
for piece in data { for piece in data {
piece.hash(state); piece.hash(state);
} }
@ -121,7 +123,9 @@ pub trait Hasher {
/// Write a single `u8` into this hasher /// Write a single `u8` into this hasher
#[inline] #[inline]
#[stable(feature = "hasher_write", since = "1.3.0")] #[stable(feature = "hasher_write", since = "1.3.0")]
fn write_u8(&mut self, i: u8) { self.write(&[i]) } fn write_u8(&mut self, i: u8) {
self.write(&[i])
}
/// Write a single `u16` into this hasher. /// Write a single `u16` into this hasher.
#[inline] #[inline]
#[stable(feature = "hasher_write", since = "1.3.0")] #[stable(feature = "hasher_write", since = "1.3.0")]
@ -145,8 +149,7 @@ pub trait Hasher {
#[stable(feature = "hasher_write", since = "1.3.0")] #[stable(feature = "hasher_write", since = "1.3.0")]
fn write_usize(&mut self, i: usize) { fn write_usize(&mut self, i: usize) {
let bytes = unsafe { let bytes = unsafe {
::slice::from_raw_parts(&i as *const usize as *const u8, ::slice::from_raw_parts(&i as *const usize as *const u8, mem::size_of::<usize>())
mem::size_of::<usize>())
}; };
self.write(bytes); self.write(bytes);
} }
@ -154,23 +157,33 @@ pub trait Hasher {
/// Write a single `i8` into this hasher. /// Write a single `i8` into this hasher.
#[inline] #[inline]
#[stable(feature = "hasher_write", since = "1.3.0")] #[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i8(&mut self, i: i8) { self.write_u8(i as u8) } fn write_i8(&mut self, i: i8) {
self.write_u8(i as u8)
}
/// Write a single `i16` into this hasher. /// Write a single `i16` into this hasher.
#[inline] #[inline]
#[stable(feature = "hasher_write", since = "1.3.0")] #[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i16(&mut self, i: i16) { self.write_u16(i as u16) } fn write_i16(&mut self, i: i16) {
self.write_u16(i as u16)
}
/// Write a single `i32` into this hasher. /// Write a single `i32` into this hasher.
#[inline] #[inline]
#[stable(feature = "hasher_write", since = "1.3.0")] #[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i32(&mut self, i: i32) { self.write_u32(i as u32) } fn write_i32(&mut self, i: i32) {
self.write_u32(i as u32)
}
/// Write a single `i64` into this hasher. /// Write a single `i64` into this hasher.
#[inline] #[inline]
#[stable(feature = "hasher_write", since = "1.3.0")] #[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i64(&mut self, i: i64) { self.write_u64(i as u64) } fn write_i64(&mut self, i: i64) {
self.write_u64(i as u64)
}
/// Write a single `isize` into this hasher. /// Write a single `isize` into this hasher.
#[inline] #[inline]
#[stable(feature = "hasher_write", since = "1.3.0")] #[stable(feature = "hasher_write", since = "1.3.0")]
fn write_isize(&mut self, i: isize) { self.write_usize(i as usize) } fn write_isize(&mut self, i: isize) {
self.write_usize(i as usize)
}
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////

View file

@ -37,12 +37,12 @@ pub struct SipHasher {
// and simd implementations of SipHash will use vectors // and simd implementations of SipHash will use vectors
// of v02 and v13. By placing them in this order in the struct, // of v02 and v13. By placing them in this order in the struct,
// the compiler can pick up on just a few simd optimizations by itself. // the compiler can pick up on just a few simd optimizations by itself.
v0: u64, // hash state v0: u64, // hash state
v2: u64, v2: u64,
v1: u64, v1: u64,
v3: u64, v3: u64,
tail: u64, // unprocessed bytes le tail: u64, // unprocessed bytes le
ntail: usize, // how many bytes in tail are valid ntail: usize, // how many bytes in tail are valid
} }
// sadly, these macro definitions can't appear later, // sadly, these macro definitions can't appear later,
@ -80,8 +80,7 @@ macro_rules! u8to64_le {
unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 { unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
debug_assert!(i + 8 <= buf.len()); debug_assert!(i + 8 <= buf.len());
let mut data = 0u64; let mut data = 0u64;
ptr::copy_nonoverlapping(buf.get_unchecked(i), ptr::copy_nonoverlapping(buf.get_unchecked(i), &mut data as *mut _ as *mut u8, 8);
&mut data as *mut _ as *mut u8, 8);
data.to_le() data.to_le()
} }
@ -152,12 +151,12 @@ impl Hasher for SipHasher {
if self.ntail != 0 { if self.ntail != 0 {
needed = 8 - self.ntail; needed = 8 - self.ntail;
if length < needed { if length < needed {
self.tail |= u8to64_le!(msg, 0, length) << 8*self.ntail; self.tail |= u8to64_le!(msg, 0, length) << 8 * self.ntail;
self.ntail += length; self.ntail += length;
return return
} }
let m = self.tail | u8to64_le!(msg, 0, needed) << 8*self.ntail; let m = self.tail | u8to64_le!(msg, 0, needed) << 8 * self.ntail;
self.v3 ^= m; self.v3 ^= m;
compress!(self.v0, self.v1, self.v2, self.v3); compress!(self.v0, self.v1, self.v2, self.v3);

View file

@ -706,7 +706,8 @@ impl<T> Option<T> {
} }
impl<'a, T: Clone> Option<&'a T> { impl<'a, T: Clone> Option<&'a T> {
/// Maps an Option<&T> to an Option<T> by cloning the contents of the Option. /// Maps an `Option<&T>` to an `Option<T>` by cloning the contents of the
/// option.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn cloned(self) -> Option<T> { pub fn cloned(self) -> Option<T> {
self.map(|t| t.clone()) self.map(|t| t.clone())

View file

@ -12,6 +12,21 @@
register_long_diagnostics! { register_long_diagnostics! {
E0515: r##"
A constant index expression was out of bounds. Erroneous code example:
```
let x = &[0, 1, 2][7]; // error: const index-expr is out of bounds
```
Please specify a valid index (not inferior to 0 or superior to array length).
Example:
```
let x = &[0, 1, 2][2]; // ok!
```
"##,
} }
register_diagnostics! { register_diagnostics! {

View file

@ -628,8 +628,8 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
if iv >= len { if iv >= len {
// FIXME #3170: report this earlier on in the const-eval // FIXME #3170: report this earlier on in the const-eval
// pass. Reporting here is a bit late. // pass. Reporting here is a bit late.
cx.sess().span_err(e.span, span_err!(cx.sess(), e.span, E0515,
"const index-expr is out of bounds"); "const index-expr is out of bounds");
C_undef(val_ty(arr).element_type()) C_undef(val_ty(arr).element_type())
} else { } else {
const_get_elt(cx, arr, &[iv as c_uint]) const_get_elt(cx, arr, &[iv as c_uint])

View file

@ -1,7 +1,7 @@
// ignore-tidy-cr ignore-license // ignore-tidy-cr ignore-license
// ignore-tidy-cr (repeated again because of tidy bug) // ignore-tidy-cr (repeated again because of tidy bug)
// license is ignored because tidy can't handle the CRLF here properly. // license is ignored because tidy can't handle the CRLF here properly.
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at // file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT. // http://rust-lang.org/COPYRIGHT.
@ -11,33 +11,33 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// NB: this file needs CRLF line endings. The .gitattributes file in // NB: this file needs CRLF line endings. The .gitattributes file in
// this directory should enforce it. // this directory should enforce it.
// ignore-pretty // ignore-pretty
/// Doc comment that ends in CRLF /// Doc comment that ends in CRLF
pub fn foo() {} pub fn foo() {}
/** Block doc comment that /** Block doc comment that
* contains CRLF characters * contains CRLF characters
*/ */
pub fn bar() {} pub fn bar() {}
fn main() { fn main() {
let s = "string let s = "string
literal"; literal";
assert_eq!(s, "string\nliteral"); assert_eq!(s, "string\nliteral");
let s = "literal with \ let s = "literal with \
escaped newline"; escaped newline";
assert_eq!(s, "literal with escaped newline"); assert_eq!(s, "literal with escaped newline");
let s = r"string let s = r"string
literal"; literal";
assert_eq!(s, "string\nliteral"); assert_eq!(s, "string\nliteral");
// validate that our source file has CRLF endings // validate that our source file has CRLF endings
let source = include_str!("lexer-crlf-line-endings-string-literal-doc-comment.rs"); let source = include_str!("lexer-crlf-line-endings-string-literal-doc-comment.rs");
assert!(source.contains("string\r\nliteral")); assert!(source.contains("string\r\nliteral"));