diff --git a/src/doc/index.md b/src/doc/index.md index 5a437e959b7fb..c4725c26e46bd 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -5,15 +5,14 @@ to jump to any particular section. # Getting Started -If you haven't seen Rust at all yet, the first thing you should read is the [30 -minute intro](intro.html). It will give you an overview of the basic ideas of Rust -at a high level. +If you haven't seen Rust at all yet, the first thing you should read is the +introduction to [The Rust Programming Language](book/index.html). It'll give +you a good idea of what Rust is like. -Once you know you really want to learn Rust, the next step is reading [The -Rust Programming Language](book/index.html). It is a lengthy explanation of -Rust, its syntax, and its concepts. Upon completing the book, you'll be an -intermediate Rust developer, and will have a good grasp of the fundamental -ideas behind Rust. +The book provides a lengthy explanation of Rust, its syntax, and its +concepts. Upon completing the book, you'll be an intermediate Rust +developer, and will have a good grasp of the fundamental ideas behind +Rust. [Rust By Example][rbe] was originally a community resource, but was then donated to the Rust project. As the name implies, it teaches you Rust through a @@ -24,7 +23,7 @@ series of small examples. # Community & Getting Help If you need help with something, or just want to talk about Rust with others, -there's a few places you can do that: +there are a few places you can do that: The Rust IRC channels on [irc.mozilla.org](http://irc.mozilla.org/) are the fastest way to get help. @@ -59,7 +58,7 @@ the language in as much detail as possible is in [the reference](reference.html) # Tools -Rust's still a young language, so there isn't a ton of tooling yet, but the +Rust is still a young language, so there isn't a ton of tooling yet, but the tools we have are really nice. [Cargo](http://crates.io) is Rust's package manager, and its website contains @@ -69,16 +68,21 @@ lots of good documentation. # FAQs -There are questions that are asked quite often, and so we've made FAQs for them: +There are questions that are asked quite often, so we've made FAQs for them: * [Language Design FAQ](complement-design-faq.html) * [Language FAQ](complement-lang-faq.html) * [Project FAQ](complement-project-faq.html) * [How to submit a bug report](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports) -# The standard library +# The Standard Library We have [API documentation for the entire standard library](std/index.html). There's a list of crates on the left with more specific sections, or you can use the search bar at the top to search for something if you know its name. + +# The Error Index + +If you encounter an error while compiling your code you may be able to look it +up in the [Rust Compiler Error Index](error-index.html). diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index de7ded76280f6..3f97928a56e3f 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -15,6 +15,7 @@ * [Concurrency](concurrency.md) * [Error Handling](error-handling.md) * [FFI](ffi.md) + * [Borrow and AsRef](borrow-and-asref.md) * [Syntax and Semantics](syntax-and-semantics.md) * [Variable Bindings](variable-bindings.md) * [Functions](functions.md) diff --git a/src/doc/trpl/borrow-and-asref.md b/src/doc/trpl/borrow-and-asref.md new file mode 100644 index 0000000000000..f5f314f1c21d6 --- /dev/null +++ b/src/doc/trpl/borrow-and-asref.md @@ -0,0 +1,93 @@ +% Borrow and AsRef + +The [`Borrow`][borrow] and [`AsRef`][asref] traits are very similar, but +different. Here’s a quick refresher on what these two traits mean. + +[borrow]: ../std/borrow/trait.Borrow.html +[asref]: ../std/convert/trait.AsRef.html + +# Borrow + +The `Borrow` trait is used when you’re writing a datastructure, and you want to +use either an owned or borrowed type as synonymous for some purpose. + +For example, [`HashMap`][hashmap] has a [`get` method][get] which uses `Borrow`: + +```rust,ignore +fn get(&self, k: &Q) -> Option<&V> + where K: Borrow, + Q: Hash + Eq +``` + +[hashmap]: ../std/collections/struct.HashMap.html +[get]: ../std/collections/struct.HashMap.html#method.get + +This signature is pretty complicated. The `K` parameter is what we’re interested +in here. It refers to a parameter of the `HashMap` itself: + +```rust,ignore +struct HashMap { +``` + +The `K` parameter is the type of _key_ the `HashMap` uses. So, looking at +the signature of `get()` again, we can use `get()` when the key implements +`Borrow`. That way, we can make a `HashMap` which uses `String` keys, +but use `&str`s when we’re searching: + +```rust +use std::collections::HashMap; + +let mut map = HashMap::new(); +map.insert("Foo".to_string(), 42); + +assert_eq!(map.get("Foo"), Some(&42)); +``` + +This is because the standard library has `impl Borrow for String`. + +For most types, when you want to take an owned or borrowed type, a `&T` is +enough. But one area where `Borrow` is effective is when there’s more than one +kind of borrowed value. Slices are an area where this is especially true: you +can have both an `&[T]` or a `&mut [T]`. If we wanted to accept both of these +types, `Borrow` is up for it: + +``` +use std::borrow::Borrow; +use std::fmt::Display; + +fn foo + Display>(a: T) { + println!("a is borrowed: {}", a); +} + +let mut i = 5; + +foo(&i); +foo(&mut i); +``` + +This will print out `a is borrowed: 5` twice. + +# AsRef + +The `AsRef` trait is a conversion trait. It’s used for converting some value to +a reference in generic code. Like this: + +```rust +let s = "Hello".to_string(); + +fn foo>(s: T) { + let slice = s.as_ref(); +} +``` + +# Which should I use? + +We can see how they’re kind of the same: they both deal with owned and borrowed +versions of some type. However, they’re a bit different. + +Choose `Borrow` when you want to abstract over different kinds of borrowing, or +when you’re building a datastructure that treats owned and borrowed values in +equivalent ways, such as hashing and comparison. + +Choose `AsRef` when you want to convert something to a reference directly, and +you’re writing generic code. diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md index 86164a08a430f..25d5122b4e49e 100644 --- a/src/doc/trpl/lifetimes.md +++ b/src/doc/trpl/lifetimes.md @@ -5,7 +5,7 @@ Rust’s most unique and compelling features, with which Rust developers should become quite acquainted. Ownership is how Rust achieves its largest goal, memory safety. There are a few distinct concepts, each with its own chapter: -* [ownership][ownership], ownership, the key concept +* [ownership][ownership], the key concept * [borrowing][borrowing], and their associated feature ‘references’ * lifetimes, which you’re reading now diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index 971bb7cd700db..b210f1c643f43 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -6,7 +6,7 @@ become quite acquainted. Ownership is how Rust achieves its largest goal, memory safety. There are a few distinct concepts, each with its own chapter: -* ownership, which you’re reading now. +* ownership, which you’re reading now * [borrowing][borrowing], and their associated feature ‘references’ * [lifetimes][lifetimes], an advanced concept of borrowing @@ -23,7 +23,7 @@ Before we get to the details, two important notes about the ownership system. Rust has a focus on safety and speed. It accomplishes these goals through many ‘zero-cost abstractions’, which means that in Rust, abstractions cost as little as possible in order to make them work. The ownership system is a prime example -of a zero cost abstraction. All of the analysis we’ll talk about in this guide +of a zero-cost abstraction. All of the analysis we’ll talk about in this guide is _done at compile time_. You do not pay any run-time cost for any of these features. @@ -41,7 +41,7 @@ With that in mind, let’s learn about ownership. # Ownership -[`Variable bindings`][bindings] have a property in Rust: they ‘have ownership’ +[Variable bindings][bindings] have a property in Rust: they ‘have ownership’ of what they’re bound to. This means that when a binding goes out of scope, the resource that they’re bound to are freed. For example: @@ -106,8 +106,8 @@ take(v); println!("v[0] is: {}", v[0]); ``` -Same error: “use of moved value.” When we transfer ownership to something else, -we say that we’ve ‘moved’ the thing we refer to. You don’t need some sort of +Same error: ‘use of moved value’. When we transfer ownership to something else, +we say that we’ve ‘moved’ the thing we refer to. You don’t need any sort of special annotation here, it’s the default thing that Rust does. ## The details @@ -121,19 +121,19 @@ let v = vec![1, 2, 3]; let v2 = v; ``` -The first line creates some data for the vector on the [stack][sh], `v`. The -vector’s data, however, is stored on the [heap][sh], and so it contains a -pointer to that data. When we move `v` to `v2`, it creates a copy of that pointer, -for `v2`. Which would mean two pointers to the contents of the vector on the -heap. That would be a problem: it would violate Rust’s safety guarantees by -introducing a data race. Therefore, Rust forbids using `v` after we’ve done the -move. +The first line allocates memory for the vector object, `v`, and for the data it +contains. The vector object is stored on the [stack][sh] and contains a pointer +to the content (`[1, 2, 3]`) stored on the [heap][sh]. When we move `v` to `v2`, +it creates a copy of that pointer, for `v2`. Which means that there would be two +pointers to the content of the vector on the heap. It would violate Rust’s +safety guarantees by introducing a data race. Therefore, Rust forbids using `v` +after we’ve done the move. [sh]: the-stack-and-the-heap.html It’s also important to note that optimizations may remove the actual copy of -the bytes, depending on circumstances. So it may not be as inefficient as it -initially seems. +the bytes on the stack, depending on circumstances. So it may not be as +inefficient as it initially seems. ## `Copy` types diff --git a/src/doc/trpl/primitive-types.md b/src/doc/trpl/primitive-types.md index bb2bf028700d2..22483816769c3 100644 --- a/src/doc/trpl/primitive-types.md +++ b/src/doc/trpl/primitive-types.md @@ -15,7 +15,7 @@ let x = true; let y: bool = false; ``` -A common use of booleans is in [`if` statements][if]. +A common use of booleans is in [`if` conditionals][if]. [if]: if.html diff --git a/src/doc/trpl/while-loops.md b/src/doc/trpl/while-loops.md index f2e2f6b6f49a7..e71d2033f49ed 100644 --- a/src/doc/trpl/while-loops.md +++ b/src/doc/trpl/while-loops.md @@ -1,4 +1,4 @@ -% while loops +% while Loops Rust also has a `while` loop. It looks like this: diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 7332bf4670ae5..a86a4b4215f23 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -37,6 +37,11 @@ use self::Cow::*; /// trait: if `T: Borrow`, then `&U` can be borrowed from `&T`. A given /// type can be borrowed as multiple different types. In particular, `Vec: /// Borrow>` and `Vec: Borrow<[T]>`. +/// +/// `Borrow` is very similar to, but different than, `AsRef`. See +/// [the book][book] for more. +/// +/// [book]: ../../book/borrow-and-asref.html #[stable(feature = "rust1", since = "1.0.0")] pub trait Borrow { /// Immutably borrows from an owned value. diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index da6ac6bd752bf..f6987c1966493 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -24,6 +24,11 @@ use marker::Sized; /// A cheap, reference-to-reference conversion. /// +/// `AsRef` is very similar to, but different than, `Borrow`. See +/// [the book][book] for more. +/// +/// [book]: ../../book/borrow-and-asref.html +/// /// # Examples /// /// Both `String` and `&str` implement `AsRef`: diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 56dee3034870c..9db1ceddf0d75 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -140,7 +140,7 @@ impl SliceExt for [T] { assume(!p.is_null()); if mem::size_of::() == 0 { Iter {ptr: p, - end: (p as usize + self.len()) as *const T, + end: ((p as usize).wrapping_add(self.len())) as *const T, _marker: marker::PhantomData} } else { Iter {ptr: p, @@ -277,7 +277,7 @@ impl SliceExt for [T] { assume(!p.is_null()); if mem::size_of::() == 0 { IterMut {ptr: p, - end: (p as usize + self.len()) as *mut T, + end: ((p as usize).wrapping_add(self.len())) as *mut T, _marker: marker::PhantomData} } else { IterMut {ptr: p, @@ -632,35 +632,17 @@ fn size_from_ptr(_: *const T) -> usize { // Use macros to be generic over const/mut -// -// They require non-negative `$by` because otherwise the expression -// `(ptr as usize + $by)` would interpret `-1` as `usize::MAX` (and -// thus trigger a panic when overflow checks are on). - -// Use this to do `$ptr + $by`, where `$by` is non-negative. -macro_rules! slice_add_offset { +macro_rules! slice_offset { ($ptr:expr, $by:expr) => {{ let ptr = $ptr; if size_from_ptr(ptr) == 0 { - transmute(ptr as usize + $by) + transmute((ptr as isize).wrapping_add($by)) } else { ptr.offset($by) } }}; } -// Use this to do `$ptr - $by`, where `$by` is non-negative. -macro_rules! slice_sub_offset { - ($ptr:expr, $by:expr) => {{ - let ptr = $ptr; - if size_from_ptr(ptr) == 0 { - transmute(ptr as usize - $by) - } else { - ptr.offset(-$by) - } - }}; -} - macro_rules! slice_ref { ($ptr:expr) => {{ let ptr = $ptr; @@ -683,14 +665,16 @@ macro_rules! iterator { #[inline] fn next(&mut self) -> Option<$elem> { // could be implemented with slices, but this avoids bounds checks - unsafe { - ::intrinsics::assume(!self.ptr.is_null()); - ::intrinsics::assume(!self.end.is_null()); - if self.ptr == self.end { - None - } else { + if self.ptr == self.end { + None + } else { + unsafe { + if mem::size_of::() != 0 { + ::intrinsics::assume(!self.ptr.is_null()); + ::intrinsics::assume(!self.end.is_null()); + } let old = self.ptr; - self.ptr = slice_add_offset!(self.ptr, 1); + self.ptr = slice_offset!(self.ptr, 1); Some(slice_ref!(old)) } } @@ -698,7 +682,7 @@ macro_rules! iterator { #[inline] fn size_hint(&self) -> (usize, Option) { - let diff = (self.end as usize) - (self.ptr as usize); + let diff = (self.end as usize).wrapping_sub(self.ptr as usize); let size = mem::size_of::(); let exact = diff / (if size == 0 {1} else {size}); (exact, Some(exact)) @@ -726,13 +710,15 @@ macro_rules! iterator { #[inline] fn next_back(&mut self) -> Option<$elem> { // could be implemented with slices, but this avoids bounds checks - unsafe { - ::intrinsics::assume(!self.ptr.is_null()); - ::intrinsics::assume(!self.end.is_null()); - if self.end == self.ptr { - None - } else { - self.end = slice_sub_offset!(self.end, 1); + if self.end == self.ptr { + None + } else { + unsafe { + self.end = slice_offset!(self.end, -1); + if mem::size_of::() != 0 { + ::intrinsics::assume(!self.ptr.is_null()); + ::intrinsics::assume(!self.end.is_null()); + } Some(slice_ref!(self.end)) } } @@ -742,29 +728,29 @@ macro_rules! iterator { } macro_rules! make_slice { - ($t: ty => $result: ty: $start: expr, $end: expr) => {{ - let diff = $end as usize - $start as usize; - let len = if mem::size_of::() == 0 { - diff + ($start: expr, $end: expr) => {{ + let start = $start; + let diff = ($end as usize).wrapping_sub(start as usize); + if size_from_ptr(start) == 0 { + // use a non-null pointer value + unsafe { from_raw_parts(1 as *const _, diff) } } else { - diff / mem::size_of::<$t>() - }; - unsafe { - from_raw_parts($start, len) + let len = diff / size_from_ptr(start); + unsafe { from_raw_parts(start, len) } } }} } macro_rules! make_mut_slice { - ($t: ty => $result: ty: $start: expr, $end: expr) => {{ - let diff = $end as usize - $start as usize; - let len = if mem::size_of::() == 0 { - diff + ($start: expr, $end: expr) => {{ + let start = $start; + let diff = ($end as usize).wrapping_sub(start as usize); + if size_from_ptr(start) == 0 { + // use a non-null pointer value + unsafe { from_raw_parts_mut(1 as *mut _, diff) } } else { - diff / mem::size_of::<$t>() - }; - unsafe { - from_raw_parts_mut($start, len) + let len = diff / size_from_ptr(start); + unsafe { from_raw_parts_mut(start, len) } } }} } @@ -787,14 +773,14 @@ impl<'a, T> Iter<'a, T> { /// iterator can continue to be used while this exists. #[unstable(feature = "core")] pub fn as_slice(&self) -> &'a [T] { - make_slice!(T => &'a [T]: self.ptr, self.end) + make_slice!(self.ptr, self.end) } // Helper function for Iter::nth fn iter_nth(&mut self, n: usize) -> Option<&'a T> { match self.as_slice().get(n) { Some(elem_ref) => unsafe { - self.ptr = slice_add_offset!(elem_ref as *const _, 1); + self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1)); Some(slice_ref!(elem_ref)) }, None => { @@ -827,12 +813,7 @@ impl<'a, T> RandomAccessIterator for Iter<'a, T> { fn idx(&mut self, index: usize) -> Option<&'a T> { unsafe { if index < self.indexable() { - if mem::size_of::() == 0 { - // Use a non-null pointer value - Some(&mut *(1 as *mut _)) - } else { - Some(transmute(self.ptr.offset(index as isize))) - } + Some(slice_ref!(self.ptr.offset(index as isize))) } else { None } @@ -860,14 +841,14 @@ impl<'a, T> IterMut<'a, T> { /// restricted lifetimes that do not consume the iterator. #[unstable(feature = "core")] pub fn into_slice(self) -> &'a mut [T] { - make_mut_slice!(T => &'a mut [T]: self.ptr, self.end) + make_mut_slice!(self.ptr, self.end) } // Helper function for IterMut::nth fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> { - match make_mut_slice!(T => &'a mut [T]: self.ptr, self.end).get_mut(n) { + match make_mut_slice!(self.ptr, self.end).get_mut(n) { Some(elem_ref) => unsafe { - self.ptr = slice_add_offset!(elem_ref as *mut _, 1); + self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1)); Some(slice_ref!(elem_ref)) }, None => { diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 55934da00a37c..69ab34fee5a1f 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -5722,6 +5722,9 @@ pub mod funcs { pub fn tcgetpgrp(fd: c_int) -> pid_t; pub fn ttyname(fd: c_int) -> *mut c_char; pub fn unlink(c: *const c_char) -> c_int; + pub fn wait(status: *const c_int) -> pid_t; + pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int) + -> pid_t; pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, @@ -5773,6 +5776,9 @@ pub mod funcs { pub fn sysconf(name: c_int) -> c_long; pub fn ttyname(fd: c_int) -> *mut c_char; pub fn unlink(c: *const c_char) -> c_int; + pub fn wait(status: *const c_int) -> pid_t; + pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int) + -> pid_t; pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 0f1e55544e1af..6690e6831afee 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -273,8 +273,8 @@ See also http://doc.rust-lang.org/book/unsafe.html E0137: r##" This error indicates that the compiler found multiple functions with the -#[main] attribute. This is an error because there must be a unique entry point -into a Rust program. +`#[main]` attribute. This is an error because there must be a unique entry +point into a Rust program. "##, E0152: r##" diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 06a40f1dd277d..b6202084296bb 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -189,6 +189,7 @@ pub const tag_item_impl_vtables: usize = 0x7e; pub const tag_impls: usize = 0x109; // top-level only pub const tag_impls_impl: usize = 0x7f; +pub const tag_impls_impl_trait_def_id: usize = 0x8d; pub const tag_items_data_item_inherent_impl: usize = 0x80; pub const tag_items_data_item_extension_impl: usize = 0x81; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 7132ac4895aa1..6caefec48783a 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -304,31 +304,23 @@ pub fn get_native_libraries(cstore: &cstore::CStore, crate_num: ast::CrateNum) decoder::get_native_libraries(&*cdata) } -pub fn each_impl(cstore: &cstore::CStore, - crate_num: ast::CrateNum, - callback: F) where - F: FnMut(ast::DefId), -{ - let cdata = cstore.get_crate_data(crate_num); - decoder::each_impl(&*cdata, callback) -} - -pub fn each_implementation_for_type(cstore: &cstore::CStore, - def_id: ast::DefId, - callback: F) where +pub fn each_inherent_implementation_for_type(cstore: &cstore::CStore, + def_id: ast::DefId, + callback: F) where F: FnMut(ast::DefId), { let cdata = cstore.get_crate_data(def_id.krate); - decoder::each_implementation_for_type(&*cdata, def_id.node, callback) + decoder::each_inherent_implementation_for_type(&*cdata, def_id.node, callback) } pub fn each_implementation_for_trait(cstore: &cstore::CStore, def_id: ast::DefId, - callback: F) where + mut callback: F) where F: FnMut(ast::DefId), { - let cdata = cstore.get_crate_data(def_id.krate); - decoder::each_implementation_for_trait(&*cdata, def_id.node, callback) + cstore.iter_crate_data(|_, cdata| { + decoder::each_implementation_for_trait(cdata, def_id, &mut callback) + }) } /// If the given def ID describes an item belonging to a trait (either a diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 00fc42341c389..382dc437bdc48 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -21,7 +21,8 @@ use metadata::common::*; use metadata::csearch::MethodInfo; use metadata::csearch; use metadata::cstore; -use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id, +use metadata::encoder::def_to_u64; +use metadata::tydecode::{parse_ty_data, parse_region_data, parse_type_param_def_data, parse_bare_fn_ty_data, parse_trait_ref_data, parse_predicate_data}; use middle::def; @@ -190,29 +191,32 @@ fn item_symbol(item: rbml::Doc) -> String { reader::get_doc(item, tag_items_data_item_symbol).as_str().to_string() } -fn item_parent_item(d: rbml::Doc) -> Option { +fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> ast::DefId { + let id = reader::doc_as_u64(d); + let def_id = ast::DefId { krate: (id >> 32) as u32, node: id as u32 }; + translate_def_id(cdata, def_id) +} + +fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option { let mut ret = None; reader::tagged_docs(d, tag_items_data_parent_item, |did| { - ret = Some(reader::with_doc_data(did, parse_def_id)); + ret = Some(translated_def_id(cdata, did)); false }); ret } -fn item_reqd_and_translated_parent_item(cnum: ast::CrateNum, - d: rbml::Doc) -> ast::DefId { - let trait_did = item_parent_item(d).expect("item without parent"); - ast::DefId { krate: cnum, node: trait_did.node } +fn item_require_parent_item(cdata: Cmd, d: rbml::Doc) -> ast::DefId { + translated_def_id(cdata, reader::get_doc(d, tag_items_data_parent_item)) } fn item_def_id(d: rbml::Doc, cdata: Cmd) -> ast::DefId { - let tagdoc = reader::get_doc(d, tag_def_id); - return translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); + translated_def_id(cdata, reader::get_doc(d, tag_def_id)) } fn get_provided_source(d: rbml::Doc, cdata: Cmd) -> Option { reader::maybe_get_doc(d, tag_item_method_provided_source).map(|doc| { - translate_def_id(cdata, reader::with_doc_data(doc, parse_def_id)) + translated_def_id(cdata, doc) }) } @@ -261,14 +265,12 @@ fn item_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) } fn enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec { - let mut ids: Vec = Vec::new(); - let v = tag_items_data_item_variant; - reader::tagged_docs(item, v, |p| { - let ext = reader::with_doc_data(p, parse_def_id); - ids.push(ast::DefId { krate: cdata.cnum, node: ext.node }); + let mut ids = vec![]; + reader::tagged_docs(item, tag_items_data_item_variant, |p| { + ids.push(translated_def_id(cdata, p)); true }); - return ids; + ids } fn item_path(item_doc: rbml::Doc) -> Vec { @@ -303,8 +305,7 @@ fn item_name(intr: &IdentInterner, item: rbml::Doc) -> ast::Name { } } -fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum) - -> DefLike { +fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: ast::DefId) -> DefLike { let fam = item_family(item); match fam { Constant => { @@ -314,11 +315,9 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum) // See the comment for methods below. let provenance = if reader::maybe_get_doc( item, tag_item_trait_parent_sort).is_some() { - def::FromTrait(item_reqd_and_translated_parent_item(cnum, - item)) + def::FromTrait(item_require_parent_item(cdata, item)) } else { - def::FromImpl(item_reqd_and_translated_parent_item(cnum, - item)) + def::FromImpl(item_require_parent_item(cdata, item)) }; DlDef(def::DefAssociatedConst(did, provenance)) } else { @@ -339,17 +338,15 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum) // a trait_parent_sort. let provenance = if reader::maybe_get_doc( item, tag_item_trait_parent_sort).is_some() { - def::FromTrait(item_reqd_and_translated_parent_item(cnum, - item)) + def::FromTrait(item_require_parent_item(cdata, item)) } else { - def::FromImpl(item_reqd_and_translated_parent_item(cnum, - item)) + def::FromImpl(item_require_parent_item(cdata, item)) }; DlDef(def::DefMethod(did, provenance)) } Type => { if item_sort(item) == Some('t') { - let trait_did = item_reqd_and_translated_parent_item(cnum, item); + let trait_did = item_require_parent_item(cdata, item); DlDef(def::DefAssociatedTy(trait_did, did)) } else { DlDef(def::DefTy(did, false)) @@ -358,11 +355,11 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum) Mod => DlDef(def::DefMod(did)), ForeignMod => DlDef(def::DefForeignMod(did)), StructVariant => { - let enum_did = item_reqd_and_translated_parent_item(cnum, item); + let enum_did = item_require_parent_item(cdata, item); DlDef(def::DefVariant(enum_did, did, true)) } TupleVariant => { - let enum_did = item_reqd_and_translated_parent_item(cnum, item); + let enum_did = item_require_parent_item(cdata, item); DlDef(def::DefVariant(enum_did, did, false)) } Trait => DlDef(def::DefTrait(did)), @@ -560,9 +557,7 @@ fn each_child_of_item_or_crate(intr: Rc, { // Iterate over all children. let _ = reader::tagged_docs(item_doc, tag_mod_child, |child_info_doc| { - let child_def_id = reader::with_doc_data(child_info_doc, - parse_def_id); - let child_def_id = translate_def_id(cdata, child_def_id); + let child_def_id = translated_def_id(cdata, child_info_doc); // This item may be in yet another crate if it was the child of a // reexport. @@ -584,9 +579,7 @@ fn each_child_of_item_or_crate(intr: Rc, Some(child_item_doc) => { // Hand off the item to the callback. let child_name = item_name(&*intr, child_item_doc); - let def_like = item_to_def_like(child_item_doc, - child_def_id, - cdata.cnum); + let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id); let visibility = item_visibility(child_item_doc); callback(def_like, child_name, visibility); @@ -615,9 +608,8 @@ fn each_child_of_item_or_crate(intr: Rc, if let StaticMethod = item_family(impl_method_doc) { // Hand off the static method to the callback. let static_method_name = item_name(&*intr, impl_method_doc); - let static_method_def_like = item_to_def_like(impl_method_doc, - impl_item_def_id, - cdata.cnum); + let static_method_def_like = item_to_def_like(cdata, impl_method_doc, + impl_item_def_id); callback(static_method_def_like, static_method_name, item_visibility(impl_method_doc)); @@ -633,9 +625,7 @@ fn each_child_of_item_or_crate(intr: Rc, let _ = each_reexport(item_doc, |reexport_doc| { let def_id_doc = reader::get_doc(reexport_doc, tag_items_data_item_reexport_def_id); - let child_def_id = reader::with_doc_data(def_id_doc, - parse_def_id); - let child_def_id = translate_def_id(cdata, child_def_id); + let child_def_id = translated_def_id(cdata, def_id_doc); let name_doc = reader::get_doc(reexport_doc, tag_items_data_item_reexport_name); @@ -657,9 +647,7 @@ fn each_child_of_item_or_crate(intr: Rc, // Get the item. if let Some(child_item_doc) = maybe_find_item(child_def_id.node, other_crates_items) { // Hand off the item to the callback. - let def_like = item_to_def_like(child_item_doc, - child_def_id, - child_def_id.krate); + let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id); // These items have a public visibility because they're part of // a public re-export. callback(def_like, token::intern(name), ast::Public); @@ -733,9 +721,8 @@ pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: ast::NodeI match decode_inlined_item(cdata, tcx, path, item_doc) { Ok(ii) => csearch::FoundAst::Found(ii), Err(path) => { - match item_parent_item(item_doc) { + match item_parent_item(cdata, item_doc) { Some(did) => { - let did = translate_def_id(cdata, did); let parent_item = lookup_item(did.node, cdata.data()); match decode_inlined_item(cdata, tcx, path, parent_item) { Ok(ii) => csearch::FoundAst::FoundParent(did, ii), @@ -759,7 +746,7 @@ pub fn get_enum_variant_defs(intr: &IdentInterner, let item = find_item(did.node, items); let name = item_name(intr, item); let visibility = item_visibility(item); - match item_to_def_like(item, *did, cdata.cnum) { + match item_to_def_like(cdata, item, *did) { DlDef(def @ def::DefVariant(..)) => (def, name, visibility), _ => unreachable!() } @@ -889,8 +876,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, let def_id = item_def_id(method_doc, cdata); - let container_id = item_reqd_and_translated_parent_item(cdata.cnum, - method_doc); + let container_id = item_require_parent_item(cdata, method_doc); let container_doc = lookup_item(container_id.node, cdata.data()); let container = match item_family(container_doc) { Trait => TraitContainer(container_id), @@ -1094,7 +1080,7 @@ pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd, let item = lookup_item(node_id, cdata.data()); let mut ret = None; reader::tagged_docs(item, tag_items_data_item_is_tuple_struct_ctor, |_| { - ret = Some(item_reqd_and_translated_parent_item(cdata.cnum, item)); + ret = Some(item_require_parent_item(cdata, item)); false }); ret @@ -1144,7 +1130,7 @@ pub fn get_struct_fields(intr: Rc, cdata: Cmd, id: ast::NodeId) let name = item_name(&*intr, an_item); let did = item_def_id(an_item, cdata); let tagdoc = reader::get_doc(an_item, tag_item_field_origin); - let origin_id = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); + let origin_id = translated_def_id(cdata, tagdoc); result.push(ty::field_ty { name: name, id: did, @@ -1158,7 +1144,7 @@ pub fn get_struct_fields(intr: Rc, cdata: Cmd, id: ast::NodeId) let did = item_def_id(an_item, cdata); let tagdoc = reader::get_doc(an_item, tag_item_field_origin); let f = item_family(an_item); - let origin_id = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); + let origin_id = translated_def_id(cdata, tagdoc); result.push(ty::field_ty { name: special_idents::unnamed_field.name, id: did, @@ -1342,55 +1328,77 @@ pub fn translate_def_id(cdata: Cmd, did: ast::DefId) -> ast::DefId { } } -pub fn each_impl(cdata: Cmd, mut callback: F) where - F: FnMut(ast::DefId), -{ - let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls); - let _ = reader::tagged_docs(impls_doc, tag_impls_impl, |impl_doc| { - callback(item_def_id(impl_doc, cdata)); - true - }); +// Translate a DefId from the current compilation environment to a DefId +// for an external crate. +fn reverse_translate_def_id(cdata: Cmd, did: ast::DefId) -> Option { + if did.krate == cdata.cnum { + return Some(ast::DefId { krate: ast::LOCAL_CRATE, node: did.node }); + } + + for (&local, &global) in &cdata.cnum_map { + if global == did.krate { + return Some(ast::DefId { krate: local, node: did.node }); + } + } + + None } -pub fn each_implementation_for_type(cdata: Cmd, - id: ast::NodeId, - mut callback: F) +pub fn each_inherent_implementation_for_type(cdata: Cmd, + id: ast::NodeId, + mut callback: F) where F: FnMut(ast::DefId), { let item_doc = lookup_item(id, cdata.data()); reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl, |impl_doc| { - let implementation_def_id = item_def_id(impl_doc, cdata); - callback(implementation_def_id); + if reader::maybe_get_doc(impl_doc, tag_item_trait_ref).is_none() { + callback(item_def_id(impl_doc, cdata)); + } true }); } pub fn each_implementation_for_trait(cdata: Cmd, - id: ast::NodeId, + def_id: ast::DefId, mut callback: F) where F: FnMut(ast::DefId), { - let item_doc = lookup_item(id, cdata.data()); + if cdata.cnum == def_id.krate { + let item_doc = lookup_item(def_id.node, cdata.data()); + let _ = reader::tagged_docs(item_doc, + tag_items_data_item_extension_impl, + |impl_doc| { + callback(item_def_id(impl_doc, cdata)); + true + }); + return; + } - let _ = reader::tagged_docs(item_doc, - tag_items_data_item_extension_impl, - |impl_doc| { - let implementation_def_id = item_def_id(impl_doc, cdata); - callback(implementation_def_id); - true - }); + // Do a reverse lookup beforehand to avoid touching the crate_num + // hash map in the loop below. + if let Some(crate_local_did) = reverse_translate_def_id(cdata, def_id) { + let def_id_u64 = def_to_u64(crate_local_did); + + let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls); + let _ = reader::tagged_docs(impls_doc, tag_impls_impl, |impl_doc| { + let impl_trait = reader::get_doc(impl_doc, tag_impls_impl_trait_def_id); + if reader::doc_as_u64(impl_trait) == def_id_u64 { + callback(item_def_id(impl_doc, cdata)); + } + true + }); + } } pub fn get_trait_of_item(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> Option { let item_doc = lookup_item(id, cdata.data()); - let parent_item_id = match item_parent_item(item_doc) { + let parent_item_id = match item_parent_item(cdata, item_doc) { None => return None, Some(item_id) => item_id, }; - let parent_item_id = translate_def_id(cdata, parent_item_id); let parent_item_doc = lookup_item(parent_item_id.node, cdata.data()); match item_family(parent_item_doc) { Trait => Some(item_def_id(parent_item_doc, cdata)), @@ -1538,8 +1546,7 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc, let name = item_name(&*token::get_ident_interner(), ident_str_doc); let def_id_doc = reader::get_doc(rp_doc, tag_region_param_def_def_id); - let def_id = reader::with_doc_data(def_id_doc, parse_def_id); - let def_id = translate_def_id(cdata, def_id); + let def_id = translated_def_id(cdata, def_id_doc); let doc = reader::get_doc(rp_doc, tag_region_param_def_space); let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as usize); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 90dd452e06b5b..afc71f83975c2 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -91,8 +91,8 @@ fn encode_impl_type_basename(rbml_w: &mut Encoder, name: ast::Name) { rbml_w.wr_tagged_str(tag_item_impl_type_basename, &token::get_name(name)); } -pub fn encode_def_id(rbml_w: &mut Encoder, id: DefId) { - rbml_w.wr_tagged_str(tag_def_id, &def_to_string(id)); +fn encode_def_id(rbml_w: &mut Encoder, id: DefId) { + rbml_w.wr_tagged_u64(tag_def_id, def_to_u64(id)); } #[derive(Clone)] @@ -122,6 +122,10 @@ fn encode_family(rbml_w: &mut Encoder, c: char) { rbml_w.wr_tagged_u8(tag_items_data_item_family, c as u8); } +pub fn def_to_u64(did: DefId) -> u64 { + (did.krate as u64) << 32 | (did.node as u64) +} + pub fn def_to_string(did: DefId) -> String { format!("{}:{}", did.krate, did.node) } @@ -153,9 +157,9 @@ fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder, } fn encode_variant_id(rbml_w: &mut Encoder, vid: DefId) { - let s = def_to_string(vid); - rbml_w.wr_tagged_str(tag_items_data_item_variant, &s[..]); - rbml_w.wr_tagged_str(tag_mod_child, &s[..]); + let id = def_to_u64(vid); + rbml_w.wr_tagged_u64(tag_items_data_item_variant, id); + rbml_w.wr_tagged_u64(tag_mod_child, id); } pub fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, @@ -260,7 +264,7 @@ fn encode_disr_val(_: &EncodeContext, } fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) { - rbml_w.wr_tagged_str(tag_items_data_parent_item, &def_to_string(id)); + rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id)); } fn encode_struct_fields(rbml_w: &mut Encoder, @@ -275,7 +279,7 @@ fn encode_struct_fields(rbml_w: &mut Encoder, } encode_struct_field_family(rbml_w, f.vis); encode_def_id(rbml_w, f.id); - rbml_w.wr_tagged_str(tag_item_field_origin, &def_to_string(origin)); + rbml_w.wr_tagged_u64(tag_item_field_origin, def_to_u64(origin)); rbml_w.end_tag(); } } @@ -358,8 +362,8 @@ fn encode_reexported_static_method(rbml_w: &mut Encoder, debug!("(encode reexported static method) {}::{}", exp.name, token::get_name(method_name)); rbml_w.start_tag(tag_items_data_item_reexport); - rbml_w.wr_tagged_str(tag_items_data_item_reexport_def_id, - &def_to_string(method_def_id)); + rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id, + def_to_u64(method_def_id)); rbml_w.wr_tagged_str(tag_items_data_item_reexport_name, &format!("{}::{}", exp.name, token::get_name(method_name))); @@ -495,8 +499,8 @@ fn encode_reexports(ecx: &EncodeContext, exp.def_id.node, id); rbml_w.start_tag(tag_items_data_item_reexport); - rbml_w.wr_tagged_str(tag_items_data_item_reexport_def_id, - &def_to_string(exp.def_id)); + rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id, + def_to_u64(exp.def_id)); rbml_w.wr_tagged_str(tag_items_data_item_reexport_name, exp.name.as_str()); rbml_w.end_tag(); @@ -526,12 +530,12 @@ fn encode_info_for_mod(ecx: &EncodeContext, // Encode info about all the module children. for item in &md.items { - rbml_w.wr_tagged_str(tag_mod_child, - &def_to_string(local_def(item.id))); + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(local_def(item.id))); each_auxiliary_node_id(&**item, |auxiliary_node_id| { - rbml_w.wr_tagged_str(tag_mod_child, - &def_to_string(local_def(auxiliary_node_id))); + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(local_def(auxiliary_node_id))); true }); @@ -541,8 +545,7 @@ fn encode_info_for_mod(ecx: &EncodeContext, token::get_ident(ident), did, ecx.tcx.map.node_to_string(did)); - rbml_w.wr_tagged_str(tag_mod_impl, - &def_to_string(local_def(did))); + rbml_w.wr_tagged_u64(tag_mod_impl, def_to_u64(local_def(did))); } } @@ -619,8 +622,7 @@ fn encode_parent_sort(rbml_w: &mut Encoder, sort: char) { fn encode_provided_source(rbml_w: &mut Encoder, source_opt: Option) { if let Some(source) = source_opt { - rbml_w.wr_tagged_str(tag_item_method_provided_source, - &def_to_string(source)); + rbml_w.wr_tagged_u64(tag_item_method_provided_source, def_to_u64(source)); } } @@ -725,8 +727,8 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, encode_name(rbml_w, param.name); rbml_w.end_tag(); - rbml_w.wr_tagged_str(tag_region_param_def_def_id, - &def_to_string(param.def_id)); + rbml_w.wr_tagged_u64(tag_region_param_def_def_id, + def_to_u64(param.def_id)); rbml_w.wr_tagged_u64(tag_region_param_def_space, param.space.to_uint() as u64); @@ -1089,8 +1091,8 @@ fn encode_info_for_item(ecx: &EncodeContext, // Encode all the items in this module. for foreign_item in &fm.items { - rbml_w.wr_tagged_str(tag_mod_child, - &def_to_string(local_def(foreign_item.id))); + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(local_def(foreign_item.id))); } encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); @@ -1335,8 +1337,8 @@ fn encode_info_for_item(ecx: &EncodeContext, } rbml_w.end_tag(); - rbml_w.wr_tagged_str(tag_mod_child, - &def_to_string(method_def_id.def_id())); + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(method_def_id.def_id())); } encode_path(rbml_w, path.clone()); @@ -1893,6 +1895,7 @@ impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'b, 'c, 'tcx> { def_id.krate != ast::LOCAL_CRATE { self.rbml_w.start_tag(tag_impls_impl); encode_def_id(self.rbml_w, local_def(item.id)); + self.rbml_w.wr_tagged_u64(tag_impls_impl_trait_def_id, def_to_u64(def_id)); self.rbml_w.end_tag(); } } @@ -1932,12 +1935,12 @@ fn encode_misc_info(ecx: &EncodeContext, rbml_w.start_tag(tag_misc_info); rbml_w.start_tag(tag_misc_info_crate_items); for item in &krate.module.items { - rbml_w.wr_tagged_str(tag_mod_child, - &def_to_string(local_def(item.id))); + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(local_def(item.id))); each_auxiliary_node_id(&**item, |auxiliary_node_id| { - rbml_w.wr_tagged_str(tag_mod_child, - &def_to_string(local_def(auxiliary_node_id))); + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(local_def(auxiliary_node_id))); true }); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index cb069acdfd2f0..e445b6bb300e3 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2564,9 +2564,11 @@ impl<'tcx> TraitDef<'tcx> { tcx: &ctxt<'tcx>, impl_def_id: DefId, impl_trait_ref: TraitRef<'tcx>) { + debug!("TraitDef::record_impl for {}, from {}", + self.repr(tcx), impl_trait_ref.repr(tcx)); + // We don't want to borrow_mut after we already populated all impls, // so check if an impl is present with an immutable borrow first. - if let Some(sty) = fast_reject::simplify_type(tcx, impl_trait_ref.self_ty(), false) { if let Some(is) = self.nonblanket_impls.borrow().get(&sty) { @@ -6336,10 +6338,10 @@ pub fn populate_implementations_for_primitive_if_necessary(tcx: &ctxt, tcx.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id); } -/// Populates the type context with all the implementations for the given type -/// if necessary. -pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, - type_id: ast::DefId) { +/// Populates the type context with all the inherent implementations for +/// the given type if necessary. +pub fn populate_inherent_implementations_for_type_if_necessary(tcx: &ctxt, + type_id: ast::DefId) { if type_id.krate == LOCAL_CRATE { return } @@ -6348,37 +6350,15 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, return } - debug!("populate_implementations_for_type_if_necessary: searching for {:?}", type_id); + debug!("populate_inherent_implementations_for_type_if_necessary: searching for {:?}", type_id); let mut inherent_impls = Vec::new(); - csearch::each_implementation_for_type(&tcx.sess.cstore, type_id, |impl_def_id| { - let impl_items = csearch::get_impl_items(&tcx.sess.cstore, impl_def_id); - - // Record the implementation, if needed - if let Some(trait_ref) = csearch::get_impl_trait(tcx, impl_def_id) { - let trait_def = lookup_trait_def(tcx, trait_ref.def_id); - trait_def.record_impl(tcx, impl_def_id, trait_ref); - } else { - inherent_impls.push(impl_def_id); - } - - // For any methods that use a default implementation, add them to - // the map. This is a bit unfortunate. - for impl_item_def_id in &impl_items { - let method_def_id = impl_item_def_id.def_id(); - match impl_or_trait_item(tcx, method_def_id) { - MethodTraitItem(method) => { - if let Some(source) = method.provided_source { - tcx.provided_method_sources - .borrow_mut() - .insert(method_def_id, source); - } - } - _ => {} - } - } + csearch::each_inherent_implementation_for_type(&tcx.sess.cstore, type_id, |impl_def_id| { + // Record the implementation. + inherent_impls.push(impl_def_id); // Store the implementation info. + let impl_items = csearch::get_impl_items(&tcx.sess.cstore, impl_def_id); tcx.impl_items.borrow_mut().insert(impl_def_id, impl_items); }); @@ -6388,18 +6368,18 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, /// Populates the type context with all the implementations for the given /// trait if necessary. -pub fn populate_implementations_for_trait_if_necessary( - tcx: &ctxt, - trait_id: ast::DefId) { +pub fn populate_implementations_for_trait_if_necessary(tcx: &ctxt, trait_id: ast::DefId) { if trait_id.krate == LOCAL_CRATE { return } let def = lookup_trait_def(tcx, trait_id); if def.flags.get().intersects(TraitFlags::IMPLS_VALID) { - return + return; } + debug!("populate_implementations_for_trait_if_necessary: searching for {}", def.repr(tcx)); + if csearch::is_defaulted_trait(&tcx.sess.cstore, trait_id) { record_trait_has_default_impl(tcx, trait_id); } diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index a896bd311698c..7e7af8006805d 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -10,8 +10,111 @@ #![allow(non_snake_case)] +// Error messages for EXXXX errors. +// Each message should start and end with a new line, and be wrapped to 80 characters. +// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. +register_long_diagnostics! { + +E0154: r##" +Imports (`use` statements) are not allowed after non-item statements, such as +variable declarations and expression statements. + +Here is an example that demonstrates the error: +``` +fn f() { + // Variable declaration before import + let x = 0; + use std::io::Read; + ... +} +``` + +The solution is to declare the imports at the top of the block, function, or +file. + +Here is the previous example again, with the correct order: +``` +fn f() { + use std::io::Read; + let x = 0; + ... +} +``` + +See the Declaration Statements section of the reference for more information +about what constitutes an Item declaration and what does not: + +http://doc.rust-lang.org/reference.html#statements +"##, + +E0259: r##" +The name chosen for an external crate conflicts with another external crate that +has been imported into the current module. + +Wrong example: +``` +extern crate a; +extern crate crate_a as a; +``` + +The solution is to choose a different name that doesn't conflict with any +external crate imported into the current module. + +Correct example: +``` +extern crate a; +extern crate crate_a as other_name; +``` +"##, + +E0260: r##" +The name for an item declaration conflicts with an external crate's name. + +For instance, +``` +extern crate abc; + +struct abc; +``` + +There are two possible solutions: + +Solution #1: Rename the item. + +``` +extern crate abc; + +struct xyz; +``` + +Solution #2: Import the crate with a different name. + +``` +extern crate abc as xyz; + +struct abc; +``` + +See the Declaration Statements section of the reference for more information +about what constitutes an Item declaration and what does not: + +http://doc.rust-lang.org/reference.html#statements +"##, + +E0317: r##" +User-defined types or type parameters cannot shadow the primitive types. +This error indicates you tried to define a type, struct or enum with the same +name as an existing primitive type. + +See the Types section of the reference for more information about the primitive +types: + +http://doc.rust-lang.org/reference.html#types +"## + +} + register_diagnostics! { - E0154, E0157, E0153, E0251, // a named type or value has already been imported in this module @@ -22,9 +125,6 @@ register_diagnostics! { E0256, // import conflicts with type in this module E0257, // inherent implementations are only allowed on types defined in the current module E0258, // import conflicts with existing submodule - E0259, // an extern crate has already been imported into this module - E0260, // name conflicts with an external crate that has been imported into this module - E0317, // user-defined types or type parameters cannot shadow the primitive types E0364, // item is private E0365 // item is private } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 7abe5a84c5fff..447230ada2230 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2688,18 +2688,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { check_ribs: bool) -> AssocItemResolveResult { + let max_assoc_types; + match maybe_qself { - Some(&ast::QSelf { position: 0, .. }) => - return TypecheckRequired, - _ => {} + Some(qself) => { + if qself.position == 0 { + return TypecheckRequired; + } + max_assoc_types = path.segments.len() - qself.position; + // Make sure the trait is valid. + let _ = self.resolve_trait_reference(id, path, max_assoc_types); + } + None => { + max_assoc_types = path.segments.len(); + } } - let max_assoc_types = if let Some(qself) = maybe_qself { - // Make sure the trait is valid. - let _ = self.resolve_trait_reference(id, path, 1); - path.segments.len() - qself.position - } else { - path.segments.len() - }; let mut resolution = self.with_no_errors(|this| { this.resolve_path(id, path, 0, namespace, check_ribs) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 350f69d30c4e4..9870b41e7fa63 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -618,7 +618,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { namespace_name, name_bindings.def_for_namespace(namespace)); self.check_for_conflicting_import( - &import_resolution.target_for_namespace(namespace), + &import_resolution, directive.span, target, namespace); @@ -755,7 +755,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { // Continue. } Some(ref value_target) => { - self.check_for_conflicting_import(&dest_import_resolution.value_target, + self.check_for_conflicting_import(&dest_import_resolution, import_directive.span, *ident, ValueNS); @@ -767,7 +767,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { // Continue. } Some(ref type_target) => { - self.check_for_conflicting_import(&dest_import_resolution.type_target, + self.check_for_conflicting_import(&dest_import_resolution, import_directive.span, *ident, TypeNS); @@ -887,24 +887,31 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { /// Checks that imported names and items don't have the same name. fn check_for_conflicting_import(&mut self, - target: &Option, + import_resolution: &ImportResolution, import_span: Span, name: Name, namespace: Namespace) { + let target = import_resolution.target_for_namespace(namespace); debug!("check_for_conflicting_import: {}; target exists: {}", &token::get_name(name), target.is_some()); - match *target { + match target { Some(ref target) if target.shadowable != Shadowable::Always => { - let msg = format!("a {} named `{}` has already been imported \ - in this module", - match namespace { - TypeNS => "type", - ValueNS => "value", - }, + let ns_word = match namespace { + TypeNS => "type", + ValueNS => "value", + }; + span_err!(self.resolver.session, import_span, E0252, + "a {} named `{}` has already been imported \ + in this module", ns_word, &token::get_name(name)); - span_err!(self.resolver.session, import_span, E0252, "{}", &msg[..]); + let use_id = import_resolution.id(namespace); + let item = self.resolver.ast_map.expect_item(use_id); + // item is syntax::ast::Item; + span_note!(self.resolver.session, item.span, + "previous import of `{}` here", + token::get_name(name)); } Some(_) | None => {} } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c94fa03702681..6171df218bb60 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -371,7 +371,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: ast::DefId) { // Read the inherent implementation candidates for this type from the // metadata if necessary. - ty::populate_implementations_for_type_if_necessary(self.tcx(), def_id); + ty::populate_inherent_implementations_for_type_if_necessary(self.tcx(), def_id); if let Some(impl_infos) = self.tcx().inherent_impls.borrow().get(&def_id) { for &impl_def_id in &***impl_infos { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 05b74a5cc226b..4dc1596b1ff7c 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -16,13 +16,10 @@ // mappings. That mapping code resides here. -use metadata::csearch::{each_impl, get_impl_trait}; -use metadata::csearch; use middle::subst::{self, Subst}; use middle::ty::RegionEscape; use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId}; -use middle::ty::{MethodTraitItemId, TypeTraitItemId}; -use middle::ty::{ParameterEnvironment, lookup_item_type}; +use middle::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment}; use middle::ty::{Ty, ty_bool, ty_char, ty_enum, ty_err}; use middle::ty::{ty_param, TypeScheme, ty_ptr}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; @@ -33,7 +30,6 @@ use middle::ty; use CrateCtxt; use middle::infer::InferCtxt; use middle::infer::new_infer_ctxt; -use std::collections::HashSet; use std::cell::RefCell; use std::rc::Rc; use syntax::ast::{Crate, DefId}; @@ -130,11 +126,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { Rc::new((*v.borrow()).clone())); } - // Bring in external crates. It's fine for this to happen after the - // coherence checks, because we ensure by construction that no errors - // can happen at link time. - self.add_external_crates(); - // Populate the table of destructors. It might seem a bit strange to // do this here, but it's actually the most convenient place, since // the coherence tables contain the trait -> type mappings. @@ -267,11 +258,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { trait_def.record_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref); } - fn get_self_type_for_implementation(&self, impl_did: DefId) - -> TypeScheme<'tcx> { - self.crate_context.tcx.tcache.borrow().get(&impl_did).unwrap().clone() - } - // Converts an implementation in the AST to a vector of items. fn create_impl_from_item(&self, item: &Item) -> Vec { match item.node { @@ -313,66 +299,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } } - // External crate handling - - fn add_external_impl(&self, - impls_seen: &mut HashSet, - impl_def_id: DefId) { - let tcx = self.crate_context.tcx; - let impl_items = csearch::get_impl_items(&tcx.sess.cstore, - impl_def_id); - - // Make sure we don't visit the same implementation multiple times. - if !impls_seen.insert(impl_def_id) { - // Skip this one. - return - } - // Good. Continue. - - let _ = lookup_item_type(tcx, impl_def_id); - let associated_traits = get_impl_trait(tcx, impl_def_id); - - // Do a sanity check. - assert!(associated_traits.is_some()); - - // Record all the trait items. - if let Some(trait_ref) = associated_traits { - self.add_trait_impl(trait_ref, impl_def_id); - } - - // For any methods that use a default implementation, add them to - // the map. This is a bit unfortunate. - for item_def_id in &impl_items { - let impl_item = ty::impl_or_trait_item(tcx, item_def_id.def_id()); - match impl_item { - ty::MethodTraitItem(ref method) => { - if let Some(source) = method.provided_source { - tcx.provided_method_sources - .borrow_mut() - .insert(item_def_id.def_id(), source); - } - } - _ => {} - } - } - - tcx.impl_items.borrow_mut().insert(impl_def_id, impl_items); - } - - // Adds implementations and traits from external crates to the coherence - // info. - fn add_external_crates(&self) { - let mut impls_seen = HashSet::new(); - - let crate_store = &self.crate_context.tcx.sess.cstore; - crate_store.iter_crate_data(|crate_number, _crate_metadata| { - each_impl(crate_store, crate_number, |def_id| { - assert_eq!(crate_number, def_id.krate); - self.add_external_impl(&mut impls_seen, def_id) - }) - }) - } - // // Destructors // @@ -395,7 +321,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } let method_def_id = items[0]; - let self_type = self.get_self_type_for_implementation(impl_did); + let self_type = ty::lookup_item_type(tcx, impl_did); match self_type.ty.sty { ty::ty_enum(type_def_id, _) | ty::ty_struct(type_def_id, _) | @@ -451,7 +377,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { return } - let self_type = self.get_self_type_for_implementation(impl_did); + let self_type = ty::lookup_item_type(tcx, impl_did); debug!("check_implementations_of_copy: self_type={} (bound)", self_type.repr(tcx)); diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 46cce54301168..e9c69c84630ef 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -48,14 +48,9 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { // check_for_overlapping_impls_of_trait() check, since that // check can populate this table further with impls from other // crates. - let trait_defs : Vec<&ty::TraitDef> = { - let d = self.tcx.trait_defs.borrow(); - d.values().map(|&v|v).collect() - }; + let trait_defs: Vec<_> = self.tcx.trait_defs.borrow().values().cloned().collect(); for trait_def in trait_defs { - // FIXME -- it seems like this method actually pushes - // duplicate impls onto the list ty::populate_implementations_for_trait_if_necessary( self.tcx, trait_def.trait_ref.def_id); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index ea872d1014425..f9565d528e89a 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -186,7 +186,7 @@ struct Foo<'a> { ``` This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this -differs from the behavior for `&T`, which is `Copy` when `T` is `Copy`). +differs from the behavior for `&T`, which is always `Copy`). "##, E0205: r##" @@ -216,7 +216,7 @@ enum Foo<'a> { ``` This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this -differs from the behavior for `&T`, which is `Copy` when `T` is `Copy`). +differs from the behavior for `&T`, which is always `Copy`). "##, E0206: r##" diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 0d59577a6d802..3ce8835b1a8de 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -221,7 +221,7 @@ fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEn pub fn build_impls(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> Vec { - ty::populate_implementations_for_type_if_necessary(tcx, did); + ty::populate_inherent_implementations_for_type_if_necessary(tcx, did); let mut impls = Vec::new(); match tcx.inherent_impls.borrow().get(&did) { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index eb1c338ac8591..541ec16b415d4 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -109,15 +109,6 @@ pub enum PathParsingMode { LifetimeAndTypesWithColons, } -/// How to parse a qualified path, whether to allow trailing parameters. -#[derive(Copy, Clone, PartialEq)] -pub enum QPathParsingMode { - /// No trailing parameters, e.g. `::Item` - NoParameters, - /// Optional parameters, e.g. `::item::<'a, U>` - MaybeParameters, -} - /// How to parse a bound, whether to allow bound modifiers such as `?`. #[derive(Copy, Clone, PartialEq)] pub enum BoundParsingMode { @@ -1359,7 +1350,7 @@ impl<'a> Parser<'a> { } else if try!(self.eat_lt()) { let (qself, path) = - try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); + try!(self.parse_qualified_path(NoTypesAllowed)); TyPath(Some(qself), path) } else if self.check(&token::ModSep) || @@ -1578,7 +1569,7 @@ impl<'a> Parser<'a> { // QUALIFIED PATH `::IDENT[::]` // Assumes that the leading `<` has been parsed already. - pub fn parse_qualified_path(&mut self, mode: QPathParsingMode) + pub fn parse_qualified_path(&mut self, mode: PathParsingMode) -> PResult<(QSelf, ast::Path)> { let self_type = try!(self.parse_ty_sum()); let mut path = if try!(self.eat_keyword(keywords::As)) { @@ -1599,29 +1590,18 @@ impl<'a> Parser<'a> { try!(self.expect(&token::Gt)); try!(self.expect(&token::ModSep)); - let item_name = try!(self.parse_ident()); - let parameters = match mode { - QPathParsingMode::NoParameters => ast::PathParameters::none(), - QPathParsingMode::MaybeParameters => { - if try!(self.eat(&token::ModSep)) { - try!(self.expect_lt()); - // Consumed `item::<`, go look for types - let (lifetimes, types, bindings) = - try!(self.parse_generic_values_after_lt()); - ast::AngleBracketedParameters(ast::AngleBracketedParameterData { - lifetimes: lifetimes, - types: OwnedSlice::from_vec(types), - bindings: OwnedSlice::from_vec(bindings), - }) - } else { - ast::PathParameters::none() - } + let segments = match mode { + LifetimeAndTypesWithoutColons => { + try!(self.parse_path_segments_without_colons()) + } + LifetimeAndTypesWithColons => { + try!(self.parse_path_segments_with_colons()) + } + NoTypesAllowed => { + try!(self.parse_path_segments_without_types()) } }; - path.segments.push(ast::PathSegment { - identifier: item_name, - parameters: parameters - }); + path.segments.extend(segments); if path.segments.len() == 1 { path.span.lo = self.last_span.lo; @@ -2096,7 +2076,7 @@ impl<'a> Parser<'a> { if try!(self.eat_lt()){ let (qself, path) = - try!(self.parse_qualified_path(QPathParsingMode::MaybeParameters)); + try!(self.parse_qualified_path(LifetimeAndTypesWithColons)); return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path))); } @@ -3176,7 +3156,7 @@ impl<'a> Parser<'a> { let (qself, path) = if try!(self.eat_lt()) { // Parse a qualified path let (qself, path) = - try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); + try!(self.parse_qualified_path(NoTypesAllowed)); (Some(qself), path) } else { // Parse an unqualified path @@ -3270,7 +3250,7 @@ impl<'a> Parser<'a> { let (qself, path) = if try!(self.eat_lt()) { // Parse a qualified path let (qself, path) = - try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); + try!(self.parse_qualified_path(NoTypesAllowed)); (Some(qself), path) } else { // Parse an unqualified path diff --git a/src/test/compile-fail/double-import.rs b/src/test/compile-fail/double-import.rs new file mode 100644 index 0000000000000..cbf13c0a55909 --- /dev/null +++ b/src/test/compile-fail/double-import.rs @@ -0,0 +1,27 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(no_std)] +#![no_std] + +// This tests that conflicting imports shows both `use` lines +// when reporting the error. + +mod sub1 { + fn foo() {} // implementation 1 +} + +mod sub2 { + fn foo() {} // implementation 2 +} + +use sub1::foo; //~ NOTE previous import of `foo` here +use sub2::foo; //~ ERROR a value named `foo` has already been imported in this module [E0252] + +fn main() {} diff --git a/src/test/compile-fail/issue-20413.rs b/src/test/compile-fail/issue-20413.rs new file mode 100644 index 0000000000000..a48c03aa178c3 --- /dev/null +++ b/src/test/compile-fail/issue-20413.rs @@ -0,0 +1,25 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + fn answer(self); +} + +struct NoData; +//~^ ERROR: parameter `T` is never used + +impl Foo for T where NoData: Foo { +//~^ ERROR: overflow evaluating the requirement + fn answer(self) { + let val: NoData = NoData; + } +} + +fn main() {} diff --git a/src/test/run-pass/associated-item-long-paths.rs b/src/test/run-pass/associated-item-long-paths.rs new file mode 100644 index 0000000000000..4ad0187df7a8f --- /dev/null +++ b/src/test/run-pass/associated-item-long-paths.rs @@ -0,0 +1,55 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem::size_of; + +// The main point of this test is to ensure that we can parse and resolve +// associated items on associated types. + +trait Foo { + type U; +} + +trait Bar { + // Note 1: Chains of associated items in a path won't type-check. + // Note 2: Associated consts can't depend on type parameters or `Self`, + // which are the only types that an associated type can be referenced on for + // now, so we can only test methods. + fn method() -> u32; + fn generic_method() -> usize; +} + +struct MyFoo; +struct MyBar; + +impl Foo for MyFoo { + type U = MyBar; +} + +impl Bar for MyBar { + fn method() -> u32 { + 2u32 + } + fn generic_method() -> usize { + size_of::() + } +} + +fn foo() + where T: Foo, + T::U: Bar, +{ + assert_eq!(2u32, ::U::method()); + assert_eq!(8usize, ::U::generic_method::()); +} + +fn main() { + foo::(); +} diff --git a/src/test/run-pass/issue-18075.rs b/src/test/run-pass/issue-18075.rs new file mode 100644 index 0000000000000..5f07ba2235fd5 --- /dev/null +++ b/src/test/run-pass/issue-18075.rs @@ -0,0 +1,16 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// exec-env:RUST_LOG=rustc::middle=debug + +fn main() { + let b = 1isize; + println!("{}", b); +} diff --git a/src/test/run-pass/slice-of-zero-size-elements.rs b/src/test/run-pass/slice-of-zero-size-elements.rs new file mode 100644 index 0000000000000..6fe510586c748 --- /dev/null +++ b/src/test/run-pass/slice-of-zero-size-elements.rs @@ -0,0 +1,60 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C debug-assertions + +#![feature(core)] + +use std::slice; + +fn foo(v: &[T]) -> Option<&[T]> { + let mut it = v.iter(); + for _ in 0..5 { + let _ = it.next(); + } + Some(it.as_slice()) +} + +fn foo_mut(v: &mut [T]) -> Option<&mut [T]> { + let mut it = v.iter_mut(); + for _ in 0..5 { + let _ = it.next(); + } + Some(it.into_slice()) +} + +pub fn main() { + // In a slice of zero-size elements the pointer is meaningless. + // Ensure iteration still works even if the pointer is at the end of the address space. + let slice: &[()] = unsafe { slice::from_raw_parts(-5isize as *const (), 10) }; + assert_eq!(slice.len(), 10); + assert_eq!(slice.iter().count(), 10); + + // .nth() on the iterator should also behave correctly + let mut it = slice.iter(); + assert!(it.nth(5).is_some()); + assert_eq!(it.count(), 4); + + // Converting Iter to a slice should never have a null pointer + assert!(foo(slice).is_some()); + + // Test mutable iterators as well + let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(-5isize as *mut (), 10) }; + assert_eq!(slice.len(), 10); + assert_eq!(slice.iter_mut().count(), 10); + + { + let mut it = slice.iter_mut(); + assert!(it.nth(5).is_some()); + assert_eq!(it.count(), 4); + } + + assert!(foo_mut(slice).is_some()) +}